Bill   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 79
dl 0
loc 259
rs 10
c 0
b 0
f 0
wmc 18

18 Methods

Rating   Name   Duplication   Size   Complexity  
A session() 0 3 1
A scopeLibre() 0 3 1
A scopePaid() 0 3 1
A settlement() 0 3 1
A scopeUnpaid() 0 3 1
A session_bill() 0 3 1
A libre() 0 4 1
A round_bill() 0 3 1
A casts() 0 5 1
A libre_bill() 0 3 1
A scopeFixed() 0 3 1
A onetime_bill() 0 3 1
A scopeOfSession() 0 28 1
A scopeForSession() 0 7 1
A scopeOfRound() 0 14 1
A scopeLendable() 0 3 1
A scopeSearch() 0 4 1
A scopeOfCharge() 0 14 1
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
     * @param Session $session
187
     *
188
     * @return Builder
189
     */
190
    public function scopeForSession(Builder $query, Session $session): Builder
191
    {
192
        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...
193
            ->join(DB::raw('members as m'), 'v.member_id', '=', 'm.id')
194
            ->join(DB::raw('member_defs as md'), 'm.def_id', '=', 'md.id')
195
            ->select(['bills.*', 'v.*',
196
                DB::raw('md.name as member'), DB::raw('s.day_date as bill_date')]);
197
    }
198
199
    /**
200
     * @param Builder $query
201
     * @param Session $session
202
     *
203
     * @return Builder
204
     */
205
    public function scopeOfRound(Builder $query, Session $session): Builder
206
    {
207
        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...
208
            ->join(DB::raw('v_bills as v'), 'v.bill_id', '=', 'bills.id')
209
            ->join(DB::raw('sessions as s'), 'v.session_id', '=', 's.id')
210
            ->where(function($query) use($session) {
211
                $query->orWhere(function($query) use($session) {
212
                    $query->whereIn('v.bill_type', [self::TYPE_LIBRE, self::TYPE_SESSION])
213
                        ->where('v.round_id', $session->round_id)
214
                        ->where('s.day_date', '<', $session->day_date);
215
                })
216
                ->orWhere(function($query) use($session) {
217
                    $query->whereIn('v.bill_type', [self::TYPE_ROUND, self::TYPE_ONETIME])
218
                        ->where('v.round_id', $session->round_id);
219
                });
220
            });
221
    }
222
223
    /**
224
     * @param Builder $query
225
     * @param Charge $charge
226
     * @param bool $withLibre
227
     *
228
     * @return Builder
229
     */
230
    public function scopeOfCharge(Builder $query, Charge $charge, bool $withLibre): Builder
231
    {
232
        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...
233
            ->where(function($query) use($charge, $withLibre) {
234
                $query
235
                    ->orWhereHas('onetime_bill', fn(Builder $qb) =>
236
                        $qb->where('charge_id', $charge->id))
237
                    ->orWhereHas('round_bill', fn(Builder $qb) =>
238
                        $qb->where('charge_id', $charge->id))
239
                    ->orWhereHas('session_bill', fn(Builder $qb) =>
240
                        $qb->where('charge_id', $charge->id))
241
                    ->when($withLibre, fn($qw) =>
242
                        $qw->orWhereHas('libre_bill', fn(Builder $qb) =>
243
                            $qb->where('charge_id', $charge->id)));
244
            });
245
    }
246
247
    /**
248
     * @param  Builder  $query
249
     * @param  string $search
250
     *
251
     * @return Builder
252
     */
253
    public function scopeSearch(Builder $query, string $search): Builder
254
    {
255
        return $query->when($search !== '', fn($qs) => $qs
256
            ->where(DB::raw('lower(member)'), 'like', "%{$search}%"));
257
    }
258
259
    /**
260
     * @param  Builder  $query
261
     * @param  bool  $lendable
262
     *
263
     * @return Builder
264
     */
265
    public function scopeLendable(Builder $query, bool $lendable): Builder
266
    {
267
        return $query->where('lendable', $lendable);
268
    }
269
}
270