SavingService::getMemberSavingsFilter()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Saving;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Relations\Relation;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\DB;
9
use Siak\Tontine\Model\Fund;
10
use Siak\Tontine\Model\Member;
11
use Siak\Tontine\Model\Round;
12
use Siak\Tontine\Model\Saving;
13
use Siak\Tontine\Model\Session;
14
use Siak\Tontine\Service\LocaleService;
15
use Siak\Tontine\Service\TenantService;
16
use Siak\Tontine\Validation\SearchSanitizer;
17
use Closure;
18
19
class SavingService
20
{
21
    /**
22
     * @param LocaleService $localeService
23
     * @param TenantService $tenantService
24
     * @param SearchSanitizer $searchSanitizer
25
     */
26
    public function __construct(private LocaleService $localeService,
27
        private TenantService $tenantService, private SearchSanitizer $searchSanitizer)
28
    {}
29
30
    /**
31
     * Count the session funds.
32
     *
33
     * @param Session $session
34
     *
35
     * @return int
36
     */
37
    public function getFundCount(Session $session): int
38
    {
39
        return $session->funds()->real()->count();
40
    }
41
42
    /**
43
     * @param Session $session
44
     *
45
     * @return Relation
46
     */
47
    private function getFundQuery(Session $session): Relation
48
    {
49
        $sqlFrom = "savings s where s.fund_id=funds.id and s.session_id={$session->id}";
50
        return $session->funds()->real()
51
            ->addSelect([
52
                DB::raw("(select count(*) from $sqlFrom) as s_count"),
53
                DB::raw("(select sum(s.amount) from $sqlFrom) as s_amount"),
54
            ]);
55
    }
56
57
    /**
58
     * Get the session funds.
59
     *
60
     * @param Session $session
61
     * @param int $page
62
     *
63
     * @return Collection
64
     */
65
    public function getFunds(Session $session, int $page = 0): Collection
66
    {
67
        return $this->getFundQuery($session)
68
            ->page($page, $this->tenantService->getLimit())
69
            ->join('fund_defs', 'fund_defs.id', '=', 'funds.def_id')
70
            ->orderBy('fund_defs.type') // The default fund is first in the list.
71
            ->orderBy('funds.id')
72
            ->get();
73
    }
74
75
    /**
76
     * Get a session fund.
77
     *
78
     * @param Session $session
79
     * @param int $fundId
80
     *
81
     * @return Fund|null
82
     */
83
    public function getFund(Session $session, int $fundId): ?Fund
84
    {
85
        return $this->getFundQuery($session)->find($fundId);
86
    }
87
88
    /**
89
     * @param Session $session
90
     * @param Fund|null $fund
91
     *
92
     * @return Builder|Relation
93
     */
94
    private function getSavingQuery(Session $session, ?Fund $fund): Builder|Relation
95
    {
96
        return $session->savings()->when($fund !== null,
97
            fn(Builder $query) => $query->where('fund_id', $fund->id));
98
    }
99
100
    /**
101
     * Find a member saving for a given session.
102
     *
103
     * @param Session $session
104
     * @param Fund $fund
105
     * @param Member $member
106
     *
107
     * @return Saving|null
108
     */
109
    public function findSaving(Session $session, Fund $fund, Member $member): ?Saving
110
    {
111
        return $this->getSavingQuery($session, $fund)
112
            ->where('member_id', $member->id)
113
            ->first();
114
    }
115
116
    /**
117
     * @param Session $session
118
     * @param Fund $fund
119
     * @param Member $member
120
     * @param Saving $saving
121
     * @param int $amount
122
     *
123
     * @return void
124
     */
125
    private function persistSaving(Session $session, Fund $fund, Member $member,
126
        Saving $saving, int $amount)
127
    {
128
        $saving->amount = $amount;
129
        $saving->session()->associate($session);
130
        $saving->fund()->associate($fund);
131
        $saving->member()->associate($member);
132
        $saving->save();
133
    }
134
135
    /**
136
     * Create or update a saving.
137
     *
138
     * @param Session $session The session
139
     * @param Fund $fund
140
     * @param Member $member
141
     * @param int $amount
142
     *
143
     * @return void
144
     */
145
    public function saveSaving(Session $session, Fund $fund, Member $member, int $amount): void
146
    {
147
        $saving = $this->findSaving($session, $fund, $member);
148
        if(!$saving)
149
        {
150
            $saving = new Saving();
151
        }
152
153
        $this->persistSaving($session, $fund, $member, $saving, $amount);
154
    }
155
156
    /**
157
     * @param Session $session
158
     * @param Fund $fund
159
     *
160
     * @return Closure
161
     */
162
    private function getMemberSavingsFilter(Session $session, Fund $fund): Closure
163
    {
164
        return fn(/*Builder|Relation*/ $query) =>
165
            $query->where('session_id', $session->id)->where('fund_id', $fund->id);
166
    }
167
168
    /**
169
     * @param Session $session
170
     * @param Fund $fund
171
     * @param string $search
172
     * @param bool|null $filter
173
     *
174
     * @return Builder|Relation
175
     */
176
    private function getMembersQuery(Session $session, Fund $fund,
177
        string $search, ?bool $filter): Builder|Relation
178
    {
179
        $savingsFilter = $this->getMemberSavingsFilter($session, $fund);
180
        return $session->round->members()
181
            ->search($this->searchSanitizer->sanitize($search))
182
            ->when($filter === true, fn(Builder $query) =>
183
                $query->whereHas('savings', $savingsFilter))
184
            ->when($filter === false, fn(Builder $query) =>
185
                $query->whereDoesntHave('savings', $savingsFilter));
186
    }
187
188
    /**
189
     * Get a paginated list of members.
190
     *
191
     * @param Session $session
192
     * @param Fund $fund
193
     * @param string $search
194
     * @param bool|null $filter
195
     * @param int $page
196
     *
197
     * @return Collection
198
     */
199
    public function getMembers(Session $session, Fund $fund, string $search,
200
        ?bool $filter, int $page = 0): Collection
201
    {
202
        return $this->getMembersQuery($session, $fund, $search, $filter)
203
            ->page($page, $this->tenantService->getLimit())
204
            ->with('savings', $this->getMemberSavingsFilter($session, $fund))
205
            ->orderBy('name', 'asc')
206
            ->get()
207
            ->each(fn($member) => $member->saving = $member->savings->first());
208
    }
209
210
    /**
211
     * Get the number of members.
212
     *
213
     * @param Session $session
214
     * @param Fund $fund
215
     * @param string $search
216
     * @param bool|null $filter
217
     *
218
     * @return int
219
     */
220
    public function getMemberCount(Session $session, Fund $fund, string $search, ?bool $filter): int
221
    {
222
        return $this->getMembersQuery($session, $fund, $search, $filter)->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMembers...arch, $filter)->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...
223
    }
