private static void PrepareCareChargesModel(CareChargesCreateDomain request, CarePackage package) { foreach (var careCharge in request.CareCharges) { careCharge.CarePackageId = package.Id; } var coreCost = package.GetCoreCostDetail(); // Limit ongoing charges if package interval is finite request.CareCharges = request.CareCharges.OrderBy(cc => cc.SubType).ToList(); if (request.CareCharges.Last().EndDate is null && coreCost.EndDate != null) { request.CareCharges.Last().EndDate = coreCost.EndDate; } // if requested 1-12 charge covers period of provisional charge, 1-12 will replace provisional var provisionalCharge = request.CareCharges.SingleOrDefault(cc => cc.SubType is ReclaimSubType.CareChargeProvisional); var first12WeeksCharge = request.CareCharges.SingleOrDefault(cc => cc.SubType is ReclaimSubType.CareCharge1To12Weeks); if (first12WeeksCharge != null && first12WeeksCharge.StartDate.Date <= provisionalCharge?.StartDate.Date) { provisionalCharge.Status = ReclaimStatus.Cancelled; } }
private void ReplaceUpdatedCareCharges(CareChargesCreateDomain request, CarePackage package) { foreach (var requestedCharge in request.CareCharges) { // if existing charge date / cost / collector is changed, cancel it and create a new one instead. if (!requestedCharge.Id.IsEmpty()) { var existingCharge = package.Reclaims.Single(cc => cc.Id == requestedCharge.Id); if (CareChargeHasChanged(existingCharge, requestedCharge) && requestedCharge.Status != ReclaimStatus.Cancelled) { existingCharge.Status = ReclaimStatus.Cancelled; requestedCharge.Id = null; package.Reclaims.Add(requestedCharge.ToEntity()); } else { _mapper.Map(requestedCharge, existingCharge); } } else { package.Reclaims.Add(requestedCharge.ToEntity()); } } }
private void VerifyFailedRequest(CareChargesCreateDomain request, string message) { _useCase .Invoking(async useCase => await useCase.ExecuteAsync(_package.Id, request)) .Should().Throw <ApiException>() .Where(ex => ex.Message.Contains(message)); _dbManager.Verify(db => db.SaveAsync(It.IsAny <string>()), Times.Never); }
private static void ValidateCareChargesModel(CareChargesCreateDomain request, CarePackage package) { Debug.Assert(ReclaimSubType.CareChargeProvisional == ReclaimSubType.CareCharge1To12Weeks - 1); Debug.Assert(ReclaimSubType.CareCharge1To12Weeks == ReclaimSubType.CareCharge13PlusWeeks - 1); var coreCost = package.GetCoreCostDetail(); var requestedCareCharges = request.CareCharges .Where(c => c.Status != ReclaimStatus.Cancelled) .OrderBy(c => c.SubType).ToList(); // Care charges should follow each other without gaps for (var i = 1; i < requestedCareCharges.Count; i++) { var currentCharge = requestedCareCharges[i]; var previousCharge = requestedCareCharges[i - 1]; if (!package.IsMigrated && currentCharge.SubType != previousCharge.SubType + 1) { throw new ApiException($"{GetShortName(previousCharge.SubType)} care charge must be followed by" + $" {GetShortName(previousCharge.SubType + 1)}", HttpStatusCode.BadRequest); } var expectedEndDate = currentCharge.StartDate.Date.AddDays(-1); if (previousCharge.EndDate is null) { throw new ApiException($"{GetShortName(previousCharge.SubType)} care charge must have an end date one day before " + $"{GetShortName(currentCharge.SubType)} start: {expectedEndDate:yyy-MM-dd}", HttpStatusCode.BadRequest); } var expectedStartDate = previousCharge.EndDate.Value.Date.AddDays(1); if (currentCharge.StartDate.Date != expectedStartDate) { throw new ApiException($"{GetShortName(currentCharge.SubType)} care charge must start one day after " + $"{GetShortName(previousCharge.SubType)} care charge end: {expectedStartDate:yyy-MM-dd}", HttpStatusCode.BadRequest); } } // First care charge must be started at package start date if (requestedCareCharges.First()?.StartDate.Date < coreCost.StartDate.Date) { throw new ApiException("First care charge start date must be greater or equal to package start date " + $"{coreCost.StartDate:yyyy-MM-dd}", HttpStatusCode.BadRequest); } // Last care charge end date must not exceed package end date (if any) if (coreCost.EndDate.HasValue && requestedCareCharges.Last().EndDate?.Date > coreCost.EndDate.Value.Date) { throw new ApiException("Last care charge end date expected to be less than or equal " + $"to {coreCost.EndDate.Value:yyyy-MM-dd}", HttpStatusCode.BadRequest); } ValidateCareChargeBounds(requestedCareCharges); }
private static void ValidateRequestIntegrity(CareChargesCreateDomain request, CarePackage package) { var existingCareCharges = package.Reclaims .Where(r => r.Type is ReclaimType.CareCharge && r.Status.In(ReclaimStatus.Pending, ReclaimStatus.Active, ReclaimStatus.Ended)) .ToList(); // each existing care charge should be presented in upsert request var missedCareCharges = existingCareCharges .Where(existingCharge => !request.CareCharges.Any( requestedCharge => requestedCharge.SubType == existingCharge.SubType && requestedCharge.Id == existingCharge.Id)) .Select(existingCareCharge => GetShortName(existingCareCharge.SubType)) .ToList(); if (missedCareCharges.Count > 0) { throw new ApiException($"Care charges {String.Join(", ", missedCareCharges)} " + "must present in the request with valid Id", HttpStatusCode.BadRequest); } // each requested care charge with non-empty Id should have matching DB record var unknownCareCharges = request.CareCharges .Where(requestedCharge => !requestedCharge.Id.IsEmpty() && !existingCareCharges.Any(existingCharge => existingCharge.Id == requestedCharge.Id)) .Select(requestedCharge => requestedCharge.Id) .ToList(); if (unknownCareCharges.Count > 0) { throw new ApiException($"Care charges {String.Join(", ", unknownCareCharges)} not found", HttpStatusCode.BadRequest); } // each care charge sub-type must have only one entry var duplicatedSubtypes = request.CareCharges .GroupBy(careCharge => careCharge.SubType) .Where(group => group.Count() > 1) .Select(group => group.Key.GetDisplayName()) .ToList(); if (duplicatedSubtypes.Count > 0) { throw new ApiException("Not allowed to have more than one " + $"{String.Join(", ", duplicatedSubtypes)} in request", HttpStatusCode.BadRequest); } }
public async Task ExecuteAsync(Guid carePackageId, CareChargesCreateDomain request) { // Get package with all reclaims var package = await _carePackageGateway .GetPackageAsync(carePackageId, PackageFields.Settings | PackageFields.Details | PackageFields.Reclaims, true) .EnsureExistsAsync($"Care package with id {carePackageId} not found"); ValidatePackage(package); ValidateRequestIntegrity(request, package); // ensure existing reclaims match requested // since validating raw request is tricky, first build a model of ordered charges // and then validate them to be in package date range and followed each other without any gaps PrepareCareChargesModel(request, package); ValidateCareChargesModel(request, package); // if care charge has date / cost / collector changed, cancel existing one and replace it with new. ReplaceUpdatedCareCharges(request, package); ReclaimCostValidator.Validate(package); await _dbManager.SaveAsync(); }
public static CareChargesCreationRequest ToionRequest(this CareChargesCreateDomain input) { return(_mapper.Map <CareChargesCreationRequest>(input)); }