protected override decimal GetPayAdjustment(TaxCode taxCode, PayPeriods periods /*, int period*/) { if (taxCode.IsNoAdjustmentCode || !taxCode.TaxCodeNumber.HasValue || taxCode.TaxCodeNumber.Value == 0) { return(0); } var codeNumber = taxCode.TaxCodeNumber.Value; var remainder = ((codeNumber - 1m) % 500) + 1m; var quotient = Math.Floor(codeNumber - remainder) / 500m; var payPeriodForQuotient = (periods == PayPeriods.Monthly ? PayPeriods.Monthly : PayPeriods.Weekly); var quotientMult = TaxMath.UpRound(500 * (10 / (decimal)payPeriodForQuotient), 2); remainder = ((remainder * 10) + 9) / (int)payPeriodForQuotient; remainder = Math.Ceiling(remainder * 100) / 100; //remainder *= Math.Round((decimal)payPeriodForQuotient / (decimal)periods); quotient = quotient * quotientMult; var adjustment = (quotient + remainder);// * period; adjustment *= Math.Round((decimal)payPeriodForQuotient / (decimal)periods); if (taxCode.IsPrefixCode) { adjustment *= -1; } return(adjustment); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { // The ST is back! But lower than PT. var niRates = TaxYearConfigurationData.NiRates[niCategory]; // 'X' NI Code does not pay NI contributions if (niCategory == 'X') { gross = 0m; } var limitThresholds = GetLimitThresholdsForPeriods(payPeriods); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, limitThresholds.LowerEarningsLimit, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.LowerEarningsLimit), EarningsAboveUEL = SubtractRound(gross, gross, limitThresholds.UpperEarningsLimit), EarningsAboveSTUpToIncludingPT = SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.SecondaryThreshold), EarningsAbovePTUptoIncludingUEL = SubtractRound(gross, limitThresholds.UpperEarningsLimit, limitThresholds.PrimaryThreshold), }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUpToIncludingPT * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAbovePTUptoIncludingUEL * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound((niCalc.EarningsAboveSTUpToIncludingPT + niCalc.EarningsAbovePTUptoIncludingUEL) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErE / 100)); return(niCalc); }
protected override void CreateContainer(TaxCode taxCode, decimal grossForPeriod, PayPeriods periods, int period = 1, bool week1 = false, decimal grossToDateExcludingPeriod = 0, decimal taxToDateExcludingPeriod = 0) { if (week1 || period == 1) { period = 1; grossToDateExcludingPeriod = 0; taxToDateExcludingPeriod = 0; } CalculationContainer = new PayeCalculationContainer { TaxCode = taxCode, Week1 = week1, Periods = periods, TaxToDate = taxToDateExcludingPeriod, n = period, pn = grossForPeriod, Pn1 = grossToDateExcludingPeriod, Pn = grossForPeriod + grossToDateExcludingPeriod, a1 = GetPayAdjustment(taxCode, periods), // Constants M = 50 }; CalculationContainer.na1 = CalculationContainer.a1 * CalculationContainer.n; CalculationContainer.Un = CalculationContainer.Pn - CalculationContainer.na1; CalculationContainer.Tn = TaxMath.Truncate(CalculationContainer.Un, 0); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var niRates = TaxYearConfigurationData.NiRates[niCategory]; var limitThresholds = GetLimitThresholdsForPeriods(payPeriods); #pragma warning disable IDE0017 // Simplify object initialization var niCalc = new NationalInsuranceCalculation(); #pragma warning restore IDE0017 // Simplify object initialization // Employee NI Gross niCalc.EmployeeNiGross = TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.UpperAccrualPoint, limitThresholds.PrimaryThreshold) * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.UpperEarningsLimit, limitThresholds.UpperAccrualPoint) * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, limitThresholds.UpperEarningsLimit) * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.SecondaryThreshold, limitThresholds.LowerEarningsLimit) * (niRates.EeB / 100)); niCalc.EmployeeNiRebate += TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.SecondaryThreshold) * (niRates.EeC / 100)); // Employer NI Gross niCalc.EmployerNiGross = TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.SecondaryThreshold) * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.UpperAccrualPoint, limitThresholds.PrimaryThreshold) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.UpperEarningsLimit, limitThresholds.UpperAccrualPoint) * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, limitThresholds.UpperEarningsLimit) * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(SubtractRound(gross, limitThresholds.SecondaryThreshold, limitThresholds.LowerEarningsLimit) * (niRates.ErB / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.PrimaryThreshold); var totalST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.SecondaryThreshold); var totalUEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperEarningsLimit); var totalLEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.LowerEarningsLimit); var totalUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperSecondaryThreshold); var totalAUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.ApprenticeUpperSecondaryThreshold); var niRates = TaxYearSpecificProvider.GetCodeSpecifics(niCategory); var(periods, weeksInPeriod) = TaxMath.GetFactoring(payPeriods); decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periods), weeksInPeriod), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAbovePTUptoIncludingST = SubtractRound(gross, periodST, periodPT), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodST), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAbovePTUptoIncludingST * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErE / 100)); return(niCalc); }
protected virtual decimal SubtractRound(decimal gross, decimal limit, decimal subtract) { var subtractFrom = TaxMath.Smallest(gross, limit); var subtracted = subtractFrom - subtract; subtracted = Math.Round(subtracted, 2, MidpointRounding.AwayFromZero); return(TaxMath.PositiveOnly(subtracted)); }
protected override void Calculateln() { CalculationContainer.ln = TaxMath.Truncate(CalculationContainer.Ln, 2); if (CalculationContainer.n > 1) CalculationContainer.ln -= CalculationContainer.TaxToDate; // In V13+ we always apply the regulatory limit CalculationContainer.ln = Math.Min(CalculationContainer.ln, TaxMath.Truncate(CalculationContainer.pn * (CalculationContainer.M / 100), 2)); }
public void BankersRoundingTest() { Assert.AreEqual(1m, TaxMath.BankersRound(0.99999m)); Assert.AreEqual(1.96m, TaxMath.BankersRound(1.956m)); Assert.AreEqual(2.96m, TaxMath.BankersRound(2.9555555m)); Assert.AreEqual(2.47m, TaxMath.BankersRound(2.4719m)); Assert.AreEqual(978.55m, TaxMath.BankersRound(978.54823m)); Assert.AreEqual(8956.54m, TaxMath.BankersRound(8956.54168m)); Assert.AreEqual(654.17m, TaxMath.BankersRound(654.168749m)); Assert.AreEqual(236514.47m, TaxMath.BankersRound(236514.46984m)); Assert.AreEqual(784.47m, TaxMath.BankersRound(784.4687m)); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = taxYearConfigurationData.PrimaryThreshold; var totalST = taxYearConfigurationData.SecondaryThreshold; var totalUAP = taxYearConfigurationData.UpperAccrualPoint; var totalUEL = taxYearConfigurationData.UpperEarningsLimit; var totalLEL = taxYearConfigurationData.LowerEarningsLimit; var niRates = taxYearConfigurationData.NiRates[niCategory]; var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUAP = TaxMath.PeriodRound(TaxMath.Factor(totalUAP, weeksInPeriod, periods), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periods), weeksInPeriod), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation(); // Employee NI Gross var lelToPt = SubtractRound(gross, periodPT, periodLEL); var ptToSt = SubtractRound(gross, periodST, periodPT); var stToUap = SubtractRound(gross, periodUAP, periodST); var uapToUel = SubtractRound(gross, periodUEL, periodUAP); var aboveUel = SubtractRound(gross, gross, periodUEL); niCalc.EmployeeNiGross = TaxMath.HmrcRound(ptToSt * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(stToUap * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(uapToUel * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(aboveUel * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(lelToPt * (niRates.EeB / 100)); // Employer NI Gross //niCalc.EmployerNiGross = TaxMath.HmrcRound(ptToSt * (niRates.ErC / 100)); if (!(niCategory == 'I' || niCategory == 'K' || niCategory == 'V')) { niCalc.EmployerNiGross += TaxMath.HmrcRound(stToUap * (niRates.ErD / 100)); } niCalc.EmployerNiGross += TaxMath.HmrcRound(uapToUel * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(aboveUel * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(lelToPt * (niRates.ErB / 100)); niCalc.EmployerNiRebate += TaxMath.HmrcRound(ptToSt * (niRates.ErC / 100)); if ((niCategory == 'I' || niCategory == 'K' || niCategory == 'V')) { niCalc.EmployerNiRebate += TaxMath.HmrcRound(stToUap * (niRates.ErD / 100)); } return(niCalc); }
public StudentLoanCalculation CalculateStudentLoanDeduction(StudentLoanPlan plan, decimal gross, PayPeriods periods) { decimal threshold = 0, rate = 0, periodAdjustedThreshold, thresholdAdjustedGross, deduction; int periodCnt = 52; int weeksInPeriod = 1; if (periods == PayPeriods.Monthly) { periodCnt = 12; } else { weeksInPeriod = (int)Math.Round((decimal)periodCnt / (int)periods); } switch (plan) { case StudentLoanPlan.Plan1: threshold = taxYearConfigurationData.Plan1StudentLoanThreshold; rate = taxYearConfigurationData.Plan1StudentLoanRate; break; case StudentLoanPlan.Plan2: threshold = taxYearConfigurationData.Plan2StudentLoanThreshold; rate = taxYearConfigurationData.Plan2StudentLoanRate; break; case StudentLoanPlan.Plan4: threshold = taxYearConfigurationData.Plan4StudentLoanThreshold; rate = taxYearConfigurationData.Plan4StudentLoanRate; break; case StudentLoanPlan.PostGrad: threshold = taxYearConfigurationData.PostGradStudentLoanThreshold; rate = taxYearConfigurationData.PostGradStudentLoanRate; break; } periodAdjustedThreshold = TaxMath.Truncate(((threshold * weeksInPeriod) / periodCnt), 2); thresholdAdjustedGross = Math.Max(0, gross - periodAdjustedThreshold); deduction = Math.Floor(thresholdAdjustedGross * rate); return(new StudentLoanCalculation { Gross = gross, Threshold = threshold, Rate = rate, PeriodAdjustedThreshold = periodAdjustedThreshold, ThresholdAdjustedGross = thresholdAdjustedGross, StudentLoanDeduction = deduction }); }
protected override LimitThresholds CalculateLimitThresholdsForPeriods(PayPeriods payPeriods) { var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; // WTF. UEL must round 865.3846 to 866. But PT must round 680.3333 to 680. This isn't sane. return(new LimitThresholds { PrimaryThreshold = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.PrimaryThreshold, weeksInPeriod, periods), weeksInPeriod), UpperEarningsLimit = Math.Ceiling(TaxMath.Factor(TaxYearConfigurationData.UpperEarningsLimit, weeksInPeriod, periods)), LowerEarningsLimit = Math.Ceiling(TaxMath.Factor(TaxYearConfigurationData.LowerEarningsLimit, weeksInPeriod, periods)), }); }
protected override LimitThresholds CalculateLimitThresholdsForPeriods(PayPeriods payPeriods) { var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; return(new LimitThresholds { PrimaryThreshold = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.PrimaryThreshold, weeksInPeriod, periods), weeksInPeriod), SecondaryThreshold = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.SecondaryThreshold, weeksInPeriod, periods), weeksInPeriod), UpperEarningsLimit = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.UpperEarningsLimit, weeksInPeriod, periods), weeksInPeriod), LowerEarningsLimit = Math.Ceiling(TaxMath.Factor(TaxYearConfigurationData.LowerEarningsLimit, weeksInPeriod, periods)), }); }
protected virtual void Calculateln() { CalculationContainer.ln = TaxMath.Truncate(CalculationContainer.Ln, 2); if (CalculationContainer.n > 1) { CalculationContainer.ln -= CalculationContainer.TaxToDate; } if (CalculationContainer.TaxCode.IsPrefixCode) { CalculationContainer.ln = Math.Min(CalculationContainer.ln, TaxMath.Truncate(CalculationContainer.pn * (CalculationContainer.M / 100), 2)); } }
protected override LimitThresholds CalculateLimitThresholdsForPeriods(PayPeriods payPeriods) { var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; // WTF. HMRC changed their rounding rules AGAIN in 2020. PeriodRound for the ST too. return(new LimitThresholds { PrimaryThreshold = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.PrimaryThreshold, weeksInPeriod, periods), weeksInPeriod), SecondaryThreshold = TaxMath.PeriodRound(TaxMath.Factor(TaxYearConfigurationData.SecondaryThreshold, weeksInPeriod, periods), weeksInPeriod), UpperEarningsLimit = Math.Ceiling(TaxMath.Factor(TaxYearConfigurationData.UpperEarningsLimit, weeksInPeriod, periods)), LowerEarningsLimit = Math.Ceiling(TaxMath.Factor(TaxYearConfigurationData.LowerEarningsLimit, weeksInPeriod, periods)), }); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods periods) { int periodCnt = 52; int weeksInPeriod = 1; if (periods == PayPeriods.Monthly) { periodCnt = 12; } else { weeksInPeriod = (int)Math.Round((decimal)periodCnt / (int)periods); } var totalPT = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.PrimaryThreshold); var totalST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.SecondaryThreshold); var totalUAP = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperAccrualPoint); var totalUEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperEarningsLimit); var totalLEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.LowerEarningsLimit); var niRates = TaxYearSpecificProvider.GetCodeSpecifics(niCategory); decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periodCnt), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periodCnt), weeksInPeriod), periodUAP = TaxMath.PeriodRound(TaxMath.Factor(totalUAP, weeksInPeriod, periodCnt), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periodCnt), weeksInPeriod), periodLEL = TaxMath.PeriodRound(TaxMath.Factor(totalLEL, weeksInPeriod, periodCnt), weeksInPeriod); var niCalc = new NationalInsuranceCalculation(); // Employee NI Gross niCalc.EmployeeNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.EeB / 100)); niCalc.EmployeeNiRebate += TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.EeC / 100)); // Employer NI Gross niCalc.EmployerNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.ErB / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { // The ST is back! But lower than PT. var totalPT = taxYearConfigurationData.PrimaryThreshold; var totalST = taxYearConfigurationData.SecondaryThreshold; var totalUEL = taxYearConfigurationData.UpperEarningsLimit; var totalLEL = taxYearConfigurationData.LowerEarningsLimit; var totalUST = taxYearConfigurationData.UpperSecondaryThreshold; var totalAUST = taxYearConfigurationData.ApprenticeUpperSecondaryThreshold; var niRates = taxYearConfigurationData.NiRates[niCategory]; var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; // 'X' NI Code does not pay NI contributions if (niCategory == 'X') { gross = 0m; } // WTF. HMRC changed their rounding rules AGAIN in 2020. PeriodRound for the ST too. decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUEL = Math.Ceiling(TaxMath.Factor(totalUEL, weeksInPeriod, periods)), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL), EarningsAboveSTUpToIncludingPT = SubtractRound(gross, periodPT, periodST), EarningsAbovePTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodPT), }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUpToIncludingPT * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAbovePTUptoIncludingUEL * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound((niCalc.EarningsAboveSTUpToIncludingPT + niCalc.EarningsAbovePTUptoIncludingUEL) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErE / 100)); return(niCalc); }
public void NumberTruncationTest() { Assert.AreEqual(9999.99999m, TaxMath.Truncate(9999.999999999m, 5)); Assert.AreEqual(9999.9999m, TaxMath.Truncate(9999.999999999m, 4)); Assert.AreEqual(9999.999m, TaxMath.Truncate(9999.999999999m, 3)); Assert.AreEqual(9999.99m, TaxMath.Truncate(9999.999999999m, 2)); Assert.AreEqual(9999.9m, TaxMath.Truncate(9999.999999999m, 1)); Assert.AreEqual(9999m, TaxMath.Truncate(9999.999999999m, 0)); Assert.AreEqual(9990m, TaxMath.Truncate(9999.999999999m, -1)); Assert.AreEqual(-9999.99999m, TaxMath.Truncate(-9999.999999999m, 5)); Assert.AreEqual(-9999.9999m, TaxMath.Truncate(-9999.999999999m, 4)); Assert.AreEqual(-9999.999m, TaxMath.Truncate(-9999.999999999m, 3)); Assert.AreEqual(-9999.99m, TaxMath.Truncate(-9999.999999999m, 2)); Assert.AreEqual(-9999.9m, TaxMath.Truncate(-9999.999999999m, 1)); Assert.AreEqual(-9999m, TaxMath.Truncate(-9999.999999999m, 0)); Assert.AreEqual(-9990m, TaxMath.Truncate(-9999.999999999m, -1)); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods periods) { int periodCnt = 52; int weeksInPeriod = 1; if (periods == PayPeriods.Monthly) { periodCnt = 12; } else { weeksInPeriod = (int)Math.Round((decimal)periodCnt / (int)periods); } var totalPT = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.PrimaryThreshold); var totalST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.SecondaryThreshold); var totalUEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperEarningsLimit); var totalLEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.LowerEarningsLimit); var totalUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperSecondaryThreshold); var totalAUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.ApprenticeUpperSecondaryThreshold); var niRates = TaxYearSpecificProvider.GetCodeSpecifics(niCategory); // WTF. UEL must round 865.3846 to 866. But PT must round 680.3333 to 680. This isn't sane. decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periodCnt), weeksInPeriod), periodUEL = Math.Ceiling(TaxMath.Factor(totalUEL, weeksInPeriod, periodCnt)), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periodCnt)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodPT), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErD / 100)); return(niCalc); }
protected override PayeInternalBracket[] GetBracketsForPeriod() { int year = TaxYear, period = CalculationContainer.n, periods = (int)CalculationContainer.Periods; bool scottish = CalculationContainer.TaxCode.IsScotlandTax; Tuple <int, int, int, bool> brKey; if (BracketCache.ContainsKey(brKey = new Tuple <int, int, int, bool>(year, period, periods, scottish))) { return(BracketCache[brKey]); } var taxYearBrackets = GetBracketsFromProvider(TaxYear > 2016 ? scottish : false); var periodBrackets = new List <PayeInternalBracket>(); decimal lastC = 0, lastK = 0; foreach (var taxYearBracket in taxYearBrackets) { #pragma warning disable IDE0017 // Simplify object initialization var periodBracket = new PayeInternalBracket(); #pragma warning restore IDE0017 // Simplify object initialization periodBracket.R = taxYearBracket.Multiplier; periodBracket.B = taxYearBracket.To - taxYearBracket.From; periodBracket.C = periodBracket.B + lastC; lastC = periodBracket.C; periodBracket.c = TaxMath.Factor(periodBracket.C, period, periods); periodBracket.c = TaxMath.Truncate(periodBracket.c, 4); periodBracket.v = Math.Ceiling(periodBracket.c); periodBracket.K = lastK + TaxMath.Multiply(periodBracket.B, periodBracket.R, TaxMath.MultiplicationAccuracy.High); lastK = periodBracket.K; periodBracket.k = TaxMath.Factor(periodBracket.K, period, periods); periodBracket.k = TaxMath.Truncate(periodBracket.k, 4); periodBrackets.Add(periodBracket); } BracketCache[brKey] = periodBrackets.ToArray(); return(periodBrackets.ToArray()); }
public StudentLoanCalculationResult CalculateStudentLoanDeduction(StudentLoanPlan plan, decimal gross, PayPeriods periods) { decimal threshold = 0, rate = 0, periodAdjustedThreshold, thresholdAdjustedGross, deduction; int periodCnt = 52; int weeksInPeriod = 1; if (periods == PayPeriods.Monthly) { periodCnt = 12; } else { weeksInPeriod = (int)Math.Round((decimal)periodCnt / (int)periods); } switch (plan) { case StudentLoanPlan.Plan1: threshold = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.Plan1StudentLoanThreshold); rate = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.Plan1StudentLoanRate); break; case StudentLoanPlan.Plan2: threshold = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.Plan2StudentLoanThreshold); rate = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.Plan2StudentLoanRate); break; } periodAdjustedThreshold = TaxMath.Truncate(((threshold * weeksInPeriod) / periodCnt), 2); thresholdAdjustedGross = Math.Max(0, gross - periodAdjustedThreshold); deduction = Math.Floor(thresholdAdjustedGross * rate); return(new StudentLoanCalculationResult { Gross = gross, Threshold = threshold, Rate = rate, PeriodAdjustedThreshold = periodAdjustedThreshold, ThresholdAdjustedGross = thresholdAdjustedGross, StudentLoanDeduction = deduction }); }
/// <summary> /// Returns a rounded period value /// </summary> /// <param name="specificValueType"></param> /// <param name="period"></param> /// <returns></returns> public decimal GetPeriodTaxYearValue(TaxYearSpecificValues specificValueType, PayPeriods period) { // Get the annual value decimal annualValue = GetSpecificValue <decimal>(specificValueType); // By default for weekly we have 52 weeks in our period int periodCnt = 52; int weeksInPeriod = 1; if (period == PayPeriods.Monthly) { periodCnt = 12; } else { weeksInPeriod = (int)Math.Round((decimal)periodCnt / (int)period); } return(TaxMath.PeriodRound((annualValue * weeksInPeriod) / periodCnt, weeksInPeriod)); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = taxYearConfigurationData.PrimaryThreshold; var totalST = taxYearConfigurationData.SecondaryThreshold; var totalUEL = taxYearConfigurationData.UpperEarningsLimit; var totalLEL = taxYearConfigurationData.LowerEarningsLimit; var totalUST = taxYearConfigurationData.UpperSecondaryThreshold; var totalAUST = taxYearConfigurationData.ApprenticeUpperSecondaryThreshold; var niRates = taxYearConfigurationData.NiRates[niCategory]; var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; // 'X' NI Code does not pay NI contributions if (niCategory == 'X') { gross = 0m; } // WTF. UEL must round 865.3846 to 866. But PT must round 680.3333 to 680. This isn't sane. decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodUEL = Math.Ceiling(TaxMath.Factor(totalUEL, weeksInPeriod, periods)), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodPT), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErD / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var niRates = TaxYearConfigurationData.NiRates[niCategory]; var niCalc = new NationalInsuranceCalculation(); var limitThresholds = GetLimitThresholdsForPeriods(payPeriods); // Employee NI Gross var lelToPt = SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.LowerEarningsLimit); var ptToSt = SubtractRound(gross, limitThresholds.SecondaryThreshold, limitThresholds.PrimaryThreshold); var stToUap = SubtractRound(gross, limitThresholds.UpperAccrualPoint, limitThresholds.SecondaryThreshold); var uapToUel = SubtractRound(gross, limitThresholds.UpperEarningsLimit, limitThresholds.UpperAccrualPoint); var aboveUel = SubtractRound(gross, gross, limitThresholds.UpperEarningsLimit); niCalc.EmployeeNiGross = TaxMath.HmrcRound(ptToSt * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(stToUap * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(uapToUel * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(aboveUel * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(lelToPt * (niRates.EeB / 100)); // Employer NI Gross //niCalc.EmployerNiGross = TaxMath.HmrcRound(ptToSt * (niRates.ErC / 100)); if (!(niCategory == 'I' || niCategory == 'K' || niCategory == 'V')) { niCalc.EmployerNiGross += TaxMath.HmrcRound(stToUap * (niRates.ErD / 100)); } niCalc.EmployerNiGross += TaxMath.HmrcRound(uapToUel * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(aboveUel * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(lelToPt * (niRates.ErB / 100)); niCalc.EmployerNiRebate += TaxMath.HmrcRound(ptToSt * (niRates.ErC / 100)); if ((niCategory == 'I' || niCategory == 'K' || niCategory == 'V')) { niCalc.EmployerNiRebate += TaxMath.HmrcRound(stToUap * (niRates.ErD / 100)); } return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.PrimaryThreshold); var totalST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.SecondaryThreshold); var totalUEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperEarningsLimit); var totalLEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.LowerEarningsLimit); var totalUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperSecondaryThreshold); var totalAUST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.ApprenticeUpperSecondaryThreshold); var niRates = TaxYearSpecificProvider.GetCodeSpecifics(niCategory); // 'X' Ni Code does not pay NI contributions if (niCategory == 'X') { gross = 0m; } var(periods, weeksInPeriod) = TaxMath.GetFactoring(payPeriods); // WTF. UEL must round 865.3846 to 866. But PT must round 680.3333 to 680. This isn't sane. decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodUEL = Math.Ceiling(TaxMath.Factor(totalUEL, weeksInPeriod, periods)), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodPT), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErD / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = taxYearConfigurationData.PrimaryThreshold; var totalST = taxYearConfigurationData.SecondaryThreshold; var totalUAP = taxYearConfigurationData.UpperAccrualPoint; var totalUEL = taxYearConfigurationData.UpperEarningsLimit; var totalLEL = taxYearConfigurationData.LowerEarningsLimit; var niRates = taxYearConfigurationData.NiRates[niCategory]; var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUAP = TaxMath.PeriodRound(TaxMath.Factor(totalUAP, weeksInPeriod, periods), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periods), weeksInPeriod), periodLEL = TaxMath.PeriodRound(TaxMath.Factor(totalLEL, weeksInPeriod, periods), weeksInPeriod); #pragma warning disable IDE0017 // Simplify object initialization var niCalc = new NationalInsuranceCalculation(); #pragma warning restore IDE0017 // Simplify object initialization // Employee NI Gross niCalc.EmployeeNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.EeB / 100)); niCalc.EmployeeNiRebate += TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.EeC / 100)); // Employer NI Gross niCalc.EmployerNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.ErB / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.PrimaryThreshold); var totalST = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.SecondaryThreshold); var totalUAP = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperAccrualPoint); var totalUEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.UpperEarningsLimit); var totalLEL = TaxYearSpecificProvider.GetSpecificValue <decimal>(TaxYearSpecificValues.LowerEarningsLimit); var niRates = TaxYearSpecificProvider.GetCodeSpecifics(niCategory); var(periods, weeksInPeriod) = TaxMath.GetFactoring(payPeriods); decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUAP = TaxMath.PeriodRound(TaxMath.Factor(totalUAP, weeksInPeriod, periods), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periods), weeksInPeriod), periodLEL = TaxMath.PeriodRound(TaxMath.Factor(totalLEL, weeksInPeriod, periods), weeksInPeriod); #pragma warning disable IDE0017 // Simplify object initialization var niCalc = new NationalInsuranceCalculation(); #pragma warning restore IDE0017 // Simplify object initialization // Employee NI Gross niCalc.EmployeeNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.EeE / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.EeF / 100)); niCalc.EmployeeNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.EeB / 100)); niCalc.EmployeeNiRebate += TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.EeC / 100)); // Employer NI Gross niCalc.EmployerNiGross = TaxMath.HmrcRound(SubtractRound(gross, periodPT, periodST) * (niRates.ErC / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUAP, periodPT) * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, periodUEL, periodUAP) * (niRates.ErE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(SubtractRound(gross, gross, periodUEL) * (niRates.ErF / 100)); niCalc.EmployerNiRebate = TaxMath.HmrcRound(SubtractRound(gross, periodST, periodLEL) * (niRates.ErB / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var niRates = TaxYearConfigurationData.NiRates[niCategory]; var limitThresholds = GetLimitThresholdsForPeriods(payPeriods); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, limitThresholds.LowerEarningsLimit, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, limitThresholds.PrimaryThreshold, limitThresholds.LowerEarningsLimit), EarningsAbovePTUptoIncludingST = SubtractRound(gross, limitThresholds.SecondaryThreshold, limitThresholds.PrimaryThreshold), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, limitThresholds.UpperEarningsLimit, limitThresholds.SecondaryThreshold), EarningsAboveUEL = SubtractRound(gross, gross, limitThresholds.UpperEarningsLimit) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAbovePTUptoIncludingST * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErE / 100)); return(niCalc); }
public override NationalInsuranceCalculation CalculateNationalInsurance(decimal gross, char niCategory, PayPeriods payPeriods) { var totalPT = taxYearConfigurationData.PrimaryThreshold; var totalST = taxYearConfigurationData.SecondaryThreshold; var totalUEL = taxYearConfigurationData.UpperEarningsLimit; var totalLEL = taxYearConfigurationData.LowerEarningsLimit; var totalUST = taxYearConfigurationData.UpperSecondaryThreshold; var totalAUST = taxYearConfigurationData.ApprenticeUpperSecondaryThreshold; var niRates = taxYearConfigurationData.NiRates[niCategory]; var factoring = TaxMath.GetFactoring(payPeriods); int periods = factoring.Periods, weeksInPeriod = factoring.WeeksInPeriod; decimal periodPT = TaxMath.PeriodRound(TaxMath.Factor(totalPT, weeksInPeriod, periods), weeksInPeriod), periodST = TaxMath.PeriodRound(TaxMath.Factor(totalST, weeksInPeriod, periods), weeksInPeriod), periodUEL = TaxMath.PeriodRound(TaxMath.Factor(totalUEL, weeksInPeriod, periods), weeksInPeriod), periodLEL = Math.Ceiling(TaxMath.Factor(totalLEL, weeksInPeriod, periods)); var niCalc = new NationalInsuranceCalculation { EarningsUptoIncludingLEL = SubtractRound(gross, periodLEL, 0), EarningsAboveLELUptoIncludingPT = SubtractRound(gross, periodPT, periodLEL), EarningsAbovePTUptoIncludingST = SubtractRound(gross, periodST, periodPT), EarningsAboveSTUptoIncludingUEL = SubtractRound(gross, periodUEL, periodST), EarningsAboveUEL = SubtractRound(gross, gross, periodUEL) }; niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAbovePTUptoIncludingST * (niRates.EeC / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.EeD / 100)); niCalc.EmployeeNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.EeE / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveSTUptoIncludingUEL * (niRates.ErD / 100)); niCalc.EmployerNiGross += TaxMath.HmrcRound(niCalc.EarningsAboveUEL * (niRates.ErE / 100)); return(niCalc); }