ReportTrait::makeFigures()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 1
dl 0
loc 18
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Traits;
4
5
use Illuminate\Support\Collection;
6
use Siak\Tontine\Model\Pool;
7
use Siak\Tontine\Service\Planning\PoolService;
8
use stdClass;
9
10
use function floor;
11
use function gmp_gcd;
12
13
trait ReportTrait
14
{
15
    /**
16
     * @var PoolService
17
     */
18
    protected PoolService $poolService;
19
20
    /**
21
     * @param int $defaultValue
22
     *
23
     * @return stdClass
24
     */
25
    private function makeFigures(int $defaultValue = 0): stdClass
26
    {
27
        $figures = new stdClass();
28
29
        $figures->cashier = new stdClass();
30
        $figures->cashier->start = $defaultValue;
31
        $figures->cashier->recv = $defaultValue;
32
        $figures->cashier->end = $defaultValue;
33
34
        $figures->deposit = new stdClass();
35
        $figures->deposit->count = $defaultValue;
36
        $figures->deposit->amount = $defaultValue;
37
38
        $figures->remitment = new stdClass();
39
        $figures->remitment->count = $defaultValue;
40
        $figures->remitment->amount = $defaultValue;
41
42
        return $figures;
43
    }
44
45
    /**
46
     * Get the number of subscribers to remit a pool to at a given session
47
     *
48
     * @param int $sessionCount
49
     * @param int $subscriptionCount
50
     * @param int $sessionPosition
51
     *
52
     * @return int
53
     */
54
    public function getRemitmentCount(int $sessionCount, int $subscriptionCount, int $sessionPosition): int
55
    {
56
        if($sessionCount === 0 || $subscriptionCount === 0)
57
        {
58
            return 0;
59
        }
60
61
        // Greatest common divisor
62
        $gcd = (int)gmp_gcd($sessionCount, $subscriptionCount);
63
        $sessionsInLoop = (int)($sessionCount / $gcd);
64
        $positionInLoop = $sessionPosition % $sessionsInLoop;
65
        $subscriptionsInLoop = (int)($subscriptionCount / $gcd);
66
        $extraSubscriptionsInLoop = $subscriptionsInLoop % $sessionsInLoop;
67
68
        // There's is an extra remitment when the modulo decreases compared to the previous session.
69
        $prevModulo = ($positionInLoop * $extraSubscriptionsInLoop) % $sessionsInLoop;
70
        if($prevModulo > ($prevModulo + $extraSubscriptionsInLoop) % $sessionsInLoop)
71
        {
72
            return (int)floor($subscriptionCount / $sessionCount) + 1;
73
        }
74
        return (int)floor($subscriptionCount / $sessionCount);
75
    }
76
77
    /**
78
     * Get the payables of a given pool.
79
     *
80
     * @param Pool $pool
81
     * @param array $with
82
     *
83
     * @return Collection
84
     */
85
    private function getActiveSessions(Pool $pool, array $with = []): Collection
86
    {
87
        // Keep only the subscriptions of the current pool.
88
        $with['payables'] = fn($qp) => $qp
89
            ->whereHas('subscription', fn($qs) => $qs->where('pool_id', $pool->id));
90
        return $this->poolService->getActiveSessions($pool)->load($with);
91
    }
92
93
    /**
94
     * @param Pool $pool
95
     * @param Collection $sessions
96
     *
97
     * @return array
98
     */
99
    private function getExpectedFigures(Pool $pool, Collection $sessions): array
100
    {
101
        $depositCount = $pool->subscriptions()->count();
102
        $sessionCount = $sessions->count();
103
        $subscriptionCount = $depositCount;
104
        $depositAmount = $pool->amount * $depositCount;
105
        $remitmentAmount = $pool->amount * $sessionCount;
106
107
        $position = 0;
108
        $cashier = 0;
109
        $expectedFigures = [];
110
        foreach($sessions as $session)
111
        {
112
            $figures = $this->makeFigures(0);
113
            $figures->cashier->start = $cashier;
114
            $figures->cashier->recv = $cashier + $depositAmount;
115
            $figures->deposit->count = $depositCount;
116
            $figures->deposit->amount = $depositAmount;
117
            $figures->remitment->count = !$pool->deposit_fixed ? 1 :
118
                $this->getRemitmentCount($sessionCount, $subscriptionCount, $position++);
119
            $figures->remitment->amount = $remitmentAmount * $figures->remitment->count;
120
            $figures->cashier->end = $cashier + $depositAmount - $figures->remitment->amount;
121
            $cashier = $figures->cashier->end;
122
123
            $expectedFigures[$session->id] = $figures;
124
        }
125
        return $expectedFigures;
126
    }
127
}
128