224
225
    /**
226
     * Delete a saving.
227
     *
228
     * @param Session $session The session
229
     * @param Fund $fund
230
     * @param Member $member
231
     *
232
     * @return void
233
     */
234
    public function deleteMemberSaving(Session $session, Fund $fund, Member $member): void
235
    {
236
        $session->savings()
237
            ->where('fund_id', $fund->id)
238
            ->where('member_id', $member->id)
239
            ->delete();
240
    }
241
242
    /**
243
     * Get a single member.
244
     *
245
     * @param Round $round
246
     * @param int $memberId
247
     *
248
     * @return Member|null
249
     */
250
    public function getMember(Round $round, int $memberId): ?Member
251
    {
252
        return $round->members()->find($memberId);
253
    }
254
255
    /**
256
     * @param Fund $fund
257
     * @param int $amount
258
     *
259
     * @return void
260
     */
261
    public function saveFundStartAmount(Fund $fund, int $amount): void
262
    {
263
        $options = $fund->options;
264
        $options['amount']['start'] = $amount;
265
        $fund->options = $options;
266
        $fund->save();
267
    }
268
269
    /**
270
     * @param Fund $fund
271
     * @param int $amount
272
     *
273
     * @return void
274
     */
275
    public function saveFundEndAmount(Fund $fund, int $amount): void
276
    {
277
        $options = $fund->options;
278
        $options['amount']['end'] = $amount;
279
        $fund->options = $options;
280
        $fund->save();
281
    }
282
283
    /**
284
     * @param Fund $fund
285
     * @param int $amount
286
     *
287
     * @return void
288
     */
289
    public function saveFundProfitAmount(Fund $fund, int $amount): void
290
    {
291
        $options = $fund->options;
292
        $options['amount']['profit'] = $amount;
293
        $fund->options = $options;
294
        $fund->save();
295
    }
296
}
297