Passed
Push — main ( ef0742...4e298b )
by Thierry
11:40
created

LoanService::updateDeadline()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 3
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Credit;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Siak\Tontine\Model\Debt;
8
use Siak\Tontine\Model\Fund;
9
use Siak\Tontine\Model\Guild;
10
use Siak\Tontine\Model\Loan;
11
use Siak\Tontine\Model\Member;
12
use Siak\Tontine\Model\Session;
13
use Siak\Tontine\Service\Payment\BalanceCalculator;
14
use Siak\Tontine\Service\Guild\FundService;
15
use Siak\Tontine\Service\Guild\MemberService;
16
use Siak\Tontine\Service\LocaleService;
17
use Siak\Tontine\Service\TenantService;
18
19
use function trans;
20
21
class LoanService
22
{
23
    /**
24
     * @param BalanceCalculator $balanceCalculator
25
     * @param LocaleService $localeService
26
     * @param TenantService $tenantService
27
     * @param FundService $fundService
28
     * @param MemberService $memberService
29
     */
30
    public function __construct(private BalanceCalculator $balanceCalculator,
31
        private LocaleService $localeService, private TenantService $tenantService,
32
        private FundService $fundService, private  MemberService $memberService)
33
    {}
34
35
    /**
36
     * @return array
37
     */
38
    public function getInterestTypes(): array
39
    {
40
        return [
41
            Loan::INTEREST_FIXED => trans('meeting.loan.interest.if'),
42
            Loan::INTEREST_UNIQUE => trans('meeting.loan.interest.iu'),
43
            Loan::INTEREST_SIMPLE => trans('meeting.loan.interest.is'),
44
            Loan::INTEREST_COMPOUND => trans('meeting.loan.interest.ic'),
45
        ];
46
    }
47
48
    /**
49
     * Get the amount available for loan.
50
     *
51
     * @param Session $session    The session
52
     *
53
     * @return int
54
     */
55
    public function getAmountAvailable(Session $session): int
56
    {
57
        return $this->balanceCalculator->getBalanceForLoan($session);
58
    }
59
60
    /**
61
     * Gett the number of loans for a given session.
62
     *
63
     * @param Session $session
64
     *
65
     * @return int
66
     */
67
    public function getSessionLoanCount(Session $session): int
68
    {
69
        return $session->loans()->count();
70
    }
71
72
    /**
73
     * Get the loans for a given session.
74
     *
75
     * @param Session $session
76
     * @param int $page
77
     *
78
     * @return Collection
79
     */
80
    public function getSessionLoans(Session $session, int $page = 0): Collection
81
    {
82
        return $session->loans()
83
            ->with(['member', 'fund'])
84
            ->page($page, $this->tenantService->getLimit())
85
            ->orderBy('id')
86
            ->get();
87
    }
88
89
    /**
90
     * Get a loan for a given session.
91
     *
92
     * @param Session $session
93
     * @param int $loanId
94
     *
95
     * @return Loan|null
96
     */
97
    public function getSessionLoan(Session $session, int $loanId): ?Loan
98
    {
99
        return $session->loans()->with(['member', 'fund'])->withCount('refunds')->find($loanId);
100
    }
101
102
    /**
103
     * Create a loan.
104
     *
105
     * @param Session $session The session
106
     * @param Member $member
107
     * @param Fund $fund
108
     * @param array $values
109
     *
110
     * @return void
111
     */
112
    public function createLoan(Session $session, Member $member, Fund $fund, array $values): void
113
    {
114
        $loan = new Loan();
115
        $loan->interest_type = $values['interest_type'];
116
        $loan->interest_rate = $values['interest_rate'];
117
        $loan->session()->associate($session);
118
        $loan->member()->associate($member);
119
        $loan->fund()->associate($fund);
120
        DB::transaction(function() use($loan, $values) {
121
            $loan->save();
122
123
            $principal = $values['principal'];
124
            $interest = $values['interest'];
125
            // Create an entry for each type of debt
126
            if($principal > 0)
127
            {
128
                $loan->debts()->create(['type' => Debt::TYPE_PRINCIPAL, 'amount' => $principal]);
129
            }
130
            if($interest > 0)
131
            {
132
                $loan->debts()->create(['type' => Debt::TYPE_INTEREST, 'amount' => $interest]);
133
            }
134
        });
135
    }
136
137
    /**
138
     * Update a loan.
139
     *
140
     * @param Member $member
141
     * @param Fund $fund
142
     * @param Loan $loan
143
     * @param array $values
144
     *
145
     * @return void
146
     */
147
    public function updateLoan(Member $member, Fund $fund, Loan $loan, array $values): void
148
    {
149
        $loan->interest_type = $values['interest_type'];
150
        $loan->interest_rate = $values['interest_rate'];
151
        $loan->member()->associate($member);
152
        $loan->fund()->associate($fund);
153
        DB::transaction(function() use($loan, $values) {
154
            $loan->save();
155
156
            $principal = $values['principal'];
157
            $interest = $values['interest'];
158
            $loan->debts()->principal()->update(['amount' => $principal]);
159
            // The interest debt may need to be created or deleted.
160
            if($interest <= 0)
161
            {
162
                $loan->debts()->where('type', Debt::TYPE_INTEREST)->delete();
163
                return;
164
            }
165
            $loan->debts()->updateOrCreate(['type' => Debt::TYPE_INTEREST], ['amount' => $interest]);
166
        });
167
    }
168
169
    /**
170
     * Delete a loan.
171
     *
172
     * @param Session $session The session
173
     * @param int $loanId
174
     *
175
     * @return void
176
     */
177
    public function deleteLoan(Session $session, int $loanId): void
178
    {
179
        /** @var Loan|null */
180
        $loan = $session->loans()->find($loanId);
181
        if($loan !== null)
182
        {
183
            DB::transaction(function() use($loan) {
184
                $loan->refunds()->delete();
185
                $loan->debts()->delete();
186
                $loan->delete();
187
            });
188
        }
189
    }
190
191
    /**
192
     * @param Guild $guild
193
     * @param Loan $loan
194
     * @param string $deadline
195
     *
196
     * @return void
197
     */
198
    public function updateDeadline(Guild $guild, Loan $loan, string $deadline): void
199
    {
200
        $loan->deadline_date = null;
201
        $loan->deadline_session_id = null;
202
        $session = $guild->sessions()->where('day_date', $deadline)->first();
203
        if($session !== null)
204
        {
205
            $loan->deadline_session()->associate($session);
206
        }
207
        else
208
        {
209
            $loan->deadline_date = $deadline;
210
        }
211
        $loan->save();
212
    }
213
214
    /**
215
     * @param Loan $loan
216
     *
217
     * @return void
218
     */
219
    public function deleteDeadline(Loan $loan): void
220
    {
221
        $loan->deadline_date = null;
222
        $loan->deadline_session_id = null;
223
        $loan->save();
224
    }
225
}
226