public async Task PerformCalculationAsync_WithPeriodOutside4Month() { var request = new NoticeWorkedNotPaidCalculationRequestModel() { InputSource = InputSource.Rp14a, EmploymentStartDate = new DateTime(2015, 8, 2), InsolvencyDate = new DateTime(2018, 7, 26), DateNoticeGiven = new DateTime(2018, 7, 20), DismissalDate = new DateTime(2018, 8, 8), UnpaidPeriodFrom = new DateTime(2018, 7, 27), UnpaidPeriodTo = new DateTime(2018, 8, 8), WeeklyWage = 320, ShiftPattern = new List <string> { "1", "2", "3", "4", "5" }, PayDay = 6, IsTaxable = true, ApClaimAmount = 100 }; var expectedResults = new NoticeWorkedNotPaidResponseDTO(InputSource.Rp14a, 508, weeklyResult: new List <NoticeWorkedNotPaidWeeklyResult>() { new NoticeWorkedNotPaidWeeklyResult() { WeekNumber = 1, PayDate = new DateTime(2018, 8, 03), MaximumEntitlement = 508m, EmployerEntitlement = 55.56M, GrossEntitlement = 55.56M, IsTaxable = true, TaxDeducted = 11.11M, NiDeducted = 0m, NetEntitlement = 44.45M, MaximumDays = 7, EmploymentDays = 5, MaximumEntitlementIn4MonthPeriod = 0M, EmployerEntitlementIn4MonthPeriod = 0M, GrossEntitlementIn4Months = 0m }, new NoticeWorkedNotPaidWeeklyResult() { WeekNumber = 2, PayDate = new DateTime(2018, 8, 10), MaximumEntitlement = 362.86m, EmployerEntitlement = 33.33M, GrossEntitlement = 33.33M, IsTaxable = true, TaxDeducted = 6.67M, NiDeducted = 0m, NetEntitlement = 26.66M, MaximumDays = 5, EmploymentDays = 3, MaximumEntitlementIn4MonthPeriod = 0M, EmployerEntitlementIn4MonthPeriod = 0m, GrossEntitlementIn4Months = 0m } }); await TestCalculation(request, expectedResults); }
private async Task TestCalculation( NoticeWorkedNotPaidCalculationRequestModel request, NoticeWorkedNotPaidResponseDTO expectedResult) { //Act var actualResult = await _noticeWorkedNotPaidCalculationService.PerformNwnpCalculationAsync(request, _options); //Assert actualResult.InputSource.Should().Be(expectedResult.InputSource); actualResult.StatutoryMax.Should().Be(expectedResult.StatutoryMax); actualResult.WeeklyResult.Count.Should().Be(expectedResult.WeeklyResult.Count); for (var index = 0; index < expectedResult.WeeklyResult.Count; index++) { actualResult.WeeklyResult[index].WeekNumber.Should().Be(expectedResult.WeeklyResult[index].WeekNumber); actualResult.WeeklyResult[index].PayDate.Should().Be(expectedResult.WeeklyResult[index].PayDate); actualResult.WeeklyResult[index].MaximumEntitlement.Should().Be(expectedResult.WeeklyResult[index].MaximumEntitlement); actualResult.WeeklyResult[index].EmployerEntitlement.Should().Be(expectedResult.WeeklyResult[index].EmployerEntitlement); actualResult.WeeklyResult[index].GrossEntitlement.Should().Be(expectedResult.WeeklyResult[index].GrossEntitlement); actualResult.WeeklyResult[index].IsTaxable.Should().Be(expectedResult.WeeklyResult[index].IsTaxable); actualResult.WeeklyResult[index].TaxDeducted.Should().Be(expectedResult.WeeklyResult[index].TaxDeducted); actualResult.WeeklyResult[index].NiDeducted.Should().Be(expectedResult.WeeklyResult[index].NiDeducted); actualResult.WeeklyResult[index].NetEntitlement.Should().Be(expectedResult.WeeklyResult[index].NetEntitlement); actualResult.WeeklyResult[index].MaximumDays.Should().Be(expectedResult.WeeklyResult[index].MaximumDays); actualResult.WeeklyResult[index].EmploymentDays.Should().Be(expectedResult.WeeklyResult[index].EmploymentDays); actualResult.WeeklyResult[index].MaximumEntitlementIn4MonthPeriod.Should().Be(expectedResult.WeeklyResult[index].MaximumEntitlementIn4MonthPeriod); actualResult.WeeklyResult[index].EmployerEntitlementIn4MonthPeriod.Should().Be(expectedResult.WeeklyResult[index].EmployerEntitlementIn4MonthPeriod); actualResult.WeeklyResult[index].GrossEntitlementIn4Months.Should().Be(expectedResult.WeeklyResult[index].GrossEntitlementIn4Months); } }
public async Task PerformCalculationAsync_WhenNoticeGivenDuringArrearsOfPay_AndLessThatOneYearsService() { var request = new NoticeWorkedNotPaidCalculationRequestModel() { InputSource = InputSource.Rp14a, EmploymentStartDate = new DateTime(2018, 9, 3), InsolvencyDate = new DateTime(2019, 4, 3), DateNoticeGiven = new DateTime(2019, 3, 12), DismissalDate = new DateTime(2019, 3, 28), UnpaidPeriodFrom = new DateTime(2019, 3, 1), UnpaidPeriodTo = new DateTime(2019, 3, 31), WeeklyWage = 302.58m, ShiftPattern = new List <string> { "0", "1", "2", "4", "6" }, PayDay = 6, IsTaxable = true, ApClaimAmount = 1452.38M }; var expectedResults = new NoticeWorkedNotPaidResponseDTO(InputSource.Rp14a, 508, weeklyResult: new List <NoticeWorkedNotPaidWeeklyResult>() { new NoticeWorkedNotPaidWeeklyResult() { WeekNumber = 1, PayDate = new DateTime(2019, 3, 19), MaximumEntitlement = 508m, EmployerEntitlement = 330.09m, GrossEntitlement = 330.09m, IsTaxable = true, TaxDeducted = 66.02m, NiDeducted = 17.65m, NetEntitlement = 246.42m, MaximumDays = 7, EmploymentDays = 5, MaximumEntitlementIn4MonthPeriod = 508m, EmployerEntitlementIn4MonthPeriod = 330.09m, GrossEntitlementIn4Months = 330.09m } }); await TestCalculation(request, expectedResults); }
public async Task PostAsync_ReturnsBadRequest_When_RequestData_HaveInvalidNWNPData(NoticeWorkedNotPaidCalculationRequestModel request, string expectedErrorMessage) { //Arrange var controller = new NoticeController(_service.Object, _mockLogger.Object, _confOptions); var data = new NoticePayCompositeCalculationRequestModel() { Cnp = null, Nwnp = new List <NoticeWorkedNotPaidCalculationRequestModel>() { request } }; //Act var result = await controller.PostAsync(data); //Assert var badRequestObjectRequest = result.Should().BeOfType <BadRequestObjectResult>().Subject; badRequestObjectRequest.StatusCode.Should().Be((int)System.Net.HttpStatusCode.BadRequest); _mockLogger.Verify(x => x.Log( LogLevel.Error, It.IsAny <EventId>(), It.Is <object>(v => v.ToString().Contains(expectedErrorMessage)), null, It.IsAny <Func <object, Exception, string> >() )); }
public async Task <NoticeWorkedNotPaidResponseDTO> PerformNwnpCalculationAsync(NoticeWorkedNotPaidCalculationRequestModel data, IOptions <ConfigLookupRoot> options, TraceInfoDate traceInfoDate = null) { var calculationResult = new NoticeWorkedNotPaidResponseDTO(); var weeklyResult = new List <NoticeWorkedNotPaidWeeklyResult>(); decimal statutoryMax = ConfigValueLookupHelper.GetStatutoryMax(options, data.InsolvencyDate.Date); int yearsOfService = await data.EmploymentStartDate.Date.GetServiceYearsAsync(data.DismissalDate.Date); yearsOfService = Math.Max(yearsOfService, 1); yearsOfService = Math.Min(yearsOfService, 12); //calculate last date they can claim var noticeStartDate = data.DateNoticeGiven.Date.AddDays(1); var adjUnpaidPeriodFrom = (data.UnpaidPeriodFrom.Date > noticeStartDate) ? data.UnpaidPeriodFrom.Date : noticeStartDate; var entitlementEndDate = noticeStartDate.AddDays(yearsOfService * 7).AddDays(-1); //The maximum end date is notice start date + number of entitlement weeks var adjUnpaidPeriodTo = (data.UnpaidPeriodTo.Date < entitlementEndDate) ? data.UnpaidPeriodTo.Date : entitlementEndDate; adjUnpaidPeriodTo = (data.DismissalDate.Date < adjUnpaidPeriodTo) ? data.DismissalDate.Date : adjUnpaidPeriodTo; // Extend adjusted period by 7 days to capture last working week var extendedAdjustedPeriodTo = adjUnpaidPeriodTo; if (extendedAdjustedPeriodTo.DayOfWeek != data.DateNoticeGiven.DayOfWeek) { extendedAdjustedPeriodTo = extendedAdjustedPeriodTo.AddDays(7); } var payDays = await adjUnpaidPeriodFrom .AddDays(1) .GetDaysInRange(extendedAdjustedPeriodTo, data.DateNoticeGiven.DayOfWeek); // set pref period start date DateTime prefPeriodStartDate = data.InsolvencyDate.Date.AddMonths(-4); //step through paydaysCollection for (var paydaysCollectionIndex = 0; paydaysCollectionIndex < payDays.Count; paydaysCollectionIndex++) { var employmentDaysInPrefPeriod = 0; var maximumDaysInPrefPeriod = 0; var employmentDays = 0; var maximumDays = 0; var maximumEntitlement = 0.0m; // Debug.WriteLine($"Week start = {pDay.Start}"); //step through days of week for this payday var weekDates = await payDays[paydaysCollectionIndex].Date.GetWeekDatesAsync(); var weekDatesListIndex = 6; while (weekDatesListIndex >= 0) { var date = weekDates[weekDatesListIndex]; var dayNum = (int)date.DayOfWeek; //is this day a working day? if (data.ShiftPattern.Contains(dayNum.ToString())) { if (date >= adjUnpaidPeriodFrom.Date && date <= adjUnpaidPeriodTo.Date) { employmentDays++; if (date >= prefPeriodStartDate && date <= data.InsolvencyDate) { employmentDaysInPrefPeriod++; } } } //maxDays does not rely on working days if (date <= extendedAdjustedPeriodTo.Date && date <= adjUnpaidPeriodTo.Date) { maximumDays++; if (date >= prefPeriodStartDate && date <= data.InsolvencyDate) { maximumDaysInPrefPeriod++; } } weekDatesListIndex--; } decimal adjustedWeeklyWage = await data.WeeklyWage.GetAdjustedWeeklyWageAsync(data.ShiftPattern, data.UnpaidPeriodFrom, data.UnpaidPeriodTo, data.ApClaimAmount); //calculate Employer Liability for week var employerEntitlement = adjustedWeeklyWage / data.ShiftPattern.Count * employmentDays; var employerEntitlementInPrefPeriod = adjustedWeeklyWage / data.ShiftPattern.Count * employmentDaysInPrefPeriod; var maximumEntitlementInPrefPeriod = statutoryMax / 7 * maximumDaysInPrefPeriod; //calculate Statutory Maximum liability for week // if it is the last week if (paydaysCollectionIndex == payDays.Count - 1) { //if last payday is after dismissal date if (payDays[paydaysCollectionIndex].Date > data.DismissalDate.Date) { maximumEntitlement = statutoryMax / 7m * maximumDays; } else { maximumEntitlement = statutoryMax; maximumDays = 7; if (payDays[paydaysCollectionIndex].Date < data.DismissalDate.Date && payDays[paydaysCollectionIndex].Date < data.InsolvencyDate) { maximumEntitlementInPrefPeriod = statutoryMax; } } } else { maximumEntitlement = statutoryMax; } var grossEntitlement = Math.Min(maximumEntitlement, employerEntitlement); var taxRate = ConfigValueLookupHelper.GetTaxRate(options, DateTime.Now); var taxDeducated = Math.Round(await grossEntitlement.GetTaxDeducted(taxRate, data.IsTaxable), 2); var niThreshold = ConfigValueLookupHelper.GetNIThreshold(options, DateTime.Now); var niRate = ConfigValueLookupHelper.GetNIRate(options, DateTime.Now); var niDeducted = Math.Round(await grossEntitlement.GetNIDeducted(niThreshold, niRate, data.IsTaxable), 2); grossEntitlement = Math.Round(grossEntitlement, 2); var netLiability = await grossEntitlement.GetNetLiability(taxDeducated, niDeducted); Debug.WriteLine( $"week : {payDays[paydaysCollectionIndex]} MaxEntitlement : {maximumEntitlement} || EmpEntitlement = {employerEntitlement} || Min : {Math.Min(maximumEntitlement, employerEntitlement)} "); weeklyResult.Add(new NoticeWorkedNotPaidWeeklyResult { WeekNumber = paydaysCollectionIndex + 1, PayDate = payDays[paydaysCollectionIndex].Date, MaximumEntitlement = Math.Round(maximumEntitlement, 2), EmployerEntitlement = Math.Round(employerEntitlement, 2), GrossEntitlement = grossEntitlement, IsTaxable = data.IsTaxable, TaxDeducted = taxDeducated, NiDeducted = niDeducted, NetEntitlement = netLiability, MaximumDays = maximumDays, EmploymentDays = employmentDays, MaximumEntitlementIn4MonthPeriod = Math.Round(maximumEntitlementInPrefPeriod, 2), EmployerEntitlementIn4MonthPeriod = Math.Round(employerEntitlementInPrefPeriod, 2), GrossEntitlementIn4Months = Math.Round(Math.Min(maximumEntitlementInPrefPeriod, employerEntitlementInPrefPeriod), 2) }); } //outter loop payday collection calculationResult.InputSource = data.InputSource; calculationResult.StatutoryMax = statutoryMax; calculationResult.WeeklyResult = weeklyResult; if (traceInfoDate != null) { traceInfoDate.StartDate = data.UnpaidPeriodFrom; traceInfoDate.EndDate = data.UnpaidPeriodTo; } return(await Task.FromResult(calculationResult)); }