Passed
Pull Request — master (#5)
by Kauri
02:48
created

PaymentPeriods::getNumberOfPeriods()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 31
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 19
cts 19
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 26
nc 5
nop 3
crap 5
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Kauri\Loan;
6
7
/**
8
 * Class PaymentPeriods
9
 * @package Kauri\Loan
10
 */
11
class PaymentPeriods implements PaymentPeriodsInterface
12
{
13
    /**
14
     * @var array
15
     */
16
    private $periods = array();
17
    /**
18
     * @var int
19
     */
20
    private $averagePeriod;
21
22
    /**
23
     * PaymentPeriods constructor.
24
     * @param int $averagePeriod
25
     */
26 21
    public function __construct(int $averagePeriod)
27
    {
28 21
        $this->averagePeriod = $averagePeriod;
29 21
    }
30
31
    /**
32
     * @param PeriodInterface $period
33
     * @param int|null $sequenceNo
34
     */
35 19
    public function add(PeriodInterface $period, int $sequenceNo = null): void
36
    {
37 19
        if (is_null($sequenceNo)) {
38 16
            $sequenceNo = $this->getNoOfPeriods() + 1;
39
        }
40
41 19
        $period->setSequenceNo($sequenceNo);
42 19
        $this->periods[$sequenceNo] = $period;
43 19
    }
44
45
    /**
46
     * @param PeriodInterface $period
47
     * @param float $yearlyInterestRate
48
     * @param int $calculationType
49
     * @param int $calculateFor
50
     * @return float
51
     * @throws \Exception
52
     */
53 9
    public function getRatePerPeriod(
54
        PeriodInterface $period,
55
        float $yearlyInterestRate,
56
        int $calculationType = self::CALCULATION_MODE_AVERAGE,
57
        int $calculateFor = self::CALCULATE_FOR_INTEREST
58
    ): float {
59
        switch ($calculationType) {
60 9
            case self::CALCULATION_MODE_EXACT:
61 7
            case self::CALCULATION_MODE_EXACT_INTEREST:
62 5
            case self::CALCULATION_MODE_AVERAGE:
63 8
                $currentPeriod = $this->getCurrentPeriod($period, $calculationType, $calculateFor);
64 8
                break;
65
            default:
66 1
                throw new \Exception('Calculation type not implemented');
67
        }
68
69 8
        $ratePerPeriod = $yearlyInterestRate / 360 * $currentPeriod;
70
71 8
        return $ratePerPeriod;
72
    }
73
74 8
    private function getCurrentPeriod($period, int $calculationType, int $calculateFor)
75
    {
76 8
        if ($calculationType == self::CALCULATION_MODE_EXACT) {
77 4
            return $period->getLength();
78
        }
79
80 6
        if ($calculateFor == self::CALCULATE_FOR_INTEREST && $calculationType == self::CALCULATION_MODE_EXACT_INTEREST) {
81 3
            return $period->getLength();
82
        }
83
84 5
        return $this->averagePeriod;
85
    }
86
87
    /**
88
     * @param PeriodInterface $period
89
     * @param int $calculationType
90
     * @param int $calculateFor
91
     * @return float
92
     * @throws \Exception
93
     */
94 12
    public function getNumberOfPeriods(
95
        PeriodInterface $period,
96
        int $calculationType = self::CALCULATION_MODE_AVERAGE,
97
        int $calculateFor = self::CALCULATE_FOR_PAYMENT
98
    ): float {
99
        switch ($calculationType) {
100 12
            case self::CALCULATION_MODE_EXACT:
101 7
                $currentPeriod = $period->getLength();
102 7
                $totalPeriods = $this->getExactPeriodsLength();
103 7
                break;
104 10
            case self::CALCULATION_MODE_EXACT_INTEREST:
105 7
                if ($calculateFor == self::CALCULATE_FOR_PAYMENT) {
106 6
                    $currentPeriod = $this->averagePeriod;
107 6
                    $totalPeriods = $this->getAveragePeriodsLength();
108
                } else {
109 1
                    $currentPeriod = $period->getLength();
110 1
                    $totalPeriods = $this->getExactPeriodsLength();
111
                }
112 7
                break;
113 8
            case self::CALCULATION_MODE_AVERAGE:
114 7
                $currentPeriod = $this->averagePeriod;
115 7
                $totalPeriods = $this->getAveragePeriodsLength();
116 7
                break;
117
            default:
118 1
                throw new \Exception('Calculation type not implemented');
119
        }
120
121 11
        $numberOfPeriods = $totalPeriods / $currentPeriod;
122
123 11
        return $numberOfPeriods;
124
    }
125
126
    /**
127
     * @return int
128
     */
129 10
    public function getExactPeriodsLength()
130
    {
131 10
        $followingPeriods = $this->getPeriods();
132 10
        $remainingPeriodsLength = 0;
133
134
135 10
        foreach ($followingPeriods as $period) {
136 10
            $remainingPeriodsLength += $period->getLength();
137
        }
138
139 10
        return $remainingPeriodsLength;
140
    }
141
142
    /**
143
     * @return int
144
     */
145 10
    public function getAveragePeriodsLength()
146
    {
147 10
        $followingPeriods = $this->getPeriods();
148 10
        $remainingPeriodsLength = $this->averagePeriod * count($followingPeriods);
149
150 10
        return $remainingPeriodsLength;
151
    }
152
153
    /**
154
     * @return array
155
     */
156 19
    public function getPeriods(): array
157
    {
158 19
        return $this->periods;
159
    }
160
161
    /**
162
     * @return int
163
     */
164 16
    public function getNoOfPeriods(): int
165
    {
166 16
        return count($this->periods);
167
    }
168
169
170
}
171