PartialRefundService::deletePartialRefund()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 8
rs 10
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Credit;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Siak\Tontine\Exception\MessageException;
7
use Siak\Tontine\Model\Debt;
8
use Siak\Tontine\Model\PartialRefund;
9
use Siak\Tontine\Model\Session;
10
use Siak\Tontine\Service\LocaleService;
11
use Siak\Tontine\Service\Meeting\Saving\FundService;
12
use Siak\Tontine\Service\Payment\PaymentServiceInterface;
13
use Siak\Tontine\Service\TenantService;
14
15
use function trans;
16
17
class PartialRefundService
18
{
19
    use RefundTrait;
0 ignored issues
show
introduced by
The trait Siak\Tontine\Service\Meeting\Credit\RefundTrait requires some properties which are not provided by Siak\Tontine\Service\Mee...it\PartialRefundService: $principal_debt, $is_principal, $session_id, $refund, $opened, $loan, $interest_debt, $id, $partial_refunds, $recurrent_interest, $session, $day_date, $is_interest
Loading history...
20
21
    /**
22
     * @param DebtCalculator $debtCalculator
23
     * @param TenantService $tenantService
24
     * @param LocaleService $localeService
25
     * @param FundService $fundService
26
     * @param PaymentServiceInterface $paymentService;
27
     */
28
    public function __construct(private DebtCalculator $debtCalculator,
29
        TenantService $tenantService, private LocaleService $localeService,
30
        FundService $fundService, private PaymentServiceInterface $paymentService)
31
    {
32
        $this->tenantService = $tenantService;
33
        $this->fundService = $fundService;
34
    }
35
36
    /**
37
     * Get an unpaid debt.
38
     *
39
     * @param Session $session The session
40
     * @param int $debtId
41
     *
42
     * @return Debt|null
43
     */
44
    public function getUnpaidDebt(Session $session, int $debtId): ?Debt
45
    {
46
        return $this->getDebtsQuery($session, null, false, false)
47
            // A debt from a loan created in the current session can be refunded only
48
            // if it is an interest debt with fixed or unique interest.
49
            ->where(function(Builder $query) use($session) {
50
                $query
51
                    ->whereHas('loan', fn(Builder $q) =>
52
                        $q->where('session_id', '!=', $session->id))
53
                    ->orWhere(fn(Builder $q) => $q
54
                        ->interest()
55
                        ->whereHas('loan', fn(Builder $ql) => $ql->fixedInterest()));
56
            })
57
            ->with([
58
                'partial_refund' => fn($q) => $q->where('session_id', $session->id),
59
            ])
60
            ->find($debtId);
61
    }
62
63
    /**
64
     * @param Session $session
65
     * @param Debt $debt
66
     *
67
     * @return bool
68
     */
69
    private function canPartiallyRefund(Session $session, Debt $debt): bool
70
    {
71
        return $session->opened && !$debt->refund;
0 ignored issues
show
Bug introduced by
The property opened does not seem to exist on Siak\Tontine\Model\Session. 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
     * Create a refund.
76
     *
77
     * @param Session $session
78
     * @param Debt $debt
79
     * @param int $amount
80
     *
81
     * @return void
82
     */
83
    public function createPartialRefund(Session $session, Debt $debt, int $amount): void
84
    {
85
        if(!$this->canPartiallyRefund($session, $debt))
86
        {
87
            throw new MessageException(trans('meeting.refund.errors.cannot_create'));
88
        }
89
        // A partial refund must not totally refund a debt
90
        if($amount >= $this->debtCalculator->getDebtPayableAmount($debt, $session))
91
        {
92
            throw new MessageException(trans('meeting.refund.errors.pr_amount'));
93
        }
94
95
        $refund = new PartialRefund();
96
        $refund->amount = $amount;
97
        $refund->debt()->associate($debt);
98
        $refund->session()->associate($session);
99
        $refund->save();
100
    }
101
102
    /**
103
     * @param Session $session
104
     * @param PartialRefund $refund
105
     *
106
     * @return bool
107
     */
108
    private function canModifyPartialRefund(Session $session, PartialRefund $refund): bool
109
    {
110
        // A partial refund cannot be updated or deleted if the debt is already refunded.
111
        return $session->opened && $refund->debt->refund === null &&
0 ignored issues
show
Bug introduced by
The property opened does not seem to exist on Siak\Tontine\Model\Session. 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...
112
            $this->paymentService->isEditable($refund);
113
    }
114
115
    /**
116
     * Update a refund.
117
     *
118
     * @param Session $session The session
119
     * @param PartialRefund $refund
120
     * @param int $amount
121
     *
122
     * @return void
123
     */
124
    public function updatePartialRefund(Session $session, PartialRefund $refund, int $amount): void
125
    {
126
        if(!$this->canModifyPartialRefund($session, $refund))
127
        {
128
            throw new MessageException(trans('meeting.refund.errors.cannot_update'));
129
        }
130
131
        // A partial refund must not totally refund a debt
132
        $maxAmount = $refund->amount +
133
            $this->debtCalculator->getDebtPayableAmount($refund->debt, $session);
134
        if($amount >= $maxAmount)
135
        {
136
            throw new MessageException(trans('meeting.refund.errors.pr_amount'));
137
        }
138
139
        $refund->update(['amount' => $amount]);
140
    }
141
142
    /**
143
     * Delete a refund.
144
     *
145
     * @param Session $session The session
146
     * @param PartialRefund $refund
147
     *
148
     * @return void
149
     */
150
    public function deletePartialRefund(Session $session, PartialRefund $refund): void
151
    {
152
        if(!$this->canModifyPartialRefund($session, $refund))
153
        {
154
            throw new MessageException(trans('meeting.refund.errors.cannot_delete'));
155
        }
156
157
        $refund->delete();
158
    }
159
}
160