Passed
Pull Request — main (#49)
by Thierry
14:14
created

LibreFeeService::getSession()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Charge;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Siak\Tontine\Exception\MessageException;
8
use Siak\Tontine\Model\Bill;
9
use Siak\Tontine\Model\LibreBill;
10
use Siak\Tontine\Model\Charge;
11
use Siak\Tontine\Model\Session;
12
use Siak\Tontine\Model\Settlement;
13
use Siak\Tontine\Service\LocaleService;
14
use Siak\Tontine\Service\TenantService;
15
16
use function trans;
17
use function strtolower;
18
19
class LibreFeeService
20
{
21
    /**
22
     * @var LocaleService
23
     */
24
    protected LocaleService $localeService;
25
26
    /**
27
     * @var TenantService
28
     */
29
    protected TenantService $tenantService;
30
31
    /**
32
     * @param LocaleService $localeService
33
     * @param TenantService $tenantService
34
     */
35
    public function __construct(LocaleService $localeService, TenantService $tenantService)
36
    {
37
        $this->localeService = $localeService;
38
        $this->tenantService = $tenantService;
39
    }
40
41
    /**
42
     * Get a single session.
43
     *
44
     * @param int $sessionId    The session id
45
     *
46
     * @return Session|null
47
     */
48
    public function getSession(int $sessionId): ?Session
49
    {
50
        return $this->tenantService->getSession($sessionId);
51
    }
52
53
    /**
54
     * Get a paginated list of fees.
55
     *
56
     * @param int $page
57
     *
58
     * @return Collection
59
     */
60
    public function getFees(int $page = 0): Collection
61
    {
62
        return $this->tenantService->tontine()->charges()
63
            ->variable()->orderBy('id', 'desc')
64
            ->page($page, $this->tenantService->getLimit())
65
            ->get();
66
    }
67
68
    /**
69
     * Get the number of fees.
70
     *
71
     * @return int
72
     */
73
    public function getFeeCount(): int
74
    {
75
        return $this->tenantService->tontine()->charges()->variable()->count();
76
    }
77
78
    /**
79
     * @param Session $session
80
     *
81
     * @return Collection
82
     */
83
    private function getCurrentSessionBills(Session $session): Collection
84
    {
85
        // Count the session bills
86
        return DB::table('libre_bills')
87
            ->select('charge_id', DB::raw('count(*) as total'), DB::raw('sum(amount) as amount'))
88
            ->join('bills', 'libre_bills.bill_id', '=', 'bills.id')
89
            ->where('libre_bills.session_id', $session->id)
90
            ->groupBy('charge_id')
91
            ->get();
92
    }
93
94
    /**
95
     * @param Session $session
96
     *
97
     * @return Collection
98
     */
99
    private function getPreviousSessionsBills(Session $session): Collection
100
    {
101
        // Count the session bills
102
        $sessionIds = $this->tenantService->getSessionIds($session, false);
103
        return DB::table('libre_bills')
104
            ->select('charge_id', DB::raw('count(*) as total'), DB::raw('sum(amount) as amount'))
105
            ->join('bills', 'libre_bills.bill_id', '=', 'bills.id')
106
            ->whereIn('libre_bills.session_id', $sessionIds)
107
            ->groupBy('charge_id')
108
            ->get();
109
    }
110
111
    /**
112
     * @param Session $session
113
     *
114
     * @return Collection
115
     */
116
    private function getCurrentSessionSettlements(Session $session): Collection
117
    {
118
        // Count the session bills
119
        $query = DB::table('settlements')
120
            ->select('charge_id', DB::raw('count(*) as total'), DB::raw('sum(amount) as amount'))
121
            ->join('bills', 'settlements.bill_id', '=', 'bills.id')
122
            ->join('libre_bills', 'libre_bills.bill_id', '=', 'bills.id')
123
            ->where('settlements.session_id', $session->id)
124
            ->groupBy('charge_id');
125
        return $query->get();
126
    }
127
128
    /**
129
     * @param Session $session
130
     *
131
     * @return Collection
132
     */
133
    private function getPreviousSessionsSettlements(Session $session): Collection
134
    {
135
        // Count the session bills
136
        $sessionIds = $this->tenantService->getSessionIds($session, false);
137
        $query = DB::table('settlements')
138
            ->select('charge_id', DB::raw('count(*) as total'), DB::raw('sum(amount) as amount'))
139
            ->join('bills', 'settlements.bill_id', '=', 'bills.id')
140
            ->join('libre_bills', 'libre_bills.bill_id', '=', 'bills.id')
141
            ->whereIn('settlements.session_id', $sessionIds)
142
            ->groupBy('charge_id');
143
        return $query->get();
144
    }
145
146
    /**
147
     * Get the report of bills
148
     *
149
     * @param Session $session
150
     *
151
     * @return array
152
     */
153
    public function getBills(Session $session): array
154
    {
155
        $currentBills = $this->getCurrentSessionBills($session);
156
        $previousBills = $this->getPreviousSessionsBills($session);
157
        return [
158
            'total' => [
159
                'current' => $currentBills->pluck('total', 'charge_id'),
160
                'previous' => $previousBills->pluck('total', 'charge_id'),
161
            ],
162
        ];
163
    }
164
165
    /**
166
     * Get the report of settlements
167
     *
168
     * @param Session $session
169
     *
170
     * @return array
171
     */
172
    public function getSettlements(Session $session): array
173
    {
174
        $currentSettlements = $this->getCurrentSessionSettlements($session);
175
        $previousSettlements = $this->getPreviousSessionsSettlements($session);
176
        return [
177
            'total' => [
178
                'current' => $currentSettlements->pluck('total', 'charge_id'),
179
                'previous' => $previousSettlements->pluck('total', 'charge_id'),
180
            ],
181
            'amount' => [
182
                'current' => $currentSettlements->pluck('amount', 'charge_id'),
183
                'previous' => $previousSettlements->pluck('amount', 'charge_id'),
184
            ],
185
        ];
186
    }
187
188
    /**
189
     * @param Charge $charge
190
     * @param Session $session
191
     * @param string $search
192
     * @param bool $filter|null
193
     *
194
     * @return mixed
195
     */
196
    private function getMembersQuery(Charge $charge, Session $session,
197
        string $search = '', ?bool $filter)
198
    {
199
        $filterFunction = function($query) use($charge, $session) {
200
            $query->where('charge_id', $charge->id)->where('session_id', $session->id);
201
        };
202
203
        return $this->tenantService->tontine()->members()->active()
204
            ->when($search !== '', function($query) use($search) {
205
                return $query->where(DB::raw('lower(name)'), 'like', '%' . strtolower($search) . '%');
206
            })
207
            ->when($filter === false, function($query) use($filterFunction) {
208
                return $query->whereDoesntHave('libre_bills', $filterFunction);
209
            })
210
            ->when($filter === true, function($query) use($filterFunction) {
211
                $query->whereHas('libre_bills', $filterFunction);
212
            });
213
    }
214
215
    /**
216
     * @param Charge $charge
217
     * @param Session $session
218
     * @param string $search
219
     * @param bool $filter|null
220
     * @param int $page
221
     *
222
     * @return Collection
223
     */
224
    public function getMembers(Charge $charge, Session $session,
225
        string $search = '', ?bool $filter = null, int $page = 0): Collection
226
    {
227
        return $this->getMembersQuery($charge, $session, $search, $filter)
228
            ->page($page, $this->tenantService->getLimit())
229
            ->with([
230
                'libre_bills' => function($query) use($charge, $session) {
231
                    $query->where('charge_id', $charge->id)->where('session_id', $session->id);
232
                },
233
            ])
234
            ->orderBy('name', 'asc')->get()
235
            ->each(function($member) {
236
                $member->bill = $member->libre_bills->count() > 0 ?
237
                    $member->libre_bills->first()->bill : null;
238
            });
239
    }
240
241
    /**
242
     * @param Charge $charge
243
     * @param Session $session
244
     * @param string $search
245
     * @param bool $filter|null
246
     *
247
     * @return int
248
     */
249
    public function getMemberCount(Charge $charge, Session $session,
250
        string $search = '', ?bool $filter = null): int
251
    {
252
        return $this->getMembersQuery($charge, $session, $search, $filter)->count();
253
    }
254
255
    /**
256
     * @param Charge $charge
257
     * @param Session $session
258
     * @param int $memberId
259
     * @param bool $paid
260
     * @param float $amount
261
     *
262
     * @return void
263
     */
264
    public function createBill(Charge $charge, Session $session,
265
        int $memberId, bool $paid, float $amount = 0): void
266
    {
267
        $member = $this->tenantService->tontine()->members()->find($memberId);
268
        if(!$member)
269
        {
270
            throw new MessageException(trans('tontine.member.errors.not_found'));
271
        }
272
273
        if($amount !== 0)
274
        {
275
            $amount = $this->localeService->convertMoneyToInt($amount);
276
        }
277
        DB::transaction(function() use($charge, $session, $member, $paid, $amount) {
278
            $bill = Bill::create([
279
                'charge' => $charge->name,
280
                'amount' => $charge->has_amount ? $charge->amount : $amount,
281
                'lendable' => $charge->lendable,
282
                'issued_at' => now(),
283
            ]);
284
            $libreBill = new LibreBill();
285
            $libreBill->charge()->associate($charge);
286
            $libreBill->member()->associate($member);
287
            $libreBill->session()->associate($session);
288
            $libreBill->bill()->associate($bill);
289
            $libreBill->save();
290
            if($paid)
291
            {
292
                $settlement = new Settlement();
293
                $settlement->bill()->associate($bill);
294
                $settlement->session()->associate($session);
295
                $settlement->save();
296
            }
297
        });
298
    }
299
300
    /**
301
     * @param Charge $charge
302
     * @param Session $session
303
     * @param int $memberId
304
     *
305
     * @return LibreBill|null
306
     */
307
    public function getBill(Charge $charge, Session $session, int $memberId): ?LibreBill
308
    {
309
        if(!($member = $this->tenantService->tontine()->members()->find($memberId)))
310
        {
311
            throw new MessageException(trans('tontine.member.errors.not_found'));
312
        }
313
314
        return LibreBill::with(['bill.settlement'])
315
            ->where('charge_id', $charge->id)
316
            ->where('session_id', $session->id)
317
            ->where('member_id', $member->id)
318
            ->first();
319
    }
320
321
    /**
322
     * @param Charge $charge
323
     * @param Session $session
324
     * @param int $memberId
325
     * @param float $amount
326
     *
327
     * @return void
328
     */
329
    public function updateBill(Charge $charge, Session $session, int $memberId, float $amount): void
330
    {
331
        if(!($libreBill = $this->getBill($charge, $session, $memberId)))
332
        {
333
            return; // throw new MessageException(trans('tontine.bill.errors.not_found'));
334
        }
335
336
        $libreBill->bill->update([
337
            'amount'=> $this->localeService->convertMoneyToInt($amount),
338
        ]);
339
    }
340
341
    /**
342
     * @param Charge $charge
343
     * @param Session $session
344
     * @param int $memberId
345
     *
346
     * @return void
347
     */
348
    public function deleteBill(Charge $charge, Session $session, int $memberId): void
349
    {
350
        if(!($libreBill = $this->getBill($charge, $session, $memberId)))
351
        {
352
            return; // throw new MessageException(trans('tontine.bill.errors.not_found'));
353
        }
354
355
        DB::transaction(function() use($libreBill, $session) {
356
            $bill = $libreBill->bill;
357
            $libreBill->delete();
358
            if($bill !== null)
359
            {
360
                // Delete the settlement only if it is on the same session
361
                if($bill->settlement !== null && $bill->settlement->session_id === $session->id)
362
                {
363
                    $bill->settlement->delete();
364
                }
365
                $bill->delete();
366
            }
367
        });
368
    }
369
}
370