public StatutoryCalculationResult <SickPayAssessment> Calculate(SickPayAssessment model, IEnumerable <SickPayAssessment> previousSicknotes = null) { var assessmentCalculation = new StatutoryCalculationResult <SickPayAssessment>(); assessmentCalculation.Assessment = model; if (!model.UpcomingPaymentDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The next Upcoming Payment Date must be provided"); } if (assessmentCalculation.Errors.Any()) { return(assessmentCalculation); } assessmentCalculation.IsEligible = model.IsEligible; var previousSickDays = new List <DateTime>(); // If we are providing some historical sick notes, extract the actual sick days for each of them if (previousSicknotes != null) { previousSickDays = previousSicknotes.OrderBy(m => m.StartDate).SelectMany(m => GetSickDays(m, true)).Distinct().ToList(); } var scheduledPayments = new List <StatutoryPayment>(); var datesInRange = GetSickDays(model, !model.ApplyWaitingDays); var nextPaymentDate = model.UpcomingPaymentDateForPeriod; var maxSickDays = Math.Max(140 - model.PreviousSickDaysTotal, 0); var totalDaysClaimed = 0; var statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = taxYearConfigurationData.StatutorySickPayDayRate, Qty = 0m }; foreach (var claimDate in datesInRange) { if (claimDate > nextPaymentDate) { scheduledPayments.Add(statPayment); // Next payment is one week away, Fort/Monthly change nextPaymentDate = nextPaymentDate.AddDays(7); statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = taxYearConfigurationData.StatutorySickPayDayRate, Qty = 0m }; } // If we have already been paid a sick note for this date, don't pay it twice if (previousSickDays.Contains(claimDate)) { continue; } // If we have reached our max sick days, don't pay any more if (totalDaysClaimed >= maxSickDays) { break; } // We do want to pay this date, woop for the worker statPayment.Qty += 1m; totalDaysClaimed++; } // Add the last period scheduledPayments.Add(statPayment); // Filter out empty schedules assessmentCalculation.Payments = scheduledPayments.Where(m => m.Qty > 0).Select(m => m); return(assessmentCalculation); }
public StatutoryCalculationResult <PaternityPayAssessment> Calculate(PaternityPayAssessment model) { var assessmentCalculation = new StatutoryCalculationResult <PaternityPayAssessment>(); if (!model.UpcomingPaymentDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The next Upcoming Payment Date must be provided"); } if (!model.StartDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The Start Date must be provided"); } if (!model.BirthDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The Birth Date must be provided"); } if (model.UpcomingPaymentDate.HasValue && model.StartDate.HasValue && model.UpcomingPaymentDate.Value < model.StartDate.Value) { assessmentCalculation.AddError(StatutoryValidationError.InvalidUpcomingPayDate, "The upcoming process date cannot be before the Start Date"); } if (model.BirthDate.HasValue && model.StartDate.HasValue && model.StartDate.Value < model.BirthDate.Value) { assessmentCalculation.AddError(StatutoryValidationError.InvalidStartDate, "Paternity pay cannot be started before the birth date"); } if (assessmentCalculation.Errors.Any()) { return(assessmentCalculation); } if (!model.EndDate.HasValue) { model.EndDate = model.StartDate?.AddDays(model.TotalClaimDays); } assessmentCalculation.IsEligible = model.IsEligible; var scheduledPayments = new List <StatutoryPayment>(); var datesInRange = model.GetQualifyingDatesInRange(); var nextPaymentDate = (model.UpcomingPaymentDate.Value >= datesInRange.First() ? model.UpcomingPaymentDate.Value : model.UpcomingPaymentDate.Value.AddDays(7)); var statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = taxYearConfigurationData.StatutoryPaternityPayDayRate, Qty = 0m }; foreach (var claimDate in datesInRange) { if (claimDate > nextPaymentDate) { scheduledPayments.Add(statPayment); // Next payment is one week away, Fort/Monthly change nextPaymentDate = nextPaymentDate.AddDays(7); statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = taxYearConfigurationData.StatutoryPaternityPayDayRate, Qty = 0m }; } // We do want to pay this date statPayment.Qty += 1m; } // Add the last period scheduledPayments.Add(statPayment); // Filter out empty schedules assessmentCalculation.Payments = scheduledPayments.Where(m => m.Qty > 0).Select(m => m); return(assessmentCalculation); }
public StatutoryCalculationResult <MaternityPayAssessment> Calculate(MaternityPayAssessment model) { var assessmentCalculation = new StatutoryCalculationResult <MaternityPayAssessment>(); if (!model.UpcomingPaymentDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The next Upcoming Payment Date must be provided"); } if (!model.StartDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The Start Date must be provided"); } if (!model.DueDate.HasValue) { assessmentCalculation.AddError(StatutoryValidationError.MissingRequiredValue, "The Due Date must be provided"); } if (model.UpcomingPaymentDate.Value < model.StartDate.Value) { assessmentCalculation.AddError(StatutoryValidationError.InvalidUpcomingPayDate, "The upcoming process date cannot be before the Start Date"); } if (assessmentCalculation.Errors.Any()) { return(assessmentCalculation); } assessmentCalculation.IsEligible = model.IsEligible; if (!model.StartDate.HasValue) { model.StartDate = model.DueDate; } // Statutory Maternity Pay ends after 39 weeks if (!model.EndDate.HasValue) { model.EndDate = model.StartDate.Value.AddDays((7 * 39) - 1); } var scheduledPayments = new List <StatutoryPayment>(); var datesInRange = model.GetQualifyingDatesInRange(); var nextPaymentDate = (model.UpcomingPaymentDate.Value >= datesInRange.First() ? model.UpcomingPaymentDate.Value : model.UpcomingPaymentDate.Value.AddDays(7)); var belowAverageEarningsCost = (model.AverageWeeklyEarnings * 0.9m) / 7; var statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = taxYearConfigurationData.StatutoryMaternityPayDayRate, Qty = 0m }; int totalDaysClaimed = 0; foreach (var claimDate in datesInRange) { totalDaysClaimed++; // First 6 weeks we claim the average rate if (totalDaysClaimed <= 43) { statPayment.Cost = belowAverageEarningsCost; statPayment.IsStatutoryMinimumRate = false; } if (claimDate > nextPaymentDate) { scheduledPayments.Add(statPayment); // Next payment is one week away, Fort/Monthly change nextPaymentDate = nextPaymentDate.AddDays(7); statPayment = new StatutoryPayment { ReferenceDate = nextPaymentDate, PaymentDate = nextPaymentDate.AddDays(7), Cost = Math.Min(belowAverageEarningsCost, taxYearConfigurationData.StatutoryMaternityPayDayRate), Qty = 0m, IsStatutoryMinimumRate = (belowAverageEarningsCost > taxYearConfigurationData.StatutoryMaternityPayDayRate) }; } // If this is the first day of our statutory minimum, create a new holder at the reduced rate if (totalDaysClaimed == (7 * 6) + 1) { scheduledPayments.Add(statPayment); statPayment = new StatutoryPayment { ReferenceDate = statPayment.ReferenceDate, PaymentDate = statPayment.PaymentDate, Cost = Math.Min(belowAverageEarningsCost, taxYearConfigurationData.StatutoryMaternityPayDayRate), Qty = 0m, IsStatutoryMinimumRate = (belowAverageEarningsCost > taxYearConfigurationData.StatutoryMaternityPayDayRate) }; } // We do want to pay this date statPayment.Qty += 1m; } // Add the last period scheduledPayments.Add(statPayment); // Filter out empty schedules assessmentCalculation.Payments = scheduledPayments.Where(m => m.Qty > 0).Select(m => m); return(assessmentCalculation); }