public async Task PerformHolidayPayAccruedCalculationAsync_Return_WhenHolidayStartDate12MonthsBeforeInsolvencyDate() { // Arrange var inputData = new HolidayPayAccruedCalculationRequestModel { InsolvencyDate = new DateTime(2019, 1, 14), EmpStartDate = new DateTime(2016, 1, 1), DismissalDate = new DateTime(2018, 11, 30), ContractedHolEntitlement = 28, HolidayYearStart = new DateTime(2018, 01, 01), IsTaxable = true, PayDay = (int)DayOfWeek.Saturday, ShiftPattern = new List <string> { "1", "2", "3", "4", "5" }, WeeklyWage = 575.34m, DaysCFwd = 8m, DaysTaken = 10m, IpConfirmedDays = 41 }; // Act var outputData = await Task.FromResult(_holidayPayAccruedCalculationService.PerformHolidayPayAccruedCalculationAsync(inputData, _options)); // Assert outputData.Result.StatutoryMax.Should().Be(508m); outputData.Result.HolidaysOwed.Should().Be(28); outputData.Result.BusinessDaysInClaim.Should().Be(261.00m); outputData.Result.WorkingDaysInClaim.Should().Be(230m); outputData.Result.ProRataAccruedDays.Should().Be(22.6743m); }
public static async Task <DateTime> GetHolidayYearEnd(this HolidayPayAccruedCalculationRequestModel model) { var holidayStart = model.HolidayYearStart.Date; if (holidayStart < model.EmpStartDate.Date) { holidayStart = model.EmpStartDate.Date; } return(await Task.FromResult(holidayStart.AddMonths(12).AddDays(-1))); }
public async Task GetHolidayYearEnd_Returns_HolidayYearEnd() { // Arrange var model = new HolidayPayAccruedCalculationRequestModel() { EmpStartDate = new DateTime(2018, 08, 01), HolidayYearStart = new DateTime(2018, 03, 01) }; var expectedHolidayYearEnd = new DateTime(2019, 07, 31); // Act var result = await model.GetHolidayYearEnd(); // Assert result.Should().Be(expectedHolidayYearEnd); }
public async Task GetHolidayYearStart_Returns_AdjustedHolidayYearStart() { // Arrange var model = new HolidayPayAccruedCalculationRequestModel() { EmpStartDate = new DateTime(2017, 08, 22), HolidayYearStart = new DateTime(2018, 01, 01) }; var expectedAdjEmpStartDate = new DateTime(2018, 01, 01); // Act var result = await model.GetHolidayYearStart(); // Assert result.Should().Be(expectedAdjEmpStartDate); }
public async Task PerformHolidayPayAccruedCalculationAsync_Return_PartialDay3() { // Arrange var inputData = new HolidayPayAccruedCalculationRequestModel { InsolvencyDate = new DateTime(2019, 10, 22), EmpStartDate = new DateTime(2010, 10, 22), DismissalDate = new DateTime(2019, 10, 22), ContractedHolEntitlement = 28, HolidayYearStart = new DateTime(2019, 01, 01), IsTaxable = true, PayDay = (int)DayOfWeek.Friday, ShiftPattern = new List <string> { "1", "3", "4" }, WeeklyWage = 800m, DaysCFwd = 0m, DaysTaken = 0m, IpConfirmedDays = 3m }; // Act var outputData = await Task.FromResult(_holidayPayAccruedCalculationService.PerformHolidayPayAccruedCalculationAsync(inputData, _options)); // Assert outputData.Result.StatutoryMax.Should().Be(525m); outputData.Result.HolidaysOwed.Should().Be(28); outputData.Result.BusinessDaysInClaim.Should().Be(156m); outputData.Result.WorkingDaysInClaim.Should().Be(126m); outputData.Result.ProRataAccruedDays.Should().Be(3m); outputData.Result.WeeklyResults.Count.Should().Be(1); outputData.Result.WeeklyResults[0].WeekNumber.Should().Be(1); outputData.Result.WeeklyResults[0].MaximumEntitlement.Should().Be(525m); outputData.Result.WeeklyResults[0].EmployerEntitlement.Should().Be(800m); outputData.Result.WeeklyResults[0].GrossEntitlement.Should().Be(525m); outputData.Result.WeeklyResults[0].IsTaxable.Should().Be(true); outputData.Result.WeeklyResults[0].TaxDeducted.Should().Be(105m); outputData.Result.WeeklyResults[0].NiDeducted.Should().Be(41.04m); outputData.Result.WeeklyResults[0].NetEntitlement.Should().Be(378.96m); outputData.Result.WeeklyResults[0].PreferentialClaim.Should().Be(outputData.Result.WeeklyResults[0].GrossEntitlement); outputData.Result.WeeklyResults[0].NonPreferentialClaim.Should().Be(0m); }
public async Task PerformHolidayCalculationAsync_PerformsHpaAndHtnpCalculationsWithRp14aSelected() { // Arrange var shiftPattern = new List <string> { "1", "2", "3", "4", "5" }; var hpaRequest = new HolidayPayAccruedCalculationRequestModel { InsolvencyDate = new DateTime(2018, 10, 1), EmpStartDate = new DateTime(2016, 1, 1), DismissalDate = new DateTime(2018, 10, 1), ContractedHolEntitlement = 25, HolidayYearStart = new DateTime(2018, 1, 1), IsTaxable = true, PayDay = (int)DayOfWeek.Saturday, ShiftPattern = shiftPattern, WeeklyWage = 320m, DaysCFwd = 0m, DaysTaken = 8m, }; var hpaResponse = new HolidayPayAccruedResponseDTO() { StatutoryMax = 508, HolidaysOwed = 28, BusinessDaysInClaim = 261, WorkingDaysInClaim = 196, ProRataAccruedDays = 13.0268m, WeeklyResults = new List <HolidayPayAccruedWeeklyResult>() { new HolidayPayAccruedWeeklyResult(1, 508m, 320m, 320m, true, 64m, 18.96m, 237.04m, 320m, 0m), new HolidayPayAccruedWeeklyResult(2, 508m, 320m, 320m, true, 64m, 18.96m, 237.04m, 320m, 0m), new HolidayPayAccruedWeeklyResult(3, 292.23m, 193.72m, 193.72m, true, 38.74m, 3.81m, 151.17m, 193.72m, 0m), } }; var htnpRequest = new List <HolidayTakenNotPaidCalculationRequestModel>() { new HolidayTakenNotPaidCalculationRequestModel(InputSource.Rp1, new DateTime(2018, 10, 1), new DateTime(2018, 10, 1), new DateTime(2018, 8, 1), new DateTime(2018, 8, 12), 320, shiftPattern, 6, true), new HolidayTakenNotPaidCalculationRequestModel(InputSource.Rp14a, new DateTime(2018, 10, 1), new DateTime(2018, 10, 1), new DateTime(2018, 8, 2), new DateTime(2018, 8, 14), 320, shiftPattern, 6, true) }; var htnpResponseRp1 = new HolidayTakenNotPaidResponseDTO() { InputSource = InputSource.Rp1, WeeklyResult = new List <HolidayTakenNotPaidWeeklyResult>() { new HolidayTakenNotPaidWeeklyResult(1, new DateTime(2018, 8, 4), 508, 192, 192, true, 38.4m, 3.6m, 150m, 7, 3, 508, 192, 192, true), new HolidayTakenNotPaidWeeklyResult(2, new DateTime(2018, 8, 11), 508, 320, 320, true, 64m, 18.96m, 237.04m, 7, 5, 508, 320, 320, true), } }; var htnpResponseRp14a = new HolidayTakenNotPaidResponseDTO() { InputSource = InputSource.Rp14a, WeeklyResult = new List <HolidayTakenNotPaidWeeklyResult>() { new HolidayTakenNotPaidWeeklyResult(1, new DateTime(2018, 8, 4), 508, 128, 128, true, 25.6m, 0m, 102.4m, 7, 2, 508, 128, 128, false), new HolidayTakenNotPaidWeeklyResult(2, new DateTime(2018, 8, 11), 508, 320, 320, true, 64m, 18.96m, 237.04m, 7, 5, 508, 320, 320, false), new HolidayTakenNotPaidWeeklyResult(3, new DateTime(2018, 8, 18), 508, 128, 128, true, 25.6m, 0m, 102.4m, 7, 2, 508, 128, 128, false) } }; _hpaService.Setup(x => x.PerformHolidayPayAccruedCalculationAsync(hpaRequest, _options)).ReturnsAsync(hpaResponse); _htnpService.Setup(x => x.PerformCalculationAsync(htnpRequest, InputSource.Rp1, It.IsAny <decimal>(), It.IsAny <decimal>(), It.IsAny <DateTime?>(), _options, It.IsAny <TraceInfo>())).ReturnsAsync(htnpResponseRp1); _htnpService.Setup(x => x.PerformCalculationAsync(htnpRequest, InputSource.Rp14a, It.IsAny <decimal>(), It.IsAny <decimal>(), It.IsAny <DateTime?>(), _options, It.IsAny <TraceInfo>())).ReturnsAsync(htnpResponseRp14a); var request = new HolidayCalculationRequestModel() { Hpa = hpaRequest, Htnp = htnpRequest }; // Act var results = await _service.PerformHolidayCalculationAsync(request, _options); // Assert results.Hpa.Should().NotBeNull(); results.Htnp.Should().NotBeNull(); results.Htnp.SelectedInputSource.Should().Be(InputSource.Rp1); _hpaService.Verify(m => m.PerformHolidayPayAccruedCalculationAsync( hpaRequest, It.IsAny <IOptions <ConfigLookupRoot> >()), Times.Once); _htnpService.Verify(m => m.PerformCalculationAsync( It.IsAny <List <HolidayTakenNotPaidCalculationRequestModel> >(), InputSource.Rp1, 14.9732m, 16.9732m, hpaRequest.HolidayYearStart, It.IsAny <IOptions <ConfigLookupRoot> >(), It.IsAny <TraceInfo>()), Times.Once); _htnpService.Verify(m => m.PerformCalculationAsync( htnpRequest, InputSource.Rp14a, 0m, 0m, hpaRequest.HolidayYearStart, It.IsAny <IOptions <ConfigLookupRoot> >(), It.IsAny <TraceInfo>()), Times.Once); }
public async Task PostAsync_FailsWithBadRequest_WhenThereIsAHpaValidationError(HolidayPayAccruedCalculationRequestModel hpaRequest, string expectedErrorMessage) { //Arrange var request = new HolidayCalculationRequestModel() { Hpa = hpaRequest }; var controller = new HolidayController(_service.Object, _mockLogger.Object, _confOptions); //Act var result = await controller.PostAsync(request); //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 <HolidayPayAccruedResponseDTO> PerformHolidayPayAccruedCalculationAsync( HolidayPayAccruedCalculationRequestModel data, IOptions <ConfigLookupRoot> options) { var response = new ResponseDto <HolidayPayAccruedResponseDTO>(); var calculationResult = new HolidayPayAccruedResponseDTO(); var shiftPattern = data.ShiftPattern; var twelveMonthsPrior = data.InsolvencyDate.Date.AddMonths(-12).AddDays(1); var adjHolYearStart = await data.GetHolidayYearStart(); if (adjHolYearStart < twelveMonthsPrior) { adjHolYearStart = twelveMonthsPrior; } var holYearEndDate = await data.GetHolidayYearEnd(); var statMaxWeeklyPay = ConfigValueLookupHelper.GetStatutoryMax(options, data.DismissalDate); // Calculate totals for holiday pay accrued int totalBusinessDaysInClaim = await data.HolidayYearStart.GetNumBusinessDaysInRange(holYearEndDate, shiftPattern); int totalWorkingDaysInClaim = 0; totalWorkingDaysInClaim = await totalWorkingDaysInClaim.GetTotalWorkingDaysInHolidayClaim( data.ShiftPattern, adjHolYearStart, holYearEndDate.Date, data.DismissalDate.Date, data.InsolvencyDate.Date, data.EmpStartDate.Date); decimal limitedDaysCFwd = 0.00m; limitedDaysCFwd = await limitedDaysCFwd.GetLimitedDaysCFwd(shiftPattern, data.DaysCFwd.GetValueOrDefault()); decimal statHolEntitlement = 0.00m; statHolEntitlement = await statHolEntitlement.GetStatutoryHolidayEntitlement(shiftPattern); decimal adjHolidayEntitlement = await statHolEntitlement.GetAdjustedHolidayEntitlement(data.ContractedHolEntitlement.GetValueOrDefault()); decimal proRataAccruedDays = 0.00m; proRataAccruedDays = await proRataAccruedDays.GetProRataAccruedDays((decimal)adjHolidayEntitlement, totalBusinessDaysInClaim, totalWorkingDaysInClaim, limitedDaysCFwd, data.DaysTaken.GetValueOrDefault(), shiftPattern, data.IpConfirmedDays); calculationResult.BusinessDaysInClaim = totalBusinessDaysInClaim; calculationResult.StatutoryMax = Math.Round(statMaxWeeklyPay, 2); calculationResult.WorkingDaysInClaim = totalWorkingDaysInClaim; calculationResult.HolidaysOwed = Math.Round(adjHolidayEntitlement, 4); calculationResult.ProRataAccruedDays = Math.Round(proRataAccruedDays, 4); // Calculate weekly breakdown of holiday pay accrued var taxRate = ConfigValueLookupHelper.GetTaxRate(options, DateTime.Now); var niThreshold = ConfigValueLookupHelper.GetNIThreshold(options, DateTime.Now); var niRate = ConfigValueLookupHelper.GetNIRate(options, DateTime.Now); decimal entitlementWeeks = (proRataAccruedDays / data.ShiftPattern.Count); int wholeWeeks = (int)Math.Floor(entitlementWeeks); decimal partWeekDays = (entitlementWeeks - wholeWeeks) * shiftPattern.Count; decimal maximumEntitlement = 0.00m; decimal employerEntitlement = 0.00m; var weeklyResults = new List <HolidayPayAccruedWeeklyResult>(); decimal maxDays; decimal empDays; // Loop through each holiday entitlement week for (var weekNumber = 1; weekNumber <= Math.Ceiling(entitlementWeeks); weekNumber++) { var weeklyResult = new HolidayPayAccruedWeeklyResult(); maxDays = 0; empDays = 0; if (weekNumber <= wholeWeeks) { maximumEntitlement = statMaxWeeklyPay; employerEntitlement = data.WeeklyWage.GetValueOrDefault(); } if (weekNumber > wholeWeeks) { var weekDayNumber = data.PayDay; // This must be the last (partial) week so loop through each day, checking for working days for (var day = 0; day <= 6; day++) { weekDayNumber++; if (weekDayNumber > (int)DayOfWeek.Saturday) { weekDayNumber = (int)DayOfWeek.Sunday; } if (shiftPattern.Contains(weekDayNumber.ToString())) { if (partWeekDays > 1) { partWeekDays--; maxDays++; empDays++; } else if (partWeekDays > 0) { maxDays = maxDays + partWeekDays; empDays = empDays + partWeekDays; partWeekDays = 0; } } else if (partWeekDays > 0) { maxDays++; } if (day == 6) { maximumEntitlement = (maxDays * statMaxWeeklyPay / 7); employerEntitlement = (empDays * data.WeeklyWage.GetValueOrDefault() / shiftPattern.Count); } } } decimal grossEntitlement = 0.00m; grossEntitlement = await grossEntitlement.GetGrossEntitlement(maximumEntitlement, employerEntitlement); decimal taxDeducted = Math.Round(await grossEntitlement.GetTaxDeducted(taxRate, (bool)data.IsTaxable), 2); decimal niDeducted = Math.Round(await grossEntitlement.GetNIDeducted(niThreshold, niRate, (bool)data.IsTaxable), 2); grossEntitlement = Math.Round(grossEntitlement, 2); weeklyResult.WeekNumber = weekNumber; weeklyResult.MaximumEntitlement = Math.Round(maximumEntitlement, 2); weeklyResult.EmployerEntitlement = Math.Round(employerEntitlement, 2); weeklyResult.GrossEntitlement = grossEntitlement; weeklyResult.IsTaxable = (bool)data.IsTaxable; weeklyResult.TaxDeducted = taxDeducted; weeklyResult.NiDeducted = niDeducted; weeklyResult.NetEntitlement = grossEntitlement - taxDeducted - niDeducted; weeklyResult.PreferentialClaim = grossEntitlement; weeklyResult.NonPreferentialClaim = 0m; weeklyResults.Add(weeklyResult); } calculationResult.WeeklyResults = weeklyResults; return(await Task.FromResult(calculationResult)); }
public static async Task <DateTime> GetHolidayYearStart(this HolidayPayAccruedCalculationRequestModel model) { return(await Task.FromResult(model.EmpStartDate.Date > model.HolidayYearStart.Date?model.EmpStartDate.Date : model.HolidayYearStart.Date)); }