Passed
Pull Request — main (#48)
by Thierry
13:20
created

BillService::getSessionBillsQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 3
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Charge;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\DB;
8
use Siak\Tontine\Model\Bill;
9
use Siak\Tontine\Model\Charge;
10
use Siak\Tontine\Model\Session;
11
use Siak\Tontine\Service\TenantService;
12
13
use function strtolower;
14
15
class BillService
16
{
17
    /**
18
     * @var TenantService
19
     */
20
    protected TenantService $tenantService;
21
22
    /**
23
     * @param TenantService $tenantService
24
     */
25
    public function __construct(TenantService $tenantService)
26
    {
27
        $this->tenantService = $tenantService;
28
    }
29
30
    /**
31
     * @param Charge $charge
32
     * @param Session $session
33
     * @param string $relation
34
     * @param string $search
35
     * @param bool $onlyPaid|null
36
     *
37
     * @return Builder
38
     */
39
    private function getBillsQuery(Charge $charge, Session $session,
40
        string $relation, string $search, ?bool $onlyPaid)
41
    {
42
        $relationFilter = function(Builder $query) use($charge, $session, $relation) {
43
            $query->where('charge_id', $charge->id)
44
                ->when($relation === 'session_bill', function($query) use($session) {
45
                    // Filter session bills only on current session
46
                    return $query->where('session_id', $session->id);
47
                })
48
                ->when($relation === 'fine_bill', function($query) use($session) {
49
                    // Filter fine bills on current and previous sessions
50
                    $sessionIds = $this->tenantService->getSessionIds($session);
51
                    return $query->whereIn('session_id', $sessionIds);
52
                });
53
        };
54
        $allBillsFilter = function($query) use($session) {
55
            return $query->where(function(Builder $query) use($session) {
56
                // The bills that are paid in this session, or that are not yet paid.
57
                $query->orWhere(function(Builder $query) {
58
                    $query->whereDoesntHave('settlement');
59
                })->orWhere(function(Builder $query) use($session) {
60
                    $query->whereHas('settlement', function(Builder $query) use($session) {
61
                        $query->where('session_id', $session->id);
62
                    });
63
                });
64
            });
65
        };
66
        $searchFilter = function($query) use($search, $relation) {
67
            $relationTable = $relation . 's';
68
            $search = '%' . strtolower($search) . '%';
69
            return $query->select('bills.*')
70
                ->join($relationTable, "$relationTable.bill_id", '=', 'bills.id')
71
                ->join('members', "$relationTable.member_id", '=', 'members.id')
72
                ->where(DB::raw('lower(members.name)'), 'like', $search);
73
        };
74
75
        return Bill::whereHas($relation, $relationFilter)
76
            ->when($onlyPaid === false, function($query) {
77
                return $query->whereDoesntHave('settlement');
78
            })
79
            ->when($onlyPaid === true, function($query) use($session) {
80
                return $query->whereHas('settlement', function(Builder $query) use($session) {
81
                    $query->where('session_id', $session->id);
82
                });
83
            })
84
            ->when($onlyPaid === null && $relation !== 'session_bill', $allBillsFilter)
85
            ->when($search !== '', $searchFilter);
86
    }
87
88
    /**
89
     * @param Charge $charge
90
     *
91
     * @return string
92
     */
93
    private function getBillRelation(Charge $charge): string
94
    {
95
        // The intermediate relation to reach the member model.
96
        return $charge->is_variable ? 'fine_bill' :
97
            ($charge->period_session ? 'session_bill' :
98
            ($charge->period_round ? 'round_bill' : 'tontine_bill'));
99
    }
100
101
    /**
102
     * @param Charge $charge
103
     * @param Session $session
104
     * @param string $search
105
     * @param bool $onlyPaid|null
106
     * @param int $page
107
     *
108
     * @return Collection
109
     */
110
    public function getBills(Charge $charge, Session $session,
111
        string $search = '', ?bool $onlyPaid = null, int $page = 0): Collection
112
    {
113
        $billRelation = $this->getBillRelation($charge);
114
        $billRelations = !$charge->is_variable ? [$billRelation . '.member', 'settlement'] :
115
            ['fine_bill.session', 'fine_bill.member', 'settlement'];
116
        $query = $this->getBillsQuery($charge, $session, $billRelation, $search, $onlyPaid);
117
118
        return $query->with($billRelations)
119
            ->page($page, $this->tenantService->getLimit())
120
            ->orderBy('id', 'asc')
121
            ->get()
122
            ->each(function($bill) use($billRelation, $charge) {
123
                $bill->member = $bill->$billRelation->member;
124
                $bill->session = $charge->is_variable ? $bill->fine_bill->session : null;
125
            });
126
    }
127
128
    /**
129
     * @param Charge $charge
130
     * @param Session $session
131
     * @param string $search
132
     * @param bool $onlyPaid|null
133
     *
134
     * @return int
135
     */
136
    public function getBillCount(Charge $charge, Session $session,
137
        string $search = '', ?bool $onlyPaid = null): int
138
    {
139
        $billRelation = $this->getBillRelation($charge);
140
141
        return $this->getBillsQuery($charge, $session, $billRelation, $search, $onlyPaid)
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getBillsQu...ch, $onlyPaid)->count() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
142
            ->count();
143
    }
144
}
145