Skip to content

Commit

Permalink
[HMA-1837] - Limit taxToPay to 50% of wages if taxToPay is over 50% o…
Browse files Browse the repository at this point in the history
…f their wages (#24)
  • Loading branch information
georgeherby authored Nov 19, 2019
1 parent c463388 commit e4be443
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 27 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

[![Build Status](https://app.bitrise.io/app/cd7fb52c258b9273/status.svg?token=lntO8o4xz5AUEvLwVzbo3A&branch=master)](https://app.bitrise.io/app/cd7fb52c258b9273)
![LINE](https://img.shields.io/badge/line--coverage-98%25-brightgreen.svg)
![BRANCH](https://img.shields.io/badge/branch--coverage-94%25-brightgreen.svg)
![COMPLEXITY](https://img.shields.io/badge/complexity-1.48-brightgreen.svg)
![BRANCH](https://img.shields.io/badge/branch--coverage-92%25-brightgreen.svg)
![COMPLEXITY](https://img.shields.io/badge/complexity-1.52-brightgreen.svg)
[ ![Download](https://api.bintray.com/packages/hmrc/mobile-releases/tax-kalculator/images/download.svg) ](https://bintray.com/hmrc/mobile-releases/tax-kalculator/_latestVersion)

## Calculate take-home pay
Expand Down Expand Up @@ -32,7 +32,8 @@ val response = calculator.run()

This will returns an object of type `CalculatorResponse`. This class is broken up into weekly, four_weekly, monthly and yearly. Each of these members is of type `CalculatorResponsePayPeriod` and the members of this class are what will return the values (relative to their PayPeriod) needed for the app, they are:

- `taxToPay: Double`
- `taxToPay: Double` -> This will capped at a maximum of 50% of their wages
- `maxTaxAmountExceeded: Boolean` -> This will always be false unless taxToPay is adjusted for 50%
- `employeesNI: Double`
- `employersNI: Double`
- `wages: Double`
Expand All @@ -48,7 +49,7 @@ This will returns an object of type `CalculatorResponse`. This class is broken u
To validate a tax code:

```kotlin
val isValid = Calculator.isValidTaxCode("1250L") // true
val isValid = Validator.isValidTaxCode("1250L") // true
```

To validate wages:
Expand Down
19 changes: 10 additions & 9 deletions src/commonMain/kotlin/uk/gov/hmrc/calculator/Calculator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package uk.gov.hmrc.calculator

import kotlin.jvm.JvmOverloads
import uk.gov.hmrc.calculator.annotations.Throws
import uk.gov.hmrc.calculator.exception.InvalidHoursException
import uk.gov.hmrc.calculator.exception.InvalidPayPeriodException
Expand Down Expand Up @@ -51,7 +52,7 @@ import uk.gov.hmrc.calculator.utils.convertListOfBandBreakdownForPayPeriod
import uk.gov.hmrc.calculator.utils.convertWageToYearly
import uk.gov.hmrc.calculator.utils.toTaxCode

class Calculator(
class Calculator @JvmOverloads constructor(
private val taxCode: String,
private val wages: Double,
private val payPeriod: PayPeriod,
Expand Down Expand Up @@ -100,41 +101,41 @@ class Calculator(
isKCode = taxCode is KTaxCode,
weekly = CalculatorResponsePayPeriod(
payPeriod = WEEKLY,
taxToPay = taxPayable.convertAmountFromYearlyToPayPeriod(WEEKLY),
taxToPayForPayPeriod = taxPayable.convertAmountFromYearlyToPayPeriod(WEEKLY),
employeesNI = employeesNI.convertAmountFromYearlyToPayPeriod(WEEKLY),
employersNI = employersNI.convertAmountFromYearlyToPayPeriod(WEEKLY),
wages = yearlyWages.convertAmountFromYearlyToPayPeriod(WEEKLY),
taxBreakdown = bandBreakdown.convertListOfBandBreakdownForPayPeriod(WEEKLY),
taxBreakdownForPayPeriod = bandBreakdown.convertListOfBandBreakdownForPayPeriod(WEEKLY),
taxFree = taxFreeAmount.convertAmountFromYearlyToPayPeriod(WEEKLY),
kCodeAdjustment = amountToAddToWages?.convertAmountFromYearlyToPayPeriod(WEEKLY)
),
fourWeekly = CalculatorResponsePayPeriod(
payPeriod = FOUR_WEEKLY,
taxToPay = taxPayable.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
taxToPayForPayPeriod = taxPayable.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
employeesNI = employeesNI.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
employersNI = employersNI.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
wages = yearlyWages.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
taxBreakdown = bandBreakdown.convertListOfBandBreakdownForPayPeriod(FOUR_WEEKLY),
taxBreakdownForPayPeriod = bandBreakdown.convertListOfBandBreakdownForPayPeriod(FOUR_WEEKLY),
taxFree = taxFreeAmount.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY),
kCodeAdjustment = amountToAddToWages?.convertAmountFromYearlyToPayPeriod(FOUR_WEEKLY)
),
monthly = CalculatorResponsePayPeriod(
payPeriod = MONTHLY,
taxToPay = taxPayable.convertAmountFromYearlyToPayPeriod(MONTHLY),
taxToPayForPayPeriod = taxPayable.convertAmountFromYearlyToPayPeriod(MONTHLY),
employeesNI = employeesNI.convertAmountFromYearlyToPayPeriod(MONTHLY),
employersNI = employersNI.convertAmountFromYearlyToPayPeriod(MONTHLY),
wages = yearlyWages.convertAmountFromYearlyToPayPeriod(MONTHLY),
taxBreakdown = bandBreakdown.convertListOfBandBreakdownForPayPeriod(MONTHLY),
taxBreakdownForPayPeriod = bandBreakdown.convertListOfBandBreakdownForPayPeriod(MONTHLY),
taxFree = taxFreeAmount.convertAmountFromYearlyToPayPeriod(MONTHLY),
kCodeAdjustment = amountToAddToWages?.convertAmountFromYearlyToPayPeriod(MONTHLY)
),
yearly = CalculatorResponsePayPeriod(
payPeriod = YEARLY,
taxToPay = taxPayable.convertAmountFromYearlyToPayPeriod(YEARLY),
taxToPayForPayPeriod = taxPayable.convertAmountFromYearlyToPayPeriod(YEARLY),
employeesNI = employeesNI.convertAmountFromYearlyToPayPeriod(YEARLY),
employersNI = employersNI.convertAmountFromYearlyToPayPeriod(YEARLY),
wages = yearlyWages.convertAmountFromYearlyToPayPeriod(YEARLY),
taxBreakdown = bandBreakdown,
taxBreakdownForPayPeriod = bandBreakdown,
taxFree = taxFreeAmount,
kCodeAdjustment = amountToAddToWages
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@ data class BandBreakdown(val percentage: Double, val amount: Double) {
val bandDescription: String = "Income taxed at $percentageFormatted%"
}

data class CalculatorResponsePayPeriod(
class CalculatorResponsePayPeriod(
val payPeriod: PayPeriod,
val taxToPay: Double,
taxToPayForPayPeriod: Double,
val employeesNI: Double,
val employersNI: Double,
val wages: Double,
val taxBreakdown: List<BandBreakdown>,
taxBreakdownForPayPeriod: List<BandBreakdown>?,
val taxFree: Double,
val kCodeAdjustment: Double? = null
) {
private val maxTaxAmount = wages / 2
val taxToPay = if (taxToPayForPayPeriod > maxTaxAmount) maxTaxAmount else taxToPayForPayPeriod
val maxTaxAmountExceeded = (taxToPayForPayPeriod > maxTaxAmount)
val totalDeductions = taxToPay + employeesNI
val takeHome = wages - totalDeductions
val taxBreakdown = if (maxTaxAmountExceeded) null else taxBreakdownForPayPeriod
}

data class CalculatorResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ class CalculatorResponseTests {
fun `Check Summation Of Total Deductions`() {
val response = CalculatorResponsePayPeriod(
payPeriod = YEARLY,
taxToPay = 100.0,
taxToPayForPayPeriod = 100.0,
employeesNI = 200.0,
employersNI = 300.0,
wages = 1000.0,
taxBreakdown = listOf(
taxBreakdownForPayPeriod = listOf(
BandBreakdown(0.0, 0.0),
BandBreakdown(0.2, 2000.0)
),
Expand Down Expand Up @@ -82,7 +82,7 @@ class CalculatorResponseTests {
)
), response.yearly.taxBreakdown
)
assertEquals(response.yearly.taxBreakdown[0].bandDescription, "Income taxed at 20%")
assertEquals(response.yearly.taxBreakdown?.get(0)?.bandDescription, "Income taxed at 20%")

assertEquals(191.51666666666668, response.monthly.taxToPay)
assertEquals(153.67999999999998, response.monthly.employeesNI)
Expand Down Expand Up @@ -160,8 +160,8 @@ class CalculatorResponseTests {
BandBreakdown(percentage = 0.4, amount = 32000.00)
), response.yearly.taxBreakdown
)
assertEquals(response.yearly.taxBreakdown[0].bandDescription, "Income taxed at 20%")
assertEquals(response.yearly.taxBreakdown[1].bandDescription, "Income taxed at 40%")
assertEquals(response.monthly.taxBreakdown?.get(0)?.bandDescription, "Income taxed at 20%")
assertEquals(response.monthly.taxBreakdown?.get(1)?.bandDescription, "Income taxed at 40%")

assertEquals(3291.5166666666664, response.monthly.taxToPay)
assertEquals(530.3466666666667, response.monthly.employeesNI)
Expand Down Expand Up @@ -249,10 +249,10 @@ class CalculatorResponseTests {
BandBreakdown(percentage = 0.41, amount = 35493.70)
), response.yearly.taxBreakdown
)
assertEquals(response.yearly.taxBreakdown[0].bandDescription, "Income taxed at 19%")
assertEquals(response.yearly.taxBreakdown[1].bandDescription, "Income taxed at 20%")
assertEquals(response.yearly.taxBreakdown[2].bandDescription, "Income taxed at 21%")
assertEquals(response.yearly.taxBreakdown[3].bandDescription, "Income taxed at 41%")
assertEquals(response.monthly.taxBreakdown?.get(0)?.bandDescription, "Income taxed at 19%")
assertEquals(response.monthly.taxBreakdown?.get(1)?.bandDescription, "Income taxed at 20%")
assertEquals(response.monthly.taxBreakdown?.get(2)?.bandDescription, "Income taxed at 21%")
assertEquals(response.monthly.taxBreakdown?.get(3)?.bandDescription, "Income taxed at 41%")

assertEquals(3486.8633333333332, response.monthly.taxToPay)
assertEquals(530.3466666666667, response.monthly.employeesNI)
Expand Down Expand Up @@ -343,12 +343,13 @@ class CalculatorResponseTests {
), response.yearly.taxBreakdown
)
}

@Test
fun `NT`() {
fun NT() {
val taxCode = "NT"
val wages = 130000.00
val response = Calculator(taxCode, wages, payPeriod = YEARLY).run()

assertEquals(false, response.yearly.maxTaxAmountExceeded)
assertEquals(6564.16, response.yearly.totalDeductions)
assertEquals(
listOf(
Expand All @@ -359,4 +360,27 @@ class CalculatorResponseTests {
), response.yearly.taxBreakdown
)
}

@Test
fun `Check K9999 (Ensure HMRC does not tax you more than 50%)`() {
val taxCode = "K9999"
val wages = 400.00
val response = Calculator(taxCode, wages, payPeriod = PayPeriod.WEEKLY).run()

assertEquals(ENGLAND, response.country)
assertEquals(true, response.isKCode)
assertEquals("K9999", response.taxCode)

// Year
assertEquals(YEARLY, response.yearly.payPeriod)
assertEquals(10400.0, response.yearly.taxToPay)
assertEquals(1460.1599999999999, response.yearly.employeesNI)
assertEquals(true, response.yearly.maxTaxAmountExceeded)
assertEquals(11860.16, response.yearly.totalDeductions)
assertEquals(8939.84, response.yearly.takeHome)
assertEquals(0.0, response.yearly.taxFree)
assertEquals(20800.0, response.yearly.wages)
assertEquals(99999.0, response.yearly.kCodeAdjustment)
assertEquals(null, response.yearly.taxBreakdown)
}
}

0 comments on commit e4be443

Please sign in to comment.