public async Task PostAsync_Fails_IfClaimReceptDateIsAfterDismissalDatePlus6Months()
        {
            //Arrange
            var requestData = new RedundancyPaymentCalculationRequestModel
            {
                EmploymentStartDate = new DateTime(2015, 10, 11),
                DismissalDate       = new DateTime(2016, 08, 05),
                DateNoticeGiven     = new DateTime(2016, 08, 05),
                ClaimReceiptDate    = new DateTime(2017, 2, 06),
                DateOfBirth         = new DateTime(1995, 03, 11),
                WeeklyWage          = 203.64m,
                EmployerPartPayment = 0,
                EmploymentBreaks    = 0
            };

            //Act
            var redundancyPayController =
                new RedundancyPaymentController(_mockService.Object, _mockLogger.Object, _confOptions);

            //Assert
            var result = await redundancyPayController.PostAsync(requestData);

            var badRequest = result.Should().BeOfType <BadRequestObjectResult>().Subject;
            var statusCode = badRequest.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("Claim Receipt Date must be within 6 months of the dismissal date")),
                                   null,
                                   It.IsAny <Func <object, Exception, string> >()
                                   ));
        }
        public async Task PostAsync_Returns_NotEligibleRedundancyPaymentCalculationResponse()
        {
            //Arrange
            var requestData = new RedundancyPaymentCalculationRequestModel
            {
                EmploymentStartDate = new DateTime(2015, 10, 11),
                DismissalDate       = new DateTime(2016, 08, 05),
                DateNoticeGiven     = new DateTime(2016, 08, 05),
                DateOfBirth         = new DateTime(1995, 03, 11),
                WeeklyWage          = 203.64m,
                EmployerPartPayment = 0,
                EmploymentBreaks    = 0
            };

            //Act
            var redundancyPayController =
                new RedundancyPaymentController(_mockService.Object, _mockLogger.Object, _confOptions);

            //Assert
            var result = await redundancyPayController.PostAsync(requestData);

            var badRequest = result.Should().BeOfType <BadRequestObjectResult>().Subject;
            var statusCode = badRequest.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("Years of service cannot be less than 2 years")),
                                   null,
                                   It.IsAny <Func <object, Exception, string> >()
                                   ));
        }
        public async Task <IActionResult> PostAsync([FromBody] RedundancyPaymentCalculationRequestModel data)
        {
            try
            {
                if (data == null)
                {
                    ModelState.AddModelError("",
                                             "Bad payload provided; unable to parse the request , please review request data and try again");
                    _logger.LogError(400, $"Bad payload " +
                                     $"{ModelState}\n Request Data is null and could not be parsed");
                    return(BadRequest(ModelState));
                }

                var validator = new RedundancyPaymentCalculationRequestValidator();
                if (!ModelState.IsValid || !validator.Validate(data).IsValid)
                {
                    _logger.LogError(400, $"Request model not valid " +
                                     $"{ModelState}\n Request Data {JsonConvert.SerializeObject(data)} \n Errors : " +
                                     $"{validator.Validate(data).Errors.GetErrorsAsString()} ");
                    return(BadRequest(ModelState));
                }

                var result = await _rpCalculationsService.PerformRedundancyPayCalculationAsync(data, _options);

                _logger.LogInformation((int)HttpStatusCode.OK,
                                       $"Calculation performed successfully for the request data provided \n Request Data: {JsonConvert.SerializeObject(data)}");
                return(Ok(result));
            }
            catch (MissingConfigurationException exp)
            {
                _logger.LogError((int)HttpStatusCode.BadRequest,
                                 $"Calculation was not performed for the request data provided \n Request Data: {JsonConvert.SerializeObject(data)} Bad payload provided; {exp.Message}, please review request data and try again");
                return(BadRequest($"Bad payload provided; {exp.Message}, please review request data and try again"));
            }
        }
        public async Task PerformRedundancyPaymentCalculationForAllAgeGroups(
            RedundancyPaymentCalculationRequestModel request, RedundancyPaymentResponseDto expectedResult)
        {
            //Act
            var actualResult = await _redundancyPaymentCalculationService.PerformRedundancyPayCalculationAsync(request, _options);

            //Assert
            Assert.IsType <RedundancyPaymentResponseDto>(actualResult);
            actualResult.AdjEmploymentStartDate.Should().Be(expectedResult.AdjEmploymentStartDate);
            actualResult.NoticeDateForRedundancyPay.Should().Be(expectedResult.NoticeDateForRedundancyPay);
            actualResult.NoticeEntitlementWeeks.Should().Be(expectedResult.NoticeEntitlementWeeks);
            actualResult.RedundancyPayWeeks.Should().Be(expectedResult.RedundancyPayWeeks);
            actualResult.YearsOfServiceUpto21.Should().Be(expectedResult.YearsOfServiceUpto21);
            actualResult.YearsOfServiceFrom22To41.Should().Be(expectedResult.YearsOfServiceFrom22To41);
            actualResult.YearsServiceOver41.Should().Be(expectedResult.YearsServiceOver41);
            actualResult.GrossEntitlement.Should().Be(expectedResult.NetEntitlement);
            actualResult.EmployerPartPayment.Should().Be(expectedResult.EmployerPartPayment);
            actualResult.NetEntitlement.Should().Be(expectedResult.NetEntitlement);
            actualResult.PreferentialClaim.Should().Be(0m);
            actualResult.NonPreferentialClaim.Should().Be(expectedResult.NetEntitlement);
            actualResult.StatutoryMax.Should().Be(expectedResult.StatutoryMax);
        }
        public async Task <RedundancyPaymentResponseDto> PerformRedundancyPayCalculationAsync(
            RedundancyPaymentCalculationRequestModel data, IOptions <ConfigLookupRoot> options)
        {
            var calculationResult = new RedundancyPaymentResponseDto();

            var adjStartDate = await data.EmploymentStartDate.GetAdjustedEmploymentStartDate(data.EmploymentBreaks);

            var relevantNoticeDate = await data.DateNoticeGiven.GetRelevantNoticeDate(data.DismissalDate);

            var noticeEntitlementWeeks = await adjStartDate.GetNoticeEntitlementWeeks(relevantNoticeDate);

            var projectedNoticeDate = await relevantNoticeDate.GetProjectedNoticeDate(noticeEntitlementWeeks);

            var relevantDismissalDate = await data.DismissalDate.GetRelevantDismissalDate(projectedNoticeDate);

            var statutoryMax = ConfigValueLookupHelper.GetStatutoryMax(options, relevantDismissalDate);

            var totalYearsOfService = await adjStartDate.GetServiceYearsAsync(relevantDismissalDate);

            //limit maximum service years to 20
            if (totalYearsOfService > 20)
            {
                totalYearsOfService = 20;
            }

            var appliedRateOfPay = Math.Min(statutoryMax, data.WeeklyWage);

            int yearsOfServiceUpto21 = 0, yearsOfService22To41 = 0;

            var yearsOfServiceOver41 = await data.DateOfBirth.GetYearsOfServiceOver41(adjStartDate, relevantDismissalDate);

            if (yearsOfServiceOver41 < totalYearsOfService)
            {
                yearsOfService22To41 = await data.DateOfBirth.GetYearsOfServiceFrom22To41(adjStartDate, relevantDismissalDate);

                if (yearsOfServiceOver41 + yearsOfService22To41 > totalYearsOfService)
                {
                    yearsOfService22To41 = totalYearsOfService - yearsOfServiceOver41;
                }
            }
            if (yearsOfServiceOver41 + yearsOfService22To41 < totalYearsOfService)
            {
                yearsOfServiceUpto21 = totalYearsOfService - (yearsOfService22To41 + yearsOfServiceOver41);
            }

            var redundancyPayWeeks = decimal.Multiply(yearsOfServiceUpto21, 0.5m) + yearsOfService22To41 + decimal.Multiply(yearsOfServiceOver41, 1.5m);
            var grossEntitlement   = redundancyPayWeeks * appliedRateOfPay;

            var grossEntitlementFinal    = Math.Max(0m, Math.Round(grossEntitlement, 2));
            var employerPartPaymentFinal = Math.Round(data.EmployerPartPayment, 2);
            var netEntitlementFinal      = Math.Max(0m, (grossEntitlementFinal - employerPartPaymentFinal));

            calculationResult.AdjEmploymentStartDate     = adjStartDate;
            calculationResult.NoticeDateForRedundancyPay = relevantDismissalDate;
            calculationResult.NoticeEntitlementWeeks     = noticeEntitlementWeeks;
            calculationResult.RedundancyPayWeeks         = Math.Round(redundancyPayWeeks, 4);
            calculationResult.YearsOfServiceUpto21       = yearsOfServiceUpto21;
            calculationResult.YearsOfServiceFrom22To41   = yearsOfService22To41;
            calculationResult.YearsServiceOver41         = yearsOfServiceOver41;
            //calculationResult.GrossEntitlement = grossEntitlementFinal;
            calculationResult.GrossEntitlement     = netEntitlementFinal; //TEMP CHANGE: Gross entitlement set to Net entitlement as quick fix for CMS message to BW
            calculationResult.EmployerPartPayment  = employerPartPaymentFinal;
            calculationResult.NetEntitlement       = netEntitlementFinal;
            calculationResult.PreferentialClaim    = 0m;
            calculationResult.NonPreferentialClaim = netEntitlementFinal;
            calculationResult.StatutoryMax         = statutoryMax;

            return(calculationResult);
        }