Failed Conditions
Pull Request — master (#5)
by Kauri
02:58
created

PaymentPeriods::getRatePerPeriod()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 28
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 15
cts 15
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 23
nc 5
nop 4
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 4
                $currentPeriod = $period->getLength();
62 4
                break;
63 7
            case self::CALCULATION_MODE_EXACT_INTEREST:
64 4
                if ($calculateFor == self::CALCULATE_FOR_INTEREST) {
65 3
                    $currentPeriod = $period->getLength();
66
                } else {
67 1
                    $currentPeriod = $this->averagePeriod;
68
                }
69 4
                break;
70 5
            case self::CALCULATION_MODE_AVERAGE:
71 4
                $currentPeriod = $this->averagePeriod;
72 4
                break;
73
            default:
74 1
                throw new \Exception('Calculation type not implemented');
75
        }
76
77 8
        $ratePerPeriod = $yearlyInterestRate / 360 * $currentPeriod;
78
79 8
        return $ratePerPeriod;
80
    }
81
82
    /**
83
     * @param PeriodInterface $period
84
     * @param int $calculationType
85
     * @param int $calculateFor
86
     * @return float
87
     * @throws \Exception
88
     */
89 12
    public function getNumberOfPeriods(
90
        PeriodInterface $period,
91
        int $calculationType = self::CALCULATION_MODE_AVERAGE,
92
        int $calculateFor = self::CALCULATE_FOR_PAYMENT
93
    ): float {
94
        switch ($calculationType) {
95 12
            case self::CALCULATION_MODE_EXACT:
96 7
                $currentPeriod = $period->getLength();
97 7
                $totalPeriods = $this->getExactPeriodsLength();
98 7
                break;
99 10
            case self::CALCULATION_MODE_EXACT_INTEREST:
100 7
                if ($calculateFor == self::CALCULATE_FOR_PAYMENT) {
101 6
                    $currentPeriod = $this->averagePeriod;
102 6
                    $totalPeriods = $this->getAveragePeriodsLength();
103
                } else {
104 1
                    $currentPeriod = $period->getLength();
105 1
                    $totalPeriods = $this->getExactPeriodsLength();
106
                }
107 7
                break;
108 8
            case self::CALCULATION_MODE_AVERAGE:
109 7
                $currentPeriod = $this->averagePeriod;
110 7
                $totalPeriods = $this->getAveragePeriodsLength();
111 7
                break;
112
            default:
113 1
                throw new \Exception('Calculation type not implemented');
114
        }
115
116 11
        $numberOfPeriods = $totalPeriods / $currentPeriod;
117
118 11
        return $numberOfPeriods;
119
    }
120
121
    /**
122
     * @return int
123
     */
124 10
    public function getExactPeriodsLength()
125
    {
126 10
        $followingPeriods = $this->getPeriods();
127 10
        $remainingPeriodsLength = 0;
128
129
130 10
        foreach ($followingPeriods as $period) {
131 10
            $remainingPeriodsLength += $period->getLength();
132
        }
133
134 10
        return $remainingPeriodsLength;
135
    }
136
137
    /**
138
     * @return int
139
     */
140 10
    public function getAveragePeriodsLength()
141
    {
142 10
        $followingPeriods = $this->getPeriods();
143 10
        $remainingPeriodsLength = $this->averagePeriod * count($followingPeriods);
144
145 10
        return $remainingPeriodsLength;
146
    }
147
148
    /**
149
     * @return array
150
     */
151 19
    public function getPeriods(): array
152
    {
153 19
        return $this->periods;
154
    }
155
156
    /**
157
     * @return int
158
     */
159 16
    public function getNoOfPeriods(): int
160
    {
161 16
        return count($this->periods);
162
    }
163
164
165
}
166