SummaryService   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 272
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 112
c 1
b 0
f 0
dl 0
loc 272
rs 10
wmc 24

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getFunds() 0 5 3
A getRemitments() 0 15 1
A getDeposits() 0 16 1
A getAuctions() 0 18 1
A getCollectedFigures() 0 19 3
A getSessionRemitmentCount() 0 18 3
A getPoolFigures() 0 15 3
A getPoolsBalance() 0 11 3
A getSessionFigures() 0 26 3
A getFigures() 0 18 2
1
<?php
2
3
namespace Siak\Tontine\Service\Meeting\Session;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Siak\Tontine\Model\Fund;
8
use Siak\Tontine\Model\Pool;
9
use Siak\Tontine\Model\Round;
10
use Siak\Tontine\Model\Session;
11
use Siak\Tontine\Service\Payment\BalanceCalculator;
12
use Siak\Tontine\Service\Planning\PoolService;
13
use Siak\Tontine\Service\TenantService;
14
use Siak\Tontine\Service\Traits\ReportTrait;
15
use stdClass;
16
17
use function collect;
18
use function compact;
19
20
class SummaryService
21
{
22
    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\Mee...\Session\SummaryService: $deposit_fixed, $id
Loading history...
23
24
    /**
25
     * @var Collection
26
     */
27
    private $deposits;
28
29
    /**
30
     * @var Collection
31
     */
32
    private $remitments;
33
34
    /**
35
     * @var Collection
36
     */
37
    private $auctions;
38
39
    /**
40
     * @param BalanceCalculator $balanceCalculator
41
     * @param TenantService $tenantService
42
     * @param PoolService $poolService
43
     */
44
    public function __construct(protected BalanceCalculator $balanceCalculator,
45
        protected TenantService $tenantService, PoolService $poolService)
46
    {
47
        $this->poolService = $poolService;
48
    }
49
50
    /**
51
     * @param Pool $pool
52
     * @param int $cashier
53
     * @param stdClass|null $deposit
54
     * @param stdClass|null $remitment
55
     *
56
     * @return stdClass
57
     */
58
    private function getSessionFigures(Pool $pool, int $cashier,
59
        ?stdClass $deposit, ?stdClass $remitment): stdClass
60
    {
61
        $figures = $this->makeFigures(0);
62
        $figures->cashier->start = $cashier;
63
        $figures->cashier->recv = $cashier;
64
65
        $depositCount = $deposit?->count ?? 0;
66
        $depositAmount = $deposit?->amount ?? 0;
67
68
        $figures->deposit->amount += $depositAmount;
69
        $figures->cashier->recv += $depositAmount;
70
        $figures->deposit->count = $depositCount;
71
72
        $sessionCount = $pool->sessions->count();
73
        $remitmentCount = $remitment?->count ?? 0;
74
        $remitmentAmount = $pool->deposit_fixed ?
75
            $pool->def->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('v_deposits')
122
            ->select('subscriptions.pool_id', 'v_deposits.session_id',
123
                DB::raw('count(*) as count'), DB::raw('sum(v_deposits.amount) as amount'))
124
            ->join('sessions', 'v_deposits.session_id', '=', 'sessions.id')
125
            ->join('receivables', 'receivables.id', '=', 'v_deposits.receivable_id')
126
            ->join('subscriptions', 'receivables.subscription_id', '=', 'subscriptions.id')
127
            ->whereIn('subscriptions.pool_id', $poolIds)
128
            ->where('sessions.round_id', $round->id)
129
            ->groupBy(['subscriptions.pool_id', 'v_deposits.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
            ->where('paid', true)
176
            ->whereIn('subscriptions.pool_id', $poolIds)
177
            ->where('sessions.round_id', $round->id)
178
            ->groupBy(['subscriptions.pool_id', 'auctions.session_id'])
179
            ->get()
180
            // Group the data by pool id and session id.
181
            ->groupBy('pool_id')
182
            ->map(fn($poolAuctions) => $poolAuctions->groupBy('session_id')
183
                ->map(fn($array) => $array->first()));
184
    }
185
186
    /**
187
     * @param Pool $pool
188
     *
189
     * @return array
190
     */
191
    private function getPoolFigures(Pool $pool): array
192
    {
193
        $sessions = $this->poolService->getActiveSessions($pool);
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.guild', 'sessions'])
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 Collection $figures
238
     *
239
     * @return array
240
     */
241
    public function getPoolsBalance(Collection $figures): array
242
    {
243
        $pools = [];
244
        foreach($figures as $poolData)
245
        {
246
            foreach($poolData['figures']->collected as $sessionId => $collected)
247
            {
248
                $pools[$sessionId] = ($pools[$sessionId] ?? 0) + $collected->cashier->end;
249
            }
250
        }
251
        return $pools;
252
    }
253
254
    /**
255
     * Get the funds.
256
     *
257
     * @param Round $round
258
     *
259
     * @return Collection
260
     */
261
    public function getFunds(Round $round): Collection
262
    {
263
        return Fund::ofRound($round)->get()
264
            ->filter(fn($fund) => $fund->start_amount > 0 ||
265
                $fund->end_amount > 0 || $fund->profit_amount > 0);
266
    }
267
268
    /**
269
     * @param Pool $pool
270
     * @param Session $session
271
     *
272
     * @return int
273
     */
274
    public function getSessionRemitmentCount(Pool $pool, Session $session): int
275
    {
276
        if(!$pool->remit_planned)
277
        {
278
            return -1;
279
        }
280
        if(!$pool->deposit_fixed)
281
        {
282
            return 1;
283
        }
284
285
        $sessions = $this->poolService->getActiveSessions($pool);
286
        $position = $sessions->filter(
287
            fn($_session) => $_session->day_date->lt($session->day_date)
288
        )->count();
289
290
        return $this->getRemitmentCount($sessions->count(),
291
            $pool->subscriptions()->count(), $position);
292
    }
293
}
294