Passed
Push — main ( 936852...10149e )
by Thierry
15:09
created

LoanService::createLoan()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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