Skip to content

Commit f24123c

Browse files
authored
Merge pull request #5 from hmrc/feature/HMA-2552-first-bonus-period-calculator
HMA-2552: Added HTS calculation for first bonus calculator
2 parents 31b1408 + 2d24898 commit f24123c

File tree

9 files changed

+582
-1
lines changed

9 files changed

+582
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ yarn-error.log
2727
/.idea/
2828
/.gradle/
2929
credentials.properties
30-
gradlew.bat
30+
gradlew.bat
31+
local.properties

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ This will returns an object of type `CalculatorResponse`. This provide headline
4646
* `endOfPeriod2Savings: Double`
4747
* `endOfPeriod2Total: Double`
4848

49+
### For existing accounts in first term
50+
```kotlin
51+
FirstBonusTermCalculator.runFirstBonusCalculator(input)
52+
```
53+
Where `input` have the following object:
54+
```
55+
regularPayment: Double, // 25.0
56+
currentBalance: Double, // 25.0
57+
paidInThisMonth: Double, // 50.0
58+
accountStartDate: YearMonthDayInput, // YearMonthDayInput(2020, 3)
59+
firstTermEndDate: YearMonthDayInput, // YearMonthDayInput(2022, 2, 28)
60+
secondTermEndDate: YearMonthDayInput, // YearMonthDayInput(2024, 2, 28)
61+
balanceMustBeMoreThanForBonus: Double // 50.0
62+
```
63+
64+
## Response
65+
This will returns an object of type `FirstBonusCalculatorResponse`.
66+
* `totalProjectedSavingsIncludingBonuses: Double`
67+
* `totalProjectedSavings: Double`
68+
* `totalProjectedBonuses: Double`
69+
* `projectedSavingsFirstBonusPeriod: Double`
70+
* `projectedFirstBonus: Double`
71+
* `projectedAdditionalSavingsFinalBonusPeriod: Double`
72+
* `projectedFinalBonus: Double`
73+
4974
## Validation
5075

