Passed
Push — main ( 5b7914...28aa50 )
by Thierry
05:31
created

PoolService::saveStartSession()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Planning;
4
5
use Exception;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Relations\Relation;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Facades\DB;
10
use Siak\Tontine\Exception\MessageException;
11
use Siak\Tontine\Model\Pool;
12
use Siak\Tontine\Model\Session;
13
use Siak\Tontine\Service\TenantService;
14
15
use function trans;
16
17
class PoolService
18
{
19
    /**
20
     * @param TenantService $tenantService
21
     */
22
    public function __construct(protected TenantService $tenantService)
23
    {}
24
25
    /**
26
     * @return Builder|Relation
27
     */
28
    private function getQuery(): Builder|Relation
29
    {
30
        return Pool::ofRound($this->tenantService->round());
31
    }
32
33
    /**
34
     * Get a paginated list of pools.
35
     *
36
     * @param int $page
37
     *
38
     * @return Collection
39
     */
40
    public function getPools(int $page = 0): Collection
41
    {
42
        return $this->getQuery()
43
            ->page($page, $this->tenantService->getLimit())
44
            ->get();
45
    }
46
47
    /**
48
     * Get the number of pools.
49
     *
50
     * @return int
51
     */
52
    public function getPoolCount(): int
53
    {
54
        return $this->getQuery()->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getQuery()->count() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
55
    }
56
57
    /**
58
     * Get a single pool.
59
     *
60
     * @param int $poolId    The pool id
61
     *
62
     * @return Pool|null
63
     */
64
    public function getPool(int $poolId): ?Pool
65
    {
66
        return $this->getQuery()->with('counter')->find($poolId);
67
    }
68
69
    /**
70
     * Get the pools in the current round.
71
     *
72
     * @return Collection
73
     */
74
    public function getRoundPools(): Collection
75
    {
76
        return $this->tenantService->round()->pools()->get();
77
    }
78
79
    /**
80
     * Add a new pool.
81
     *
82
     * @param array $values
83
     *
84
     * @return bool
85
     */
86
    public function createPool(array $values): bool
87
    {
88
        $this->tenantService->round()->pools()->create($values);
89
90
        return true;
91
    }
92
93
    /**
94
     * Update a pool.
95
     *
96
     * @param Pool $pool
97
     * @param array $values
98
     *
99
     * @return bool
100
     */
101
    public function updatePool(Pool $pool, array $values): bool
102
    {
103
        return $pool->update($values);
104
    }
105
106
    /**
107
     * Delete a pool.
108
     *
109
     * @param Pool $pool
110
     *
111
     * @return void
112
     */
113
    public function deletePool(Pool $pool)
114
    {
115
        try
116
        {
117
            DB::transaction(function() use($pool) {
118
                DB::table('pool_session_disabled')->where('pool_id', $pool->id)->delete();
119
                $subscriptionIds = $pool->subscriptions()->pluck('id');
120
                DB::table('receivables')->whereIn('subscription_id', $subscriptionIds)->delete();
121
                DB::table('payables')->whereIn('subscription_id', $subscriptionIds)->delete();
122
                $pool->subscriptions()->delete();
123
                $pool->delete();
124
            });
125
        }
126
        catch(Exception $e)
127
        {
128
            throw new MessageException(trans('tontine.errors.action') .
129
                '<br/>' . trans('tontine.pool.errors.subscription'));
130
        }
131
    }
132
133
    /**
134
     * @param int $count
135
     *
136
     * @return Collection
137
     */
138
    public function getFakePools(int $count): Collection
139
    {
140
        return Pool::factory()->count($count)->make([
141
            'round_id' => $this->tenantService->round(),
142
        ]);
143
    }
144
145
    /**
146
     * Save the pool start and/or end session.
147
     *
148
     * @param Pool $pool
149
     * @param array $values
150
     *
151
     * @return void
152
     */
153
    public function saveSessions(Pool $pool, array $values)
154
    {
155
        if($pool->pool_round !== null)
156
        {
157
            $pool->pool_round()->update($values);
158
            return;
159
        }
160
161
        // The initial value is the same for start and end sessions.
162
        if(!isset($values['start_session_id']))
163
        {
164
            $values['start_session_id'] = $this
165
                ->getPoolStartSession($pool)?->id ?? $values['end_session_id'];
166
        }
167
        if(!isset($values['end_session_id']))
168
        {
169
            $values['end_session_id'] = $this
170
                ->getPoolEndSession($pool)?->id ?? $values['start_session_id'];
171
        }
172
        $pool->pool_round()->create($values);
173
    }
174
175
    /**
176
     * Delete the pool round.
177
     *
178
     * @param Pool $pool
179
     *
180
     * @return void
181
     */
182
    public function deleteRound(Pool $pool)
183
    {
184
        $pool->pool_round()->delete();
185
    }
186
187
    /**
188
     * Get a paginated list of sessions.
189
     *
190
     * @param Pool $pool
191
     * @param int $page
192
     *
193
     * @return Collection
194
     */
195
    public function getPoolSessions(Pool $pool, int $page = 0): Collection
196
    {
197
        return $pool->sessions()
198
            ->orderBy('start_at', 'asc')
199
            ->page($page, $this->tenantService->getLimit())
200
            ->get();
201
    }
202
203
    /**
204
     * Get the number of sessions.
205
     *
206
     * @param Pool $pool
207
     *
208
     * @return int
209
     */
210
    public function getPoolSessionCount(Pool $pool): int
211
    {
212
        return $pool->sessions()->count();
213
    }
214
215
    /**
216
     * Get the first session of the pool.
217
     *
218
     * @param Pool $pool
219
     *
220
     * @return Session|null
221
     */
222
    public function getPoolStartSession(Pool $pool): ?Session
223
    {
224
        return $pool->sessions()->orderBy('start_at', 'asc')->first();
225
    }
226
227
    /**
228
     * Get the last session of the pool.
229
     *
230
     * @param Pool $pool
231
     *
232
     * @return Session|null
233
     */
234
    public function getPoolEndSession(Pool $pool): ?Session
235
    {
236
        return $pool->sessions()->orderBy('start_at', 'desc')->first();
237
    }
238
239
    /**
240
     * Enable or disable a session for a pool.
241
     *
242
     * @param Pool $pool
243
     * @param int $sessionId    The session id
244
     *
245
     * @return void
246
     */
247
    public function enableSession(Pool $pool, int $sessionId)
248
    {
249
        // When the remitments are planned, don't enable or disable a session
250
        // if receivables already exist on the pool.
251
        // if($pool->remit_planned &&
252
        //     $pool->subscriptions()->whereHas('receivables')->count() > 0)
253
        // {
254
        //     return;
255
        // }
256
        $session = $pool->sessions()->find($sessionId);
257
        if(!$session || $session->enabled($pool))
258
        {
259
            return;
260
        }
261
262
        // Enable the session for the pool.
263
        $pool->disabledSessions()->detach($session->id);
264
    }
265
266
    /**
267
     * Enable or disable a session for a pool.
268
     *
269
     * @param Pool $pool
270
     * @param int $sessionId    The session id
271
     *
272
     * @return void
273
     */
274
    public function disableSession(Pool $pool, int $sessionId)
275
    {
276
        // When the remitments are planned, don't enable or disable a session
277
        // if receivables already exist on the pool.
278
        // if($pool->remit_planned &&
279
        //     $pool->subscriptions()->whereHas('receivables')->count() > 0)
280
        // {
281
        //     return;
282
        // }
283
        $session = $pool->sessions()->find($sessionId);
284
        if(!$session || $session->disabled($pool))
285
        {
286
            return;
287
        }
288
289
        // Disable the session for the pool.
290
        DB::transaction(function() use($pool, $session) {
291
            // If a session was already opened, delete the receivables and payables.
292
            // Will fail if any of them is already paid.
293
            $subscriptionIds = $pool->subscriptions()->pluck('id');
294
            $session->receivables()
295
                ->whereIn('subscription_id', $subscriptionIds)
296
                ->delete();
297
            // The payables should not be deleted, but detached from the session instead.
298
            $session->payables()
299
                ->whereIn('subscription_id', $subscriptionIds)
300
                ->update(['session_id' => null]);
301
            // Disable the session for the pool.
302
            $pool->disabledSessions()->attach($session->id);
303
        });
304
    }
305
306
    /**
307
     * Get the sessions enabled for a pool.
308
     *
309
     * @param Pool $pool
310
     *
311
     * @return Collection
312
     */
313
    public function getEnabledSessions(Pool $pool): Collection
314
    {
315
        return $pool->enabledSessions()->orderBy('start_at')->get();
316
    }
317
318
    /**
319
     * Get the number of sessions enabled for a pool.
320
     *
321
     * @param Pool $pool
322
     *
323
     * @return int
324
     */
325
    public function getEnabledSessionCount(Pool $pool): int
326
    {
327
        return $pool->enabledSessions()->count();
328
    }
329
}
330