Passed
Push — main ( 2f3e46...485e61 )
by Thierry
05:35
created

SummaryService::getDeposits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 13
nc 1
nop 2
dl 0
loc 16
rs 9.8333
c 1
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Siak\Tontine\Model\Pool;
8
use Siak\Tontine\Model\Round;
9
use Siak\Tontine\Model\Session;
10
use Siak\Tontine\Service\BalanceCalculator;
11
use Siak\Tontine\Service\Planning\PoolService;
12
use Siak\Tontine\Service\TenantService;
13
use Siak\Tontine\Service\Traits\ReportTrait;
14
use stdClass;
15
16
use function collect;
17
use function compact;
18
19
class SummaryService
20
{
21
    use ReportTrait;
0 ignored issues
show
introduced by
The trait Siak\Tontine\Service\Traits\ReportTrait requires some properties which are not provided by Siak\Tontine\Service\Meeting\SummaryService: $deposit_fixed, $id
Loading history...
22
23
    /**
24
     * @var Collection
25
     */
26
    private $deposits;
27
28
    /**
29
     * @var Collection
30
     */
31
    private $remitments;
32
33
    /**
34
     * @var Collection
35
     */
36
    private $auctions;
37
38
    /**
39
     * @param BalanceCalculator $balanceCalculator
40
     * @param TenantService $tenantService
41
     * @param PoolService $poolService
42
     */
43
    public function __construct(protected BalanceCalculator $balanceCalculator,
44
        protected TenantService $tenantService, PoolService $poolService)
45
    {
46
        $this->poolService = $poolService;
47
    }
48
49
    /**
50
     * @param Pool $pool
51
     * @param int $cashier
52
     * @param stdClass|null $deposit
53
     * @param stdClass|null $remitment
54
     *
55
     * @return stdClass
56
     */
57
    private function getSessionFigures(Pool $pool, int $cashier,
58
        ?stdClass $deposit, ?stdClass $remitment): stdClass
59
    {
60
        $figures = $this->makeFigures(0);
61
        $figures->cashier->start = $cashier;
62
        $figures->cashier->recv = $cashier;
63
64
        $depositCount = $deposit?->count ?? 0;
65
        $depositAmount = $pool->deposit_fixed ?
66
            $pool->amount * $depositCount : ($deposit?->amount ?? 0);
67
68
        $figures->deposit->amount += $depositAmount;
69
        $figures->cashier->recv += $depositAmount;
70
        $figures->deposit->count = $depositCount;
71
72
        $sessionCount = $pool->counter->sessions - $pool->counter->disabled_sessions;
0 ignored issues
show
Bug introduced by
The property sessions does not seem to exist on Siak\Tontine\Model\PoolCounter. 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 disabled_sessions does not seem to exist on Siak\Tontine\Model\PoolCounter. 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...
73
        $remitmentCount = $remitment?->count ?? 0;
74
        $remitmentAmount = $pool->deposit_fixed ?
75
            $pool->amount * $sessionCount * $remitmentCount :
76
            ($remitmentCount > 0 ? $depositAmount : 0);
77
78
        $figures->cashier->end = $figures->cashier->recv;
79
        $figures->remitment->amount += $remitmentAmount;
80
        $figures->cashier->end -= $remitmentAmount;
81
        $figures->remitment->count += $remitmentCount;
82
83
        return $figures;
84
    }
85
86
    /**
87
     * @param Pool $pool
88
     * @param Collection $sessions
89
     *
90
     * @return array
91
     */
92
    private function getCollectedFigures(Pool $pool, Collection $sessions): array
93
    {
94
        $cashier = 0;
95
        $collectedFigures = [];
96
        foreach($sessions as $session)
97
        {
98
            $deposit = $this->deposits[$pool->id][$session->id] ?? null;
99
            $remitment = $this->remitments[$pool->id][$session->id] ?? null;
100
            $figures = $this->getSessionFigures($pool, $cashier, $deposit, $remitment);
101
            if($pool->remit_auction)
102
            {
103
                // Add the auctions amount to the cash amount.
104
                $figures->cashier->end += $this->auctions[$pool->id][$session->id]?->amount ?? 0;
105
            }
106
            $cashier = $figures->cashier->end;
107
            $collectedFigures[$session->id] = $figures;
108
        }
109
110
        return $collectedFigures;
111
    }
112
113
    /**
114
     * @param Round $round
115
     * @param Collection $poolIds
116
     *
117
     * @return void
118
     */
119
    private function getDeposits(Round $round, Collection $poolIds): void
120
    {
121
        $this->deposits = DB::table('deposits')
122
            ->select('subscriptions.pool_id', 'receivables.session_id',
123
                DB::raw('count(*) as count'), DB::raw('sum(deposits.amount) as amount'))
124
            ->join('receivables', 'receivables.id', '=', 'deposits.receivable_id')
125
            ->join('subscriptions', 'receivables.subscription_id', '=', 'subscriptions.id')
126
            ->join('sessions', 'receivables.session_id', '=', 'sessions.id')
127
            ->whereIn('subscriptions.pool_id', $poolIds)
128
            ->where('sessions.round_id', $round->id)
129
            ->groupBy(['subscriptions.pool_id', 'receivables.session_id'])
130
            ->get()
131
            // Group the data by pool id and session id.
132
            ->groupBy('pool_id')
133
            ->map(fn($poolDeposits) => $poolDeposits->groupBy('session_id')
134
                ->map(fn($array) => $array->first()));
135
    }
136
137
    /**
138
     * @param Round $round
139
     * @param Collection $poolIds
140
     *
141
     * @return void
142
     */
143
    private function getRemitments(Round $round, Collection $poolIds): void
144
    {
145
        $this->remitments = DB::table('remitments')
146
            ->select('subscriptions.pool_id', 'payables.session_id', DB::raw('count(*) as count'))
147
            ->join('payables', 'payables.id', '=', 'remitments.payable_id')
148
            ->join('subscriptions', 'payables.subscription_id', '=', 'subscriptions.id')
149
            ->join('sessions', 'payables.session_id', '=', 'sessions.id')
150
            ->whereIn('subscriptions.pool_id', $poolIds)
151
            ->where('sessions.round_id', $round->id)
152
            ->groupBy(['subscriptions.pool_id', 'payables.session_id'])
153
            ->get()
154
            // Group the data by pool id and session id.
155
            ->groupBy('pool_id')
156
            ->map(fn($poolRemitments) => $poolRemitments->groupBy('session_id')
157
                ->map(fn($array) => $array->first()));
158
    }
159
160
    /**
161
     * @param Round $round
162
     * @param Collection $poolIds
163
     *
164
     * @return void
165
     */
166
    private function getAuctions(Round $round, Collection $poolIds): void
167
    {
168
        $this->auctions = DB::table('auctions')
169
            ->select('subscriptions.pool_id', 'auctions.session_id',
170
                DB::raw('count(*) as count'), DB::raw('sum(amount) as amount'))
171
            ->join('remitments', 'auctions.remitment_id', '=', 'remitments.id')
172
            ->join('payables', 'remitments.payable_id', '=', 'payables.id')
173
            ->join('subscriptions', 'payables.subscription_id', '=', 'subscriptions.id')
174
            ->join('sessions', 'payables.session_id', '=', 'sessions.id')
175
            ->whereIn('subscriptions.pool_id', $poolIds)
176
            ->where('sessions.round_id', $round->id)
177
            ->groupBy(['subscriptions.pool_id', 'auctions.session_id'])
178
            ->get()
179
            // Group the data by pool id and session id.
180
            ->groupBy('pool_id')
181
            ->map(fn($poolAuctions) => $poolAuctions->groupBy('session_id')
182
                ->map(fn($array) => $array->first()));
183
    }
184
185
    /**
186
     * @param Pool $pool
187
     *
188
     * @return array
189
     */
190
    private function getPoolFigures(Pool $pool): array
191
    {
192
        $sessions = $this->poolService->getActiveSessions($pool);
193
194
        $figures = new stdClass();
195
        if($pool->remit_planned)
196
        {
197
            $figures->expected = $this->getExpectedFigures($pool, $sessions);
198
        }
199
        $figures->collected = $this->getCollectedFigures($pool, $sessions);
200
        if($pool->remit_auction)
201
        {
202
            $figures->auctions = $this->auctions[$pool->id] ?? collect();
203
        }
204
205
        return compact('pool', 'figures', 'sessions');
206
    }
207
208
    /**
209
     * Get the receivables of a given pool.
210
     *
211
     * @param Round $round
212
     * @param int $poolId
213
     *
214
     * @return Collection
215
     */
216
    public function getFigures(Round $round, int $poolId = 0): Collection
217
    {
218
        $pools = $round->pools()
219
            ->with(['round.tontine', 'counter'])
220
            ->whereHas('subscriptions')
221
            ->when($poolId > 0, fn($query) => $query->where('pools.id', $poolId))
222
            ->get();
223
        if($pools->count() === 0)
224
        {
225
            return collect();
226
        }
227
228
        $poolIds = $pools->pluck('id');
229
        $this->getDeposits($round, $poolIds);
230
        $this->getRemitments($round, $poolIds);
231
        $this->getAuctions($round, $poolIds);
232
233
        return $pools->map(fn(Pool $pool) => $this->getPoolFigures($pool));
234
    }
235
236
    /**
237
     * @param Pool $pool
238
     * @param Session $session
239
     *
240
     * @return int
241
     */
242
    public function getSessionRemitmentCount(Pool $pool, Session $session): int
243
    {
244
        if(!$pool->remit_planned)
245
        {
246
            return -1;
247
        }
248
        if(!$pool->deposit_fixed)
249
        {
250
            return 1;
251
        }
252
253
        $sessions = $this->poolService->getActiveSessions($pool);
254
        $position = $sessions->filter(
255
            fn($_session) => $_session->start_at->lt($session->start_at)
256
        )->count();
257
258
        return $this->getRemitmentCount($sessions->count(),
259
            $pool->subscriptions()->count(), $position);
260
    }
261
}
262