Failed Conditions
Pull Request — master (#8)
by Kauri
03:50
created

PaymentsCalculator   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 3
dl 0
loc 123
ccs 33
cts 33
cp 1
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A calculatePayments() 0 63 3
A getPeriodInterestRate() 0 4 1
A getPeriodLengths() 0 11 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Kauri\Loan;
6
7
8
class PaymentsCalculator implements PaymentsCalculatorInterface
9
{
10
    /**
11
     * @var PaymentAmountCalculatorInterface
12
     */
13
    private $paymentAmountCalculator;
14
    /**
15
     * @var InterestAmountCalculatorInterface
16
     */
17
    private $interestAmountCalculator;
18
19
    /**
20
     * PaymentsCalculator constructor.
21
     * @param PaymentAmountCalculatorInterface $paymentAmountCalculator
22
     * @param InterestAmountCalculatorInterface $interestAmountCalculator
23
     */
24 3
    public function __construct(
25
        PaymentAmountCalculatorInterface $paymentAmountCalculator,
26
        InterestAmountCalculatorInterface $interestAmountCalculator
27
    ) {
28 3
        $this->paymentAmountCalculator = $paymentAmountCalculator;
29 3
        $this->interestAmountCalculator = $interestAmountCalculator;
30 3
    }
31
32
    /**
33
     * @param PaymentPeriodsInterface $paymentPeriods
34
     * @param float $amountOfPrincipal
35
     * @param float $yearlyInterestRate
36
     * @param int $calculationMode
37
     * @param float $futureValue
38
     * @return array
39
     */
40 3
    public function calculatePayments(
41
        PaymentPeriodsInterface $paymentPeriods,
42
        float $amountOfPrincipal,
43
        float $yearlyInterestRate,
44
        int $calculationMode,
45
        float $futureValue
46
    ): array {
47 3
        $payments = array();
48
49 3
        $periodLengths = $this->getPeriodLengths($paymentPeriods, $calculationMode);
50 3
        $paymentAmounts = $this->paymentAmountCalculator->getPaymentAmounts($periodLengths, $amountOfPrincipal,
51 3
            $yearlyInterestRate, 0);
52
53 3
        $principalLeft = $amountOfPrincipal;
54
55 3
        foreach ($paymentPeriods->getPeriods() as $period) {
56
            /**
57
             * Get payment amount
58
             */
59 3
            $paymentAmount = round($paymentAmounts[$period->getSequenceNo()], 2);
60
61
            /**
62
             * Get interest rate for period
63
             */
64 3
            $ratePerPeriod = $this->getPeriodInterestRate($yearlyInterestRate, $period->getLength($calculationMode));
65
66
            /**
67
             * Calculate interest part
68
             */
69 3
            $interest = round($this->interestAmountCalculator->getInterestAmount($principalLeft, $ratePerPeriod), 2);
70
71
            /**
72
             * Calculate principal part
73
             */
74 3
            if ($period->getSequenceNo() < $paymentPeriods->getNoOfPeriods()) {
75 3
                $principal = $paymentAmount - $interest;
76
            } else {
77 3
                $principal = $principalLeft;
78
            }
79
80
            /**
81
             * Calculate balance left
82
             */
83 3
            $principalLeft = $principalLeft - $principal;
84
85
            /**
86
             * Compose payment data
87
             */
88
            $paymentData = array(
89 3
                'sequence_no' => $period->getSequenceNo(),
90 3
                'payment' => $interest + $principal,
91 3
                'principal' => $principal,
92 3
                'interest' => $interest,
93 3
                'principal_left' => $principalLeft,
94 3
                'period' => $period
95
            );
96
97 3
            $payments[$period->getSequenceNo()] = $paymentData;
98
        }
99
100 3
        return $payments;
101
102
    }
103
104
    /**
105
     * @param float $yearlyInterestRate
106
     * @param float $periodLength
107
     * @return float
108
     */
109 3
    private function getPeriodInterestRate(float $yearlyInterestRate, float $periodLength): float
110
    {
111 3
        return $yearlyInterestRate / 360 * $periodLength;
112
    }
113
114
    /**
115
     * @param PaymentPeriodsInterface $paymentPeriods
116
     * @param int $lengthMode
117
     * @return array
118
     */
119 3
    private function getPeriodLengths(PaymentPeriodsInterface $paymentPeriods, int $lengthMode): array
120
    {
121 3
        $lengths = array();
122
123
        /** @var PeriodInterface $period */
124 3
        foreach ($paymentPeriods->getPeriods() as $period) {
125 3
            $lengths[$period->getSequenceNo()] = $period->getLength($lengthMode);
126
        }
127
128 3
        return $lengths;
129
    }
130
}
131