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

ReportTrait::getActiveSessions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 8
rs 10
c 1
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
        $with['payables'] = function($query) use($pool) {
88
            // Keep only the subscriptions of the current pool.
89
            $query->join('subscriptions', 'payables.subscription_id', '=', 'subscriptions.id')
90
                ->where('subscriptions.pool_id', $pool->id);
91
        };
92
        return $this->poolService->getActiveSessions($pool)->load($with);
93
    }
94
95
    /**
96
     * @param Pool $pool
97
     * @param Collection $sessions
98
     *
99
     * @return array
100
     */
101
    private function getExpectedFigures(Pool $pool, Collection $sessions): array
102
    {
103
        $depositCount = $pool->subscriptions()->count();
104
        $sessionCount = $sessions->count();
105
        $subscriptionCount = $depositCount;
106
        $depositAmount = $pool->amount * $depositCount;
107
        $remitmentAmount = $pool->amount * $sessionCount;
108
109
        $position = 0;
110
        $cashier = 0;
111
        $expectedFigures = [];
112
        foreach($sessions as $session)
113
        {
114
            $figures = $this->makeFigures(0);
115
            $figures->cashier->start = $cashier;
116
            $figures->cashier->recv = $cashier + $depositAmount;
117
            $figures->deposit->count = $depositCount;
118
            $figures->deposit->amount = $depositAmount;
119
            $figures->remitment->count = !$pool->deposit_fixed ? 1 :
120
                $this->getRemitmentCount($sessionCount, $subscriptionCount, $position++);
121
            $figures->remitment->amount = $remitmentAmount * $figures->remitment->count;
122
            $figures->cashier->end = $cashier + $depositAmount - $figures->remitment->amount;
123
            $cashier = $figures->cashier->end;
124
125
            $expectedFigures[$session->id] = $figures;
126
        }
127
        return $expectedFigures;
128
    }
129
}
130