Bill::scopeSearch()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Siak\Tontine\Model;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Casts\Attribute;
7
use Illuminate\Support\Facades\DB;
8
9
class Bill extends Base
10
{
11
    /**
12
     * @const
13
     */
14
    public const TYPE_LIBRE = 0;
15
16
    /**
17
     * @const
18
     */
19
    public const TYPE_SESSION = 1;
20
21
    /**
22
     * @const
23
     */
24
    public const TYPE_ROUND = 2;
25
26
    /**
27
     * @const
28
     */
29
    public const TYPE_ONETIME = 3;
30
31
    /**
32
     * Indicates if the model should be timestamped.
33
     *
34
     * @var bool
35
     */
36
    public $timestamps = false;
37
38
    /**
39
     * The attributes that are mass assignable.
40
     *
41
     * @var array
42
     */
43
    protected $fillable = [
44
        'charge',
45
        'amount',
46
        'lendable',
47
        'issued_at',
48
        'deadline',
49
        'notes',
50
    ];
51
52
    /**
53
     * Get the attributes that should be cast.
54
     *
55
     * @return array<string, string>
56
     */
57
    protected function casts(): array
58
    {
59
        return [
60
            'issued_at' => 'datetime',
61
            'deadline' => 'datetime',
62
        ];
63
    }
64
65
    /**
66
     * @return Attribute
67
     */
68
    protected function libre(): Attribute
69
    {
70
        return Attribute::make(
71
            get: fn() => $this->bill_type === self::TYPE_LIBRE,
0 ignored issues
show
Bug introduced by
The property bill_type does not seem to exist on Siak\Tontine\Model\Bill. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
72
        );
73
    }
74
75
    public function session()
76
    {
77
        return $this->belongsTo(Session::class);
78
    }
79
80
    public function settlement()
81
    {
82
        return $this->hasOne(Settlement::class);
83
    }
84
85
    public function onetime_bill()
86
    {
87
        return $this->hasOne(OnetimeBill::class);
88
    }
89
90
    public function round_bill()
91
    {
92
        return $this->hasOne(RoundBill::class);
93
    }
94
95
    public function session_bill()
96
    {
97
        return $this->hasOne(SessionBill::class);
98
    }
99
100
    public function libre_bill()
101
    {
102
        return $this->hasOne(LibreBill::class);
103
    }
104
105
    /**
106
     * @param  Builder  $query
107
     *
108
     * @return Builder
109
     */
110
    public function scopePaid(Builder $query): Builder
111
    {
112
        return $query->whereHas('settlement');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereHas('settlement') could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
113
    }
114
115
    /**
116
     * @param  Builder  $query
117
     *
118
     * @return Builder
119
     */
120
    public function scopeUnpaid(Builder $query): Builder
121
    {
122
        return $query->whereDoesntHave('settlement');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereDoesntHave('settlement') could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
123
    }
124
125
    /**
126
     * @param  Builder  $query
127
     *
128
     * @return Builder
129
     */
130
    public function scopeLibre(Builder $query): Builder
131
    {
132
        return $query->where('v.bill_type', self::TYPE_LIBRE);
133
    }
134
135
    /**
136
     * @param  Builder  $query
137
     *
138
     * @return Builder
139
     */
140
    public function scopeFixed(Builder $query): Builder
141
    {
142
        return $query->where('v.bill_type', '!=', self::TYPE_LIBRE);
143
    }
144
145
    /**
146
     * @param  Builder  $query
147
     * @param Session $session
148
     *
149
     * @return Builder
150
     */
151
    public function scopeOfSession(Builder $query, Session $session): Builder
152
    {
153
        return $query->select(['bills.*', 'v.*', DB::raw('s.day_date as bill_date')])
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select(ar...ion(...) { /* ... */ }) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
154
            ->join(DB::raw('v_bills as v'), 'v.bill_id', '=', 'bills.id')
155
            ->join(DB::raw('sessions as s'), 'v.session_id', '=', 's.id')
156
            ->where(function($query) use($session) {
157
                $query->orWhere(function($query) use($session) {
158
                    $query->where('v.bill_type', self::TYPE_LIBRE)
159
                        ->where('v.round_id', $session->round_id)
160
                        ->where('s.day_date', '<=', $session->day_date);
161
                })
162
                ->orWhere(function($query) use($session) {
163
                    $query->where('v.bill_type', self::TYPE_SESSION)
164
                        ->where('v.session_id', $session->id);
165
                })
166
                ->orWhere(function($query) use($session) {
167
                    $query->whereIn('v.bill_type', [self::TYPE_ROUND, self::TYPE_ONETIME])
168
                        ->where('v.round_id', $session->round_id);
169
                });
170
            })
171
            ->where(function(Builder $query) use($session) {
172
                // The bills that are not yet paid, or that are paid in this round.
173
                $query->orWhere(function(Builder $query) {
174
                    $query->whereDoesntHave('settlement');
175
                })
176
                ->orWhere(function(Builder $query) use($session) {
177
                    $query->whereHas('settlement', function(Builder $query) use($session) {
178
                        $query->where('session_id', $session->id);
179
                    });
180
                });
181
            });
182
    }
183
184
    /**
185
     * @param  Builder  $query
186
     *
187
     * @return Builder
188
     */
189
    public function scopeJoinMembers(Builder $query): Builder
190
    {
191
        return $query->join(DB::raw('v_bills as v'), 'v.bill_id', '=', 'bills.id')
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->join(Illu....def_id', '=', 'md.id') could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
192
            ->join(DB::raw('members as m'), 'v.member_id', '=', 'm.id')
193
            ->join(DB::raw('member_defs as md'), 'm.def_id', '=', 'md.id');
194
    }
195
196
    /**
197
     * @param  Builder  $query
198
     * @param Session $session
199
     *
200
     * @return Builder
201
     */
202
    public function scopeForSession(Builder $query, Session $session): Builder
203
    {
204
        return $this->scopeOfSession($query, $session)
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->scopeOfSes...y_date as bill_date'))) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
205
            ->join(DB::raw('members as m'), 'v.member_id', '=', 'm.id')
206
            ->join(DB::raw('member_defs as md'), 'm.def_id', '=', 'md.id')
207
            ->select(['bills.*', 'v.*', DB::raw('md.name as member'),
208
                DB::raw('s.day_date as bill_date')]);
209
    }
210
211
    /**
212
     * @param Builder $query
213
     * @param Session $session
214
     *
215
     * @return Builder
216
     */
217
    public function scopeOfRound(Builder $query, Session $session): Builder
218
    {
219
        return $query->select(['bills.*', 'v.*', DB::raw('s.day_date as bill_date')])
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select(ar...ion(...) { /* ... */ }) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
220
            ->join(DB::raw('v_bills as v'), 'v.bill_id', '=', 'bills.id')
221
            ->join(DB::raw('sessions as s'), 'v.session_id', '=', 's.id')
222
            ->where(function($query) use($session) {
223
                $query->orWhere(function($query) use($session) {
224
                    $query->whereIn('v.bill_type', [self::TYPE_LIBRE, self::TYPE_SESSION])
225
                        ->where('v.round_id', $session->round_id)
226
                        ->where('s.day_date', '<', $session->day_date);
227
                })
228
                ->orWhere(function($query) use($session) {
229
                    $query->whereIn('v.bill_type', [self::TYPE_ROUND, self::TYPE_ONETIME])
230
                        ->where('v.round_id', $session->round_id);
231
                });
232
            });
233
    }
234
235
    /**
236
     * @param Builder $query
237
     * @param Charge $charge
238
     * @param bool $withLibre
239
     *
240
     * @return Builder
241
     */
242
    public function scopeOfCharge(Builder $query, Charge $charge, bool $withLibre): Builder
243
    {
244
        return $query->addSelect(['bills.*'])
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->addSelect...ion(...) { /* ... */ }) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
245
            ->where(function($query) use($charge, $withLibre) {
246
                $query
247
                    ->orWhereHas('onetime_bill', fn(Builder $qb) =>
248
                        $qb->where('charge_id', $charge->id))
249
                    ->orWhereHas('round_bill', fn(Builder $qb) =>
250
                        $qb->where('charge_id', $charge->id))
251
                    ->orWhereHas('session_bill', fn(Builder $qb) =>
252
                        $qb->where('charge_id', $charge->id))
253
                    ->when($withLibre, fn($qw) =>
254
                        $qw->orWhereHas('libre_bill', fn(Builder $qb) =>
255
                            $qb->where('charge_id', $charge->id)));
256
            });
257
    }
258
259
    /**
260
     * @param  Builder  $query
261
     * @param  Session  $session
262
     *
263
     * @return Builder
264
     */
265
    public function scopeWhereSession(Builder $query, Session $session): Builder
266
    {
267
        return $query->where('session_id', $session->id);
268
    }
269
270
    /**
271
     * @param  Builder  $query
272
     * @param  Charge  $charge
273
     *
274
     * @return Builder
275
     */
276
    public function scopeWhereCharge(Builder $query, Charge $charge): Builder
277
    {
278
        return $query->where('v.charge_id', $charge->id);
279
    }
280
281
    /**
282
     * @param  Builder  $query
283
     * @param  string $search
284
     *
285
     * @return Builder
286
     */
287
    public function scopeSearch(Builder $query, string $search): Builder
288
    {
289
        return $query->when($search !== '', fn($qs) => $qs
290
            ->where(DB::raw('lower(md.name)'), 'like', "%{$search}%"));
291
    }
292
293
    /**
294
     * @param  Builder  $query
295
     * @param  bool  $lendable
296
     *
297
     * @return Builder
298
     */
299
    public function scopeLendable(Builder $query, bool $lendable): Builder
300
    {
301
        return $query->where('lendable', $lendable);
302
    }
303
}
304