Passed
Pull Request — main (#67)
by Thierry
06:31
created

DepositService::getReceivable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 5
rs 10
c 2
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Pool;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Relations\Relation;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Collection;
9
use Siak\Tontine\Model\Deposit;
10
use Siak\Tontine\Model\DepositReal;
11
use Siak\Tontine\Model\Pool;
12
use Siak\Tontine\Model\Receivable;
13
use Siak\Tontine\Model\Session;
14
use Siak\Tontine\Service\Payment\PaymentServiceInterface;
15
use Siak\Tontine\Service\TenantService;
16
use Siak\Tontine\Validation\SearchSanitizer;
17
18
class DepositService
19
{
20
    use DepositServiceTrait;
0 ignored issues
show
introduced by
The trait Siak\Tontine\Service\Mee...ool\DepositServiceTrait requires some properties which are not provided by Siak\Tontine\Service\Meeting\Pool\DepositService: $deposit_fixed, $id, $deposit
Loading history...
21
22
    /**
23
     * @param TenantService $tenantService
24
     * @param PaymentServiceInterface $paymentService
25
     * @param SearchSanitizer $searchSanitizer
26
     */
27
    public function __construct(protected TenantService $tenantService,
28
        protected PaymentServiceInterface $paymentService,
29
        protected SearchSanitizer $searchSanitizer)
30
    {}
31
32
    /**
33
     * @param Pool $pool
34
     * @param Session $session
35
     * @param bool|null $filter
36
     * @param string $search
37
     *
38
     * @return Builder|Relation
39
     */
40
    private function getQuery(Pool $pool, Session $session,
41
        ?bool $filter = null, string $search = ''): Builder|Relation
42
    {
43
        $filterQuery = match($filter) {
44
            true => fn(Builder $query) => $query->paid(),
45
            false => fn(Builder $query) => $query->unpaid(),
46
            default => null,
47
        };
48
        $search = $this->searchSanitizer->sanitize($search);
49
50
        return $session->receivables()
51
            ->select('receivables.*')
52
            ->join('subscriptions', 'subscriptions.id', '=', 'receivables.subscription_id')
53
            ->where('subscriptions.pool_id', $pool->id)
54
            ->when($filterQuery !== null, $filterQuery)
55
            ->when($search !== '', fn(Builder $query) => $query->search($search));
56
    }
57
58
    /**
59
     * @param Pool $pool
60
     * @param Session $session
61
     * @param bool|null $filter
62
     * @param string $search
63
     * @param int $page
64
     *
65
     * @return Collection
66
     */
67
    public function getReceivables(Pool $pool, Session $session,
68
        ?bool $filter = null, string $search = '', int $page = 0): Collection
69
    {
70
        // The jointure with the subscriptions and members tables is needed,
71
        // so the final records can be ordered by member name.
72
        $query = $this->getQuery($pool, $session, $filter, $search);
73
        return $this->getReceivableDetailsQuery($query, $page)->get();
74
    }
75
76
    /**
77
     * Get the number of receivables in the selected round.
78
     *
79
     * @param Pool $pool
80
     * @param Session $session
81
     * @param bool|null $filter
82
     * @param string $search
83
     *
84
     * @return int
85
     */
86
    public function getReceivableCount(Pool $pool, Session $session,
87
        ?bool $filter = null, string $search = ''): int
88
    {
89
        return $this->getQuery($pool, $session, $filter, $search)->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getQuery($...lter, $search)->count() could return the type Illuminate\Database\Eloq...uent\Relations\Relation which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
90
    }
91
92
    /**
93
     * Find the unique receivable for a pool and a session.
94
     *
95
     * @param Pool $pool The pool
96
     * @param Session $session The session
97
     * @param int $receivableId
98
     *
99
     * @return Receivable|null
100
     */
101
    public function getReceivable(Pool $pool, Session $session, int $receivableId): ?Receivable
102
    {
103
        return $this->getQuery($pool, $session)
104
            ->with(['deposit'])
105
            ->find($receivableId);
106
    }
107
108
    /**
109
     * Create a deposit.
110
     *
111
     * @param Pool $pool The pool
112
     * @param Session $session The session
113
     * @param int $receivableId
114
     * @param int $amount
115
     *
116
     * @return void
117
     */
118
    public function createDeposit(Pool $pool, Session $session,
119
        int $receivableId, int $amount = 0): void
120
    {
121
        $receivable = $this->getReceivable($pool, $session, $receivableId);
122
        $this->checkDepositCreation($pool, $receivable, $amount);
123
124
        $this->saveDeposit($receivable, $session, $amount);
125
    }
126
127
    /**
128
     * Delete a deposit.
129
     *
130
     * @param Pool $pool The pool
131
     * @param Session $session The session
132
     * @param int $receivableId
133
     *
134
     * @return void
135
     */
136
    public function deleteDeposit(Pool $pool, Session $session, int $receivableId): void
137
    {
138
        $receivable = $this->getReceivable($pool, $session, $receivableId);
139
        $this->_deleteDeposit($receivable);
140
    }
141
142
    /**
143
     * Create all deposits for a pool.
144
     *
145
     * @param Pool $pool The pool
146
     * @param Session $session The session
147
     * @param string $search
148
     *
149
     * @return void
150
     */
151
    public function createAllDeposits(Pool $pool, Session $session, string $search): void
152
    {
153
        $receivables = $this->getQuery($pool, $session, false, $search)->get();
154
        if($receivables->count() === 0)
155
        {
156
            return;
157
        }
158
159
        DB::transaction(function() use($session, $receivables) {
160
            foreach($receivables as $receivable)
161
            {
162
                $deposit = new DepositReal();
163
                $deposit->receivable()->associate($receivable);
164
                $deposit->session()->associate($session);
165
                $deposit->save();
166
            }
167
        });
168
    }
169
170
    /**
171
     * Delete all deposits for a pool.
172
     *
173
     * @param Pool $pool The pool
174
     * @param Session $session The session
175
     * @param string $search
176
     *
177
     * @return void
178
     */
179
    public function deleteAllDeposits(Pool $pool, Session $session, string $search): void
180
    {
181
        $receivables = $this->getQuery($pool, $session, true, $search)
182
            ->with(['deposit'])
183
            ->get()
184
            ->filter(fn($receivable) =>
185
                $this->paymentService->isEditable($receivable->deposit));
186
        if($receivables->count() === 0)
187
        {
188
            return;
189
        }
190
191
        DepositReal::whereIn('receivable_id', $receivables->pluck('id'))
192
            ->where('session_id', $session->id)
193
            ->delete();
194
    }
195
196
    /**
197
     * @param Pool $pool The pool
198
     * @param Session $session The session
199
     *
200
     * @return int
201
     */
202
    public function getPoolDepositCount(Pool $pool, Session $session): int
203
    {
204
        return $this->getQuery($pool, $session, true)->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getQuery($...session, true)->count() could return the type Illuminate\Database\Eloq...uent\Relations\Relation which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
205
    }
206
207
    /**
208
     * @param Pool $pool The pool
209
     * @param Session $session The session
210
     *
211
     * @return array
212
     */
213
    public function getPoolDepositNumbers(Pool $pool, Session $session): array
214
    {
215
        $pool = Pool::where('id', $pool->id)
216
            ->select([
217
                'recv_amount' => Deposit::select(DB::raw('sum(amount)'))
218
                    ->whereColumn('pool_id', 'pools.id')
219
                    ->whereHas('receivable', fn(Builder $qr) =>
220
                        $qr->whereSession($session)->paidHere($session)),
221
            ])
222
            ->withCount([
223
                'receivables as recv_count' => fn(Builder $query) =>
224
                    $query->whereSession($session),
225
                'receivables as paid_here' => fn(Builder $query) =>
226
                    $query->whereSession($session)->paidHere($session),
227
                'receivables as paid_late' => fn(Builder $query) =>
228
                    $query->whereSession($session)->paidLater($session),
229
                'receivables as paid_early' => fn(Builder $query) =>
230
                    $query->whereSession($session)->paidEarlier($session),
231
            ])
232
            ->first();
233
        return !$pool ? [0, 0, 0] : [
234
            $pool->recv_amount ??= 0, // The amount paid in the session
0 ignored issues
show
Bug introduced by
The property recv_amount does not exist on Siak\Tontine\Model\Pool. Did you mean amount?
Loading history...
235
            $pool->paid_here, // The number of recv paid in the session
0 ignored issues
show
Bug introduced by
The property paid_here does not seem to exist on Siak\Tontine\Model\Pool. 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...
236
            $pool->recv_count - $pool->paid_late - $pool->paid_early, // The total expected count
0 ignored issues
show
Bug introduced by
The property paid_early does not seem to exist on Siak\Tontine\Model\Pool. 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...
Bug introduced by
The property recv_count does not seem to exist on Siak\Tontine\Model\Pool. 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...
Bug introduced by
The property paid_late does not seem to exist on Siak\Tontine\Model\Pool. 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...
237
        ];
238
    }
239
}
240