Skip to content

Commit

Permalink
New variables and making everything double (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
georgeherby authored Feb 7, 2020
1 parent 0ec6859 commit 002fa35
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 110 deletions.
44 changes: 25 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,55 @@
## Status
[![Build Status](https://app.bitrise.io/app/6a0a30b884ce6131/status.svg?token=q0pKDUFK3Qfa6sXfy66vog&branch=master)](https://app.bitrise.io/app/6a0a30b884ce6131)
![LINE](https://img.shields.io/badge/line--coverage-98%25-brightgreen.svg)
![BRANCH](https://img.shields.io/badge/branch--coverage-86%25-brightgreen.svg)
![COMPLEXITY](https://img.shields.io/badge/complexity-1.48-brightgreen.svg)
![BRANCH](https://img.shields.io/badge/branch--coverage-82%25-brightgreen.svg)
![COMPLEXITY](https://img.shields.io/badge/complexity-1.64-brightgreen.svg)
[ ![Download](https://api.bintray.com/packages/hmrc/mobile-releases/tax-kalculator/images/download.svg) ](https://bintray.com/hmrc/mobile-releases/help-to-save-kalculator/_latestVersion)
## Calculate help to save bonus

### For new users
```kotlin
Calculator.run(
regularPayment = 50 // Must be between 1 and 50
regularPayment = 50.0 // Must be between 1 and 50
)
```
### For users with existing accounts
```kotlin
Calculator.run(
regularPayment = 50, // Must be between 1 and 50
currentBalance = 100,
currentFirstPeriodBonus = 50.0,
currentSecondPeriodBonus = 0.0,
accountStartDate = DateTime()
regularPayment = 50.0, // Must be between 1 and 50
currentBalance = 100.0,
currentPeriod1Bonus = 50.0,
currentPeriod2Bonus = 0.0,
accountStartDate = DateTime()
)
```

## Response
This will returns an object of type `CalculatorResponse`. This provide headline figures that are the results at the end of the scheme. However, if a monthly breakdown is needed a cumulative breakdown is provided in `monthlyBreakdown`

* `monthlyPayments: Int`
* `monthlyPayments: Double`
* `monthlyBreakdown: List<MonthlyBreakdown>`
* `monthNumber: Int`
* `balance: Int`
* `secondYearBonus: Double`
* `fourthYearBonus: Double`
* `totalBonusToDate: Double`
* `finalBalance: Int`
* `finalSecondYearBonus: Double`
* `finalFourthYearBonus: Double`
* `savingsToDate: Double`
* `period1Bonus: Double`
* `period2Bonus: Double`
* `bonusToDate: Double`
* `endOfSchemeBonus: Double`
* `endOfSchemeSavings: Double`
* `endOfSchemeTotal: Double`
* `endOfPeriod1Bonus: Double`
* `endOfPeriod1Savings: Double`
* `endOfPeriod1Total: Double`
* `endOfPeriod2Bonus: Double`
* `endOfPeriod2Savings: Double`
* `endOfPeriod2Total: Double`

## Validation

To validate the monthly contributions:
```kotlin
val isValidRegularPayments = RegularPaymentValidators.isValidRegularPayments(1000) // true
val isAboveMinimumRegularPayments = RegularPaymentValidators.isAboveMinimumRegularPayments(0) // false
val isBelowMaximumRegularPayments = RegularPaymentValidators.isBelowMaximumRegularPayments(50) // true
val isValidRegularPayments = RegularPaymentValidators.isValidRegularPayments(1000.0) // true
val isAboveMinimumRegularPayments = RegularPaymentValidators.isAboveMinimumRegularPayments(0.0) // false
val isBelowMaximumRegularPayments = RegularPaymentValidators.isBelowMaximumRegularPayments(50.0) // true
```

## Installation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import uk.gov.hmrc.helptosavecalculator.validation.RegularPaymentValidators

object Calculator : HtSSchemeConfig() {

fun run(regularPayment: Int): CalculatorResponse {
fun run(regularPayment: Double): CalculatorResponse {
return calculate(regularPayment)
}

fun run(
regularPayment: Int,
currentBalance: Int,
regularPayment: Double,
currentBalance: Double,
currentFirstPeriodBonus: Double,
currentSecondPeriodBonus: Double,
accountStartDate: DateTime
Expand All @@ -41,48 +41,58 @@ object Calculator : HtSSchemeConfig() {
}

private fun calculate(
regularPayment: Int,
currentBalance: Int? = null,
currentFirstPeriodBonus: Double? = null,
currentSecondPeriodBonus: Double? = null,
regularPayment: Double,
currentBalance: Double? = null,
currentPeriod1Bonus: Double? = null,
currentPeriod2Bonus: Double? = null,
accountStartDate: DateTime? = null
): CalculatorResponse {
val listOfMonths: MutableList<MonthlyBreakdown> = mutableListOf()
var currentMonth: Int = accountStartDate?.monthsSince()?.plus(1) ?: 1
var balance: Int = currentBalance ?: 0
var endOfFirstPeriodBonus: Double = currentFirstPeriodBonus ?: 0.0
var endOfSecondPeriodBonus: Double = currentSecondPeriodBonus ?: 0.0
var endOfSchemeSavings: Double = currentBalance ?: 0.0
var endOfPeriod1Savings: Double = currentBalance ?: 0.0
var endOfPeriod2Savings: Double = currentBalance ?: 0.0
var endOfPeriod1Bonus: Double = currentPeriod1Bonus ?: 0.0
var endOfPeriod2Bonus: Double = currentPeriod2Bonus ?: 0.0

validateUserInput(regularPayment)

while (currentMonth <= endOfSecondBonusPeriod) {
balance += regularPayment
endOfSchemeSavings += regularPayment
when (currentMonth) {
in startOfFirstBonusPeriod..endOfFirstBonusPeriod -> {
endOfFirstPeriodBonus += (regularPayment / 2)
endOfPeriod1Bonus += (regularPayment / 2)
if (currentMonth == endOfFirstBonusPeriod) {
endOfPeriod1Savings = endOfSchemeSavings
}
}
in startOfSecondBonusPeriod..endOfSecondBonusPeriod -> {
endOfSecondPeriodBonus += (regularPayment / 2)
endOfPeriod2Bonus += (regularPayment / 2)
if (currentMonth == endOfSecondBonusPeriod) {
endOfPeriod2Savings = endOfSchemeSavings - endOfPeriod1Savings
}
}
else -> throw IllegalStateException("The scheme has exceeded 1 to 48 months")
}
listOfMonths.add(
MonthlyBreakdown(
monthNumber = currentMonth,
balance = balance,
secondYearBonus = endOfFirstPeriodBonus,
fourthYearBonus = endOfSecondPeriodBonus))
savingsToDate = endOfSchemeSavings,
period1Bonus = endOfPeriod1Bonus,
period2Bonus = endOfPeriod2Bonus))
currentMonth++
}
return CalculatorResponse(
monthlyPayments = regularPayment,
finalBalance = balance,
finalSecondYearBonus = endOfFirstPeriodBonus,
finalFourthYearBonus = endOfSecondPeriodBonus,
monthlyBreakdown = listOfMonths)
monthlyBreakdown = listOfMonths,
endOfSchemeSavings = endOfSchemeSavings,
endOfPeriod1Bonus = endOfPeriod1Bonus,
endOfPeriod1Savings = endOfPeriod1Savings,
endOfPeriod2Bonus = endOfPeriod2Bonus,
endOfPeriod2Savings = endOfPeriod2Savings)
}

private fun validateUserInput(regularPayment: Int) {
private fun validateUserInput(regularPayment: Double) {
if (!RegularPaymentValidators.isValidRegularPayments(regularPayment)) {
throw InvalidRegularPaymentException(regularPayment)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
*/
package uk.gov.hmrc.helptosavecalculator.exceptions

class InvalidRegularPaymentException(regularPayment: Int) :
class InvalidRegularPaymentException(regularPayment: Double) :
Exception("Regular payment must be between 1 and 50. You provided $regularPayment")
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,25 @@
package uk.gov.hmrc.helptosavecalculator.models

data class CalculatorResponse(
val monthlyPayments: Int,
val monthlyPayments: Double,
val monthlyBreakdown: List<MonthlyBreakdown>,
val finalBalance: Int,
val finalSecondYearBonus: Double,
val finalFourthYearBonus: Double
val endOfSchemeSavings: Double,
val endOfPeriod1Bonus: Double,
val endOfPeriod1Savings: Double,
val endOfPeriod2Bonus: Double,
val endOfPeriod2Savings: Double
) {
val finalTotalBonus: Double = finalSecondYearBonus + finalFourthYearBonus
}
val endOfSchemeBonus: Double = endOfPeriod1Bonus + endOfPeriod2Bonus
val endOfSchemeTotal: Double = endOfSchemeSavings + endOfSchemeBonus
val endOfPeriod1Total: Double = endOfPeriod1Savings + endOfPeriod1Bonus
val endOfPeriod2Total: Double = endOfPeriod2Savings + endOfPeriod2Bonus
}

data class MonthlyBreakdown(
val monthNumber: Int,
val balance: Int,
val secondYearBonus: Double,
val fourthYearBonus: Double
val savingsToDate: Double,
val period1Bonus: Double,
val period2Bonus: Double
) {
val totalBonusToDate: Double = secondYearBonus + fourthYearBonus
val bonusToDate: Double = period1Bonus + period2Bonus
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ package uk.gov.hmrc.helptosavecalculator.validation

object RegularPaymentValidators {

fun isValidRegularPayments(payment: Int) = isBelowMaximumRegularPayments(payment) && isAboveMinimumRegularPayments(
payment)
fun isValidRegularPayments(payment: Double) =
isBelowMaximumRegularPayments(payment) && isAboveMinimumRegularPayments(
payment)

fun isAboveMinimumRegularPayments(payment: Int) = payment >= 1
fun isAboveMinimumRegularPayments(payment: Double) = payment >= 1.0

fun isBelowMaximumRegularPayments(payment: Int) = payment <= 50
fun isBelowMaximumRegularPayments(payment: Double) = payment <= 50.0
}
97 changes: 58 additions & 39 deletions src/commonTest/kotlin/uk/gov/hmrc/CalculatorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,94 +28,113 @@ class CalculatorTest {
@Test
fun `Gives list of 48 months with breakdown`() {
assertEquals(
MonthlyBreakdown(monthNumber = 1, balance = 50, secondYearBonus = 25.0, fourthYearBonus = 0.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[0])
assertEquals(25.0, Calculator.run(regularPayment = 50).monthlyBreakdown[0].totalBonusToDate)
MonthlyBreakdown(monthNumber = 1, savingsToDate = 50.0, period1Bonus = 25.0, period2Bonus = 0.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[0])
assertEquals(25.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[0].bonusToDate)

assertEquals(
MonthlyBreakdown(monthNumber = 2, balance = 100, secondYearBonus = 50.0, fourthYearBonus = 0.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[1])
assertEquals(50.0, Calculator.run(regularPayment = 50).monthlyBreakdown[1].totalBonusToDate)
MonthlyBreakdown(monthNumber = 2, savingsToDate = 100.0, period1Bonus = 50.0, period2Bonus = 0.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[1])
assertEquals(50.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[1].bonusToDate)

assertEquals(
MonthlyBreakdown(monthNumber = 3, balance = 150, secondYearBonus = 75.0, fourthYearBonus = 0.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[2])
assertEquals(50.0, Calculator.run(regularPayment = 50).monthlyBreakdown[1].totalBonusToDate)
MonthlyBreakdown(monthNumber = 3, savingsToDate = 150.0, period1Bonus = 75.0, period2Bonus = 0.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[2])
assertEquals(50.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[1].bonusToDate)

assertEquals(
MonthlyBreakdown(monthNumber = 24, balance = 1200, secondYearBonus = 600.0, fourthYearBonus = 0.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[23])
assertEquals(600.0, Calculator.run(regularPayment = 50).monthlyBreakdown[23].totalBonusToDate)
MonthlyBreakdown(monthNumber = 24, savingsToDate = 1200.0, period1Bonus = 600.0, period2Bonus = 0.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[23])
assertEquals(600.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[23].bonusToDate)

assertEquals(
MonthlyBreakdown(
monthNumber = 25, balance = 1250, secondYearBonus = 600.0, fourthYearBonus = 25.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[24])
assertEquals(625.0, Calculator.run(regularPayment = 50).monthlyBreakdown[24].totalBonusToDate)
monthNumber = 25, savingsToDate = 1250.0, period1Bonus = 600.0, period2Bonus = 25.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[24])
assertEquals(625.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[24].bonusToDate)

assertEquals(
MonthlyBreakdown(
monthNumber = 48, balance = 2400, secondYearBonus = 600.0, fourthYearBonus = 600.0),
Calculator.run(regularPayment = 50).monthlyBreakdown[47])
assertEquals(1200.0, Calculator.run(regularPayment = 50).monthlyBreakdown[47].totalBonusToDate)
monthNumber = 48, savingsToDate = 2400.0, period1Bonus = 600.0, period2Bonus = 600.0),
Calculator.run(regularPayment = 50.0).monthlyBreakdown[47])
assertEquals(1200.0, Calculator.run(regularPayment = 50.0).monthlyBreakdown[47].bonusToDate)
}

@Test
fun `Throw Exception when regular payment is below 1`() {
assertFailsWith<InvalidRegularPaymentException> {
Calculator.run(regularPayment = 0)
Calculator.run(regularPayment = 0.0)
}
}

@Test
fun `Throw Exception when regular payment is above 50`() {
assertFailsWith<InvalidRegularPaymentException> {
Calculator.run(regularPayment = 51)
Calculator.run(regularPayment = 51.0)
}
}

@Test
fun `Month breakdown if they have only saved in the first 2 months`() {
fun `Month breakdown if they have saved in the first 2 months`() {
val calculator = Calculator.run(
regularPayment = 50,
currentBalance = 100,
regularPayment = 50.0,
currentBalance = 100.0,
currentFirstPeriodBonus = 50.0,
currentSecondPeriodBonus = 0.0,
accountStartDate = DateTime.now().minus(
MonthSpan(2)))
assertEquals(2400, calculator.finalBalance)
assertEquals(600.0, calculator.finalSecondYearBonus)
assertEquals(600.0, calculator.finalFourthYearBonus)
assertEquals(1200.0, calculator.finalTotalBonus)

assertEquals(2400.0, calculator.endOfSchemeSavings)
assertEquals(1200.0, calculator.endOfSchemeBonus)
assertEquals(3600.0, calculator.endOfSchemeTotal)

assertEquals(600.0, calculator.endOfPeriod1Bonus)
assertEquals(1200.0, calculator.endOfPeriod1Savings)
assertEquals(1800.0, calculator.endOfPeriod1Total)

assertEquals(600.0, calculator.endOfPeriod2Bonus)
assertEquals(1200.0, calculator.endOfPeriod2Savings)
assertEquals(1800.0, calculator.endOfPeriod2Total)
}

@Test
fun `Month breakdown if they have not saved in the first 2 months`() {
val calculator = Calculator.run(
regularPayment = 50,
currentBalance = 0,
regularPayment = 50.0,
currentBalance = 0.0,
currentFirstPeriodBonus = 0.0,
currentSecondPeriodBonus = 0.0,
accountStartDate = DateTime.now().minus(
MonthSpan(2)))
assertEquals(2300, calculator.finalBalance)
assertEquals(550.0, calculator.finalSecondYearBonus)
assertEquals(600.0, calculator.finalFourthYearBonus)
assertEquals(1150.0, calculator.finalTotalBonus)
assertEquals(2300.0, calculator.endOfSchemeSavings)
assertEquals(1150.0, calculator.endOfSchemeBonus)
assertEquals(3450.0, calculator.endOfSchemeTotal)

assertEquals(550.0, calculator.endOfPeriod1Bonus)
assertEquals(1100.0, calculator.endOfPeriod1Savings)
assertEquals(1650.0, calculator.endOfPeriod1Total)
assertEquals(600.0, calculator.endOfPeriod2Bonus)
assertEquals(1200.0, calculator.endOfPeriod2Savings)
assertEquals(1800.0, calculator.endOfPeriod2Total)
}

@Test
fun `Month breakdown if they have not saved in the first 24 months`() {
val calculator = Calculator.run(
regularPayment = 50,
currentBalance = 0,
regularPayment = 50.0,
currentBalance = 0.0,
currentFirstPeriodBonus = 0.0,
currentSecondPeriodBonus = 0.0,
accountStartDate = DateTime.now().minus(
MonthSpan(24)))
assertEquals(1200, calculator.finalBalance)
assertEquals(0.0, calculator.finalSecondYearBonus)
assertEquals(600.0, calculator.finalFourthYearBonus)
assertEquals(600.0, calculator.finalTotalBonus)
assertEquals(1800.0, calculator.endOfSchemeTotal)
assertEquals(1200.0, calculator.endOfSchemeSavings)
assertEquals(600.0, calculator.endOfSchemeBonus)
assertEquals(0.0, calculator.endOfPeriod1Bonus)
assertEquals(0.0, calculator.endOfPeriod1Savings)
assertEquals(0.0, calculator.endOfPeriod1Total)
assertEquals(600.0, calculator.endOfPeriod2Bonus)
assertEquals(1200.0, calculator.endOfPeriod2Savings)
assertEquals(1800.0, calculator.endOfPeriod2Total)
}
}
Loading

0 comments on commit 002fa35

Please sign in to comment.