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

PaymentPeriods   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 1
dl 0
loc 174
ccs 54
cts 54
cp 1
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A add() 0 9 2
A getRatePerPeriod() 0 20 4
A getNumberOfPeriods() 0 21 4
A getExactPeriodsLength() 0 12 2
A getAveragePeriodsLength() 0 7 1
A getPeriods() 0 4 1
A getNoOfPeriods() 0 4 1
A getCurrentPeriod() 0 12 4
A getTotalPeriods() 0 12 4
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
    /**
75
     * @param PeriodInterface $period
76
     * @param int $calculationType
77
     * @param int $calculateFor
78
     * @return float
79
     * @throws \Exception
80
     */
81 12
    public function getNumberOfPeriods(
82
        PeriodInterface $period,
83
        int $calculationType = self::CALCULATION_MODE_AVERAGE,
84
        int $calculateFor = self::CALCULATE_FOR_PAYMENT
85
    ): float {
86
        switch ($calculationType) {
87 12
            case self::CALCULATION_MODE_EXACT:
88 10
            case self::CALCULATION_MODE_EXACT_INTEREST:
89 8
            case self::CALCULATION_MODE_AVERAGE:
90 11
                $totalPeriods = $this->getTotalPeriods($calculationType, $calculateFor);
91 11
                break;
92
            default:
93 1
                throw new \Exception('Calculation type not implemented');
94
        }
95
96 11
        $currentPeriod = $this->getCurrentPeriod($period, $calculationType, $calculateFor);
97
98 11
        $numberOfPeriods = $totalPeriods / $currentPeriod;
99
100 11
        return $numberOfPeriods;
101
    }
102
103
    /**
104
     * @return int
105
     */
106 10
    public function getExactPeriodsLength()
107
    {
108 10
        $followingPeriods = $this->getPeriods();
109 10
        $remainingPeriodsLength = 0;
110
111
112 10
        foreach ($followingPeriods as $period) {
113 10
            $remainingPeriodsLength += $period->getLength();
114
        }
115
116 10
        return $remainingPeriodsLength;
117
    }
118
119
    /**
120
     * @return int
121
     */
122 10
    public function getAveragePeriodsLength()
123
    {
124 10
        $followingPeriods = $this->getPeriods();
125 10
        $remainingPeriodsLength = $this->averagePeriod * count($followingPeriods);
126
127 10
        return $remainingPeriodsLength;
128
    }
129
130
    /**
131
     * @return array
132
     */
133 19
    public function getPeriods(): array
134
    {
135 19
        return $this->periods;
136
    }
137
138
    /**
139
     * @return int
140
     */
141 16
    public function getNoOfPeriods(): int
142
    {
143 16
        return count($this->periods);
144
    }
145
146
    /**
147
     * @param PeriodInterface $period
148
     * @param int $calculationType
149
     * @param int $calculateFor
150
     * @return int
151
     */
152 17
    private function getCurrentPeriod(PeriodInterface $period, int $calculationType, int $calculateFor)
153
    {
154 17
        if ($calculationType == self::CALCULATION_MODE_EXACT) {
155 9
            return $period->getLength();
156
        }
157
158 13
        if ($calculateFor == self::CALCULATE_FOR_INTEREST && $calculationType == self::CALCULATION_MODE_EXACT_INTEREST) {
159 4
            return $period->getLength();
160
        }
161
162 11
        return $this->averagePeriod;
163
    }
164
165
    /**
166
     * @param int $calculationType
167
     * @param int $calculateFor
168
     * @return int
169
     */
170 11
    private function getTotalPeriods(int $calculationType, int $calculateFor)
171
    {
172 11
        if ($calculationType == self::CALCULATION_MODE_EXACT) {
173 7
            return $this->getExactPeriodsLength();
174
        }
175
176 9
        if ($calculateFor == self::CALCULATE_FOR_INTEREST && $calculationType == self::CALCULATION_MODE_EXACT_INTEREST) {
177 1
            return $this->getExactPeriodsLength();
178
        }
179
180 8
        return $this->getAveragePeriodsLength();
181
    }
182
183
184
}
185