5176
To validate the monthly contributions:
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2020 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package uk.gov.hmrc.helptosavecalculator
17+
18+
import uk.gov.hmrc.helptosavecalculator.models.FirstBonusInput
19+
import uk.gov.hmrc.helptosavecalculator.utils.monthsSince
20+
21+
internal class FirstBonusTermCalculation {
22+
23+
fun calculateTotalProjectedSavingsIncludeBonuses(
24+
totalProjectedSavings: Double,
25+
totalProjectedBonuses: Double
26+
): Double {
27+
return totalProjectedSavings + totalProjectedBonuses
28+
}
29+
30+
fun calculateAdditionalSavingsThisMonth(input: FirstBonusInput): Double {
31+
return if (input.regularPayment > input.paidInThisMonth) {
32+
input.regularPayment - input.paidInThisMonth
33+
} else {
34+
0.0
35+
}
36+
}
37+
38+
fun calculateTotalProjectedSavings(
39+
input: FirstBonusInput,
40+
additionalSavingsThisMonth: Double,
41+
monthsLeftInScheme: Int
42+
): Double {
43+
return input.currentBalance + additionalSavingsThisMonth + (input.regularPayment * monthsLeftInScheme)
44+
}
45+
46+
fun calculateTotalProjectedBonuses(
47+
projectedFirstBonus: Double,
48+
projectedFinalBonus: Double
49+
): Double {
50+
return projectedFirstBonus + projectedFinalBonus
51+
}
52+
53+
fun calculateProjectedSavingsFirstBonusPeriod(
54+
input: FirstBonusInput,
55+
additionalSavingsThisMonth: Double,
56+
monthsLeftInFirstTerm: Int
57+
): Double {
58+
return input.currentBalance + additionalSavingsThisMonth + (input.regularPayment * monthsLeftInFirstTerm)
59+
}
60+
61+
fun calculateHighestBalanceFirstBonusPeriod(
62+
input: FirstBonusInput,
63+
projectedSavingsFirstBonusPeriod: Double
64+
): Double {
65+
return input.balanceMustBeMoreThanForBonus.takeIf {
66+
it > projectedSavingsFirstBonusPeriod
67+
} ?: projectedSavingsFirstBonusPeriod
68+
}
69+
70+
fun calculateProjectedFirstBonus(highestBalanceFirstBonusPeriod: Double): Double {
71+
return highestBalanceFirstBonusPeriod / 2
72+
}
73+
74+
fun calculateProjectedAdditionalSavingsFinalBonusPeriod(input: FirstBonusInput): Double {
75+
return input.regularPayment * 24
76+
}
77+
78+
fun calculateProjectedFinalBonus(
79+
highestBalanceFinalBonusPeriod: Double,
80+
highestBalanceFirstBonusPeriod: Double
81+
): Double {
82+
return if (highestBalanceFinalBonusPeriod > highestBalanceFirstBonusPeriod) {
83+
(highestBalanceFinalBonusPeriod - highestBalanceFirstBonusPeriod) / 2
84+
} else {
85+
0.0
86+
}
87+
}
88+
89+
fun calculateMonthsLeftInScheme(input: FirstBonusInput): Pair<Int, Int> {
90+
val startDate = input.accountStartDate.convertToDateTime()
91+
val secondTermEndDate = input.secondTermEndDate.convertToDateTime()
92+
val firstTermEndDate = input.firstTermEndDate.convertToDateTime()
93+
val monthsLeftInScheme = startDate.monthsSince(secondTermEndDate)
94+
val monthsLeftInFirstTerm = startDate.monthsSince(firstTermEndDate)
95+
return Pair(monthsLeftInScheme, monthsLeftInFirstTerm)
96+
}
97+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2020 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package uk.gov.hmrc.helptosavecalculator
17+
18+
import uk.gov.hmrc.helptosavecalculator.exceptions.InvalidRegularPaymentException
19+
import uk.gov.hmrc.helptosavecalculator.models.FirstBonusCalculatorResponse
20+
import uk.gov.hmrc.helptosavecalculator.models.FirstBonusInput
21+
import uk.gov.hmrc.helptosavecalculator.validation.RegularPaymentValidators
22+
23+
object FirstBonusTermCalculator {
24+
25+
private val calculation = FirstBonusTermCalculation()
26+
27+
fun runFirstBonusCalculator(input: FirstBonusInput): FirstBonusCalculatorResponse {
28+
return calculateFirstBonus(input)
29+
}
30+
31+
private fun calculateFirstBonus(input: FirstBonusInput): FirstBonusCalculatorResponse {
32+
validateUserInput(input.regularPayment)
33+
34+
val (monthLeftInScheme, monthLeftInFirstTerm) = calculation.calculateMonthsLeftInScheme(input)
35+
val additionalSavingsThisMonth = calculation.calculateAdditionalSavingsThisMonth(input)
36+
val totalProjectedSavings = calculation.calculateTotalProjectedSavings(input,
37+
additionalSavingsThisMonth,
38+
monthLeftInScheme)
39+
val projectedSavingsFirstBonusPeriod = calculation.calculateProjectedSavingsFirstBonusPeriod(input,
40+
additionalSavingsThisMonth,
41+
monthLeftInFirstTerm)
42+
val highestBalanceFirstBonusPeriod = calculation.calculateHighestBalanceFirstBonusPeriod(input,
43+
projectedSavingsFirstBonusPeriod)
44+
val projectedFirstBonus = calculation.calculateProjectedFirstBonus(highestBalanceFirstBonusPeriod)
45+
val projectedAdditionalSavingsFinalBonusPeriod =
46+
calculation.calculateProjectedAdditionalSavingsFinalBonusPeriod(input)
47+
val projectedFinalBonus = calculation.calculateProjectedFinalBonus(totalProjectedSavings,
48+
highestBalanceFirstBonusPeriod)
49+
val totalProjectedBonuses = calculation.calculateTotalProjectedBonuses(projectedFirstBonus,
50+
projectedFinalBonus)
51+
val totalProjectedSavingsIncludingBonuses =
52+
calculation.calculateTotalProjectedSavingsIncludeBonuses(totalProjectedSavings,
53+
totalProjectedBonuses)
54+
55+
return FirstBonusCalculatorResponse(
56+
totalProjectedSavingsIncludingBonuses,
57+
totalProjectedSavings,
58+
totalProjectedBonuses,
59+
projectedSavingsFirstBonusPeriod,
60+
projectedFirstBonus,
61+
projectedAdditionalSavingsFinalBonusPeriod,
62+
projectedFinalBonus
63+
)
64+
}
65+
66+
private fun validateUserInput(regularPayment: Double) {
67+
if (!RegularPaymentValidators.isValidRegularPayments(regularPayment)) {
68+
throw InvalidRegularPaymentException(regularPayment)
69+
}
70+
}
71+
}

src/commonMain/kotlin/uk/gov/hmrc/helptosavecalculator/models/CalculatorResponse.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,13 @@ data class MonthlyBreakdown(
3838
) {
3939
val bonusToDate: Double = period1Bonus + period2Bonus
4040
}
41+
42+
data class FirstBonusCalculatorResponse(
43+
val totalProjectedSavingsIncludingBonuses: Double,
44+
val totalProjectedSavings: Double,
45+
val totalProjectedBonuses: Double,
46+
val projectedSavingsFirstBonusPeriod: Double,
47+
val projectedFirstBonus: Double,
48+
val projectedAdditionalSavingsFinalBonusPeriod: Double,
49+
val projectedFinalBonus: Double
50+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2020 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package uk.gov.hmrc.helptosavecalculator.models
17+
18+
data class FirstBonusInput(
19+
val regularPayment: Double,
20+
val currentBalance: Double,
21+
val paidInThisMonth: Double,
22+
val accountStartDate: YearMonthDayInput,
23+
val firstTermEndDate: YearMonthDayInput,
24+
val secondTermEndDate: YearMonthDayInput,
25+
val balanceMustBeMoreThanForBonus: Double
26+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2020 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package uk.gov.hmrc.helptosavecalculator.models
17+
18+
import com.soywiz.klock.DateTime
19+
20+
data class YearMonthDayInput(
21+
val year: Int,
22+
val month: Int,
23+
val day: Int = 1
24+
) {
25+
internal fun convertToDateTime(): DateTime {
26+
return DateTime(year, month, day)
27+
}
28+
}

0 commit comments

Comments
 (0)