Passed
Push — main ( ecd12d...3c3a9e )
by Thierry
05:54
created

SettlementService::getFund()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Charge;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Siak\Tontine\Exception\MessageException;
8
use Siak\Tontine\Model\Charge;
9
use Siak\Tontine\Model\Fund;
10
use Siak\Tontine\Model\Round;
11
use Siak\Tontine\Model\Session;
12
use Siak\Tontine\Model\Settlement;
13
use Siak\Tontine\Service\Payment\PaymentServiceInterface;
14
use Siak\Tontine\Service\TenantService;
15
use Siak\Tontine\Validation\SearchSanitizer;
16
17
use function trans;
18
19
class SettlementService
20
{
21
    /**
22
     * @param TenantService $tenantService
23
     * @param SearchSanitizer $searchSanitizer
24
     * @param BillService $billService
25
     * @param PaymentServiceInterface $paymentService;
26
     */
27
    public function __construct(private TenantService $tenantService,
28
        private SearchSanitizer $searchSanitizer, private BillService $billService,
29
        private PaymentServiceInterface $paymentService)
30
    {}
31
32
    /**
33
     * @param Round $round
34
     *
35
     * @return Collection
36
     */
37
    public function getFunds(Round $round): Collection
38
    {
39
        return $round->funds()->real()
40
            ->join('fund_defs', 'fund_defs.id', '=', 'funds.def_id')
41
            ->orderBy('fund_defs.type') // The default fund is first in the list.
42
            ->orderBy('funds.id')
43
            ->get()
44
            ->pluck('title', 'id');
45
    }
46
47
    /**
48
     * @param Round $round
49
     * @param int $fundId
50
     *
51
     * @return Fund|null
52
     */
53
    public function getFund(Round $round, int $fundId): Fund|null
54
    {
55
        return $round->funds()->real()->find($fundId);
56
    }
57
58
    /**
59
     * Create a settlement
60
     *
61
     * @param Charge $charge
62
     * @param Session $session
63
     * @param int $billId
64
     * @param Fund|null $fund
65
     *
66
     * @return void
67
     */
68
    public function createSettlement(Charge $charge, Session $session,
69
        int $billId, Fund|null $fund = null): void
70
    {
71
        $bill = $this->billService->getBill($charge, $session, $billId);
72
        // Return if the bill is not found or the bill is already settled.
73
        if(!$bill || ($bill->settlement))
74
        {
75
            throw new MessageException(trans('tontine.bill.errors.not_found'));
76
        }
77
        $settlement = new Settlement();
78
        $settlement->bill()->associate($bill);
79
        $settlement->session()->associate($session);
80
        if($fund !== null)
81
        {
82
            $settlement->fund()->associate($fund);
83
        }
84
        $settlement->save();
85
    }
86
87
    /**
88
     * Delete a settlement
89
     *
90
     * @param Charge $charge
91
     * @param Session $session
92
     * @param int $Id
93
     *
94
     * @return void
95
     */
96
    public function deleteSettlement(Charge $charge, Session $session, int $billId): void
97
    {
98
        $bill = $this->billService->getBill($charge, $session, $billId);
99
        // Return if the bill is not found or the bill is not settled.
100
        if(!$bill || !($bill->settlement))
101
        {
102
            throw new MessageException(trans('tontine.bill.errors.not_found'));
103
        }
104
        if((!$this->paymentService->isEditable($bill->settlement)))
105
        {
106
            throw new MessageException(trans('tontine.errors.editable'));
107
        }
108
        $bill->settlement()->where('session_id', $session->id)->delete();
109
    }
110
111
    /**
112
     * Create a settlement for all unpaid bills
113
     *
114
     * @param Charge $charge
115
     * @param Session $session
116
     * @param string $search
117
     * @param Fund|null $fund
118
     *
119
     * @return void
120
     */
121
    public function createAllSettlements(Charge $charge, Session $session,
122
        string $search, Fund|null $fund = null): void
123
    {
124
        $bills = $this->billService->getBills($charge, $session, $search, false);
125
        if($bills->count() === 0)
126
        {
127
            // Reset the fund
128
            $this->fund = null;
0 ignored issues
show
Bug Best Practice introduced by
The property fund does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
129
130
            return;
131
        }
132
133
        // Todo: use one insert query
134
        DB::transaction(function() use($bills, $session, $fund) {
135
            foreach($bills as $bill)
136
            {
137
                $settlement = new Settlement();
138
                $settlement->bill()->associate($bill);
139
                $settlement->session()->associate($session);
140
                if($fund !== null)
141
                {
142
                    $settlement->fund()->associate($fund);
143
                }
144
                $settlement->save();
145
            }
146
        });
147
148
        // Reset the fund
149
        $this->fund = null;
150
    }
151
152
    /**
153
     * Delete all settlements
154
     *
155
     * @param Charge $charge
156
     * @param Session $session
157
     * @param string $search
158
     *
159
     * @return void
160
     */
161
    public function deleteAllSettlements(Charge $charge, Session $session, string $search): void
162
    {
163
        $bills = $this->billService->getBills($charge, $session, $search, true)
164
            ->filter(fn($bill) => $this->paymentService->isEditable($bill->settlement));
165
        if($bills->count() === 0)
166
        {
167
            return;
168
        }
169
170
        Settlement::whereIn('bill_id', $bills->pluck('id'))
171
            ->where('session_id', $session->id)
172
            ->delete();
173
    }
174
175
    /**
176
     * @param Charge $charge
177
     * @param Session $session
178
     *
179
     * @return array<int>
180
     */
181
    public function getSettlementTotal(Charge $charge, Session $session): array
182
    {
183
        $total = DB::table('v_settlements')
184
            ->where('session_id', $session->id)
185
            ->where('charge_id', $charge->id)
186
            ->select(DB::raw('count(*) as count'), DB::raw('sum(amount) as amount'))
187
            ->first();
188
        return [$total->count ?? 0, $total->amount ?? 0];
189
    }
190
}
191