private static void PopulateRecoveryMovementType(TransactionContext transactionContext, DeductibleDefinition definition, string productCode, IBusinessComponent context) { string movementType; if (definition.FundedMovementType != null && ClaimsBusinessLogicHelper.TryGetRecoveryReserveMovementType(transactionContext, definition.FundedMovementType, productCode, context, out movementType)) { definition.RecoveryFundedMovementType = movementType; } if (definition.FundedMovementType != null && ClaimsBusinessLogicHelper.TryGetRecoveryReserveMovementType(transactionContext, definition.FundedMovementType, productCode, context, out movementType)) { definition.RecoveryNonFundedMovementType = movementType; } }
/// <summary> /// Add new claim transaction detail for the new deductible. If payment/resere then stored as +ve if recovery reserve stored as -ve /// </summary> /// <param name="claimTransactionGroup">claim transaction group to attach to</param> /// <param name="amountType">amount type</param> /// <param name="deductibleDefinition">deductible definition containing deductible movement type</param> /// <param name="amount">deductible amount</param> /// <param name="latestNonFundedReserve">latest reserve if any</param> /// <returns>Amount s</returns> private static decimal AddClaimTransactionDetails(DateTime transactionDate, ClaimTransactionGroup claimTransactionGroup, StaticValues.AmountType amountType, DeductibleDefinition deductibleDefinition, decimal amount, ClaimFinancialAmount latestNonFundedReserve = null) { decimal convertedAmount; if (claimTransactionGroup.ClaimCurrencyCode != claimTransactionGroup.OriginalCurrencyCode) { convertedAmount = ClaimsBusinessLogicHelper.ConvertCurrencyAmount(claimTransactionGroup.ClaimTransactionHeader, amount, claimTransactionGroup.ClaimCurrencyCode, claimTransactionGroup.OriginalCurrencyCode); } else { convertedAmount = amount; } string fundedMovementType, nonFundedMovementType; if (amountType == StaticValues.AmountType.RecoveryReserve) { convertedAmount = -convertedAmount; fundedMovementType = deductibleDefinition.RecoveryFundedMovementType; nonFundedMovementType = deductibleDefinition.RecoveryNonFundedMovementType; } else { fundedMovementType = deductibleDefinition.FundedMovementType; nonFundedMovementType = deductibleDefinition.NonFundedMovementType; } short? reserveDaySequence = null; if (amountType == StaticValues.AmountType.Reserve || amountType == StaticValues.AmountType.RecoveryReserve) { reserveDaySequence = (short)(latestNonFundedReserve == null ? 10 : latestNonFundedReserve.ReserveDaySequence.GetValueOrDefault(0) + 10); } var claimTransactionDetail = claimTransactionGroup.AddNewClaimTransactionDetail((short)amountType, nonFundedMovementType); PopulateClaimTransactionDetail(claimTransactionDetail, convertedAmount, -Math.Abs(convertedAmount), transactionDate, reserveDaySequence, amountType); List<FlattenedTransaction> flattenedTransactions; if (GlobalClaimWakeUp.MappedTransactionDetails.TryGetValue(claimTransactionGroup.ClaimTransactionHeader.ClaimHeader.ClaimReference, out flattenedTransactions)) { flattenedTransactions.Add(Mapper.Map<ClaimTransactionDetail, FlattenedTransaction>(claimTransactionDetail)); } if (fundedMovementType != null) { claimTransactionDetail = claimTransactionGroup.AddNewClaimTransactionDetail((short)amountType, fundedMovementType); PopulateClaimTransactionDetail(claimTransactionDetail, -convertedAmount, Math.Abs(convertedAmount), transactionDate, reserveDaySequence, amountType); if (GlobalClaimWakeUp.MappedTransactionDetails.TryGetValue(claimTransactionGroup.ClaimTransactionHeader.ClaimHeader.ClaimReference, out flattenedTransactions)) { flattenedTransactions.Add(Mapper.Map<ClaimTransactionDetail, FlattenedTransaction>(claimTransactionDetail)); } } return amount; }
private static void CreateDeductibleDefinitionIfEnabled(TransactionContext transactionContext, bool isClaimDetailLevelDeductible, List<DeductibleDefinition> deductibles, decimal? amount, bool? isDeductiblePaidByInsurer, string nonFundedMovementType, string fundedMovementType, string productCode, IBusinessComponent context) { if (!amount.HasValue) { return; } var deductibleDefinition = new DeductibleDefinition { Amount = amount.Value, NonFundedMovementType = nonFundedMovementType }; deductibleDefinition.IsClaimDetailDeductible = isClaimDetailLevelDeductible; if (isDeductiblePaidByInsurer.GetValueOrDefault(false)) { if (string.IsNullOrEmpty(fundedMovementType)) { throw new InvalidOperationException(MessageServiceFactory.GetMessageBody(MessageConstants.NoFundedMovementType, nonFundedMovementType)); } deductibleDefinition.FundedMovementType = fundedMovementType; } PopulateRecoveryMovementType(transactionContext, deductibleDefinition, productCode, context); deductibles.Add(deductibleDefinition); }
private static decimal AddReserve(decimal amount, FinancialTransactionContext financialContext, ClaimDetail claimDetail, ClaimTransactionGroup claimTransactionGroup, DeductibleDefinition deductibleDefinition, DeductibleReserveCapacity deductibleReserveContext, ClaimFinancialAmount latestReserve = null) { StaticValues.AmountType amountType; string nonFundedMovementType; if (IsRecovery(financialContext.TransactionSource)) { amountType = StaticValues.AmountType.RecoveryReserve; nonFundedMovementType = deductibleDefinition.RecoveryNonFundedMovementType; } else { amountType = StaticValues.AmountType.Reserve; nonFundedMovementType = deductibleDefinition.NonFundedMovementType; } if (latestReserve == null) { if (amount > 0) { AddClaimTransactionDetails(financialContext.ClaimTransactionHeader.TransactionDate.GetValueOrDefault(DateTime.MinValue), claimTransactionGroup, amountType, deductibleDefinition, amount, latestReserve); deductibleReserveContext.AdjustDeductibleAttached(claimDetail.ClaimDetailReference, nonFundedMovementType, amount); } else { amount = 0; } } else if (amount != Math.Abs(latestReserve.TransactionAmountClaimCurrency.GetValueOrDefault(0))) { AddClaimTransactionDetails(financialContext.ClaimTransactionHeader.TransactionDate.GetValueOrDefault(DateTime.MinValue), claimTransactionGroup, amountType, deductibleDefinition, amount, latestReserve); deductibleReserveContext.AdjustDeductibleAttached(claimDetail.ClaimDetailReference, nonFundedMovementType, amount + latestReserve.TransactionAmountClaimCurrency.GetValueOrDefault()); } return amount; }
private static DeductibleResult ApplyDeductibleReserveAdjustments(string movementType, DeductibleDefinition deductibleDefinition, DeductibleReserveCapacity deductibleReserveContext, FinancialTransactionContext financialContext, IEnumerable<ClaimFinancialAmount> reserves, ClaimFinancialAmount latestReserve, decimal reserveAdjustment) { string claimDetailRef = financialContext.ClaimDetail.ClaimDetailReference; decimal incurredTotal = deductibleReserveContext.ResolveCapacity(claimDetailRef); decimal revisedAmount = Math.Max(Math.Min(incurredTotal, reserveAdjustment), 0); // if it's a recovery receipt transaction and there is reserve adjustment, stop. if (IsRecovery(financialContext.TransactionSource) && movementType == deductibleDefinition.NonFundedMovementType && ((latestReserve == null && reserveAdjustment != 0) || (latestReserve != null && reserveAdjustment != latestReserve.TransactionAmountClaimCurrency))) { return new DeductibleResult { Success = false, Message = MessageConstants.RecoveryReservesRequireManualReview }; } reserveAdjustment -= AddReserve(revisedAmount, financialContext, financialContext.ClaimDetail, financialContext.ClaimTransactionGroup, deductibleDefinition, deductibleReserveContext, latestReserve); // if the reserve adjustment couldn't be absorbed by the current claim detail apply accross the claim if (reserveAdjustment != 0 && !deductibleDefinition.IsClaimDetailDeductible) { // don't process if currencies aren't all the same if (!AreReservesInSameCurrency(reserves, movementType)) { return new DeductibleResult { Success = false, Message = MessageConstants.ReservesRequireManualReview }; } var reservesForMovementType = reserves.Where(a => a.MovementType == movementType); var claimDetails = from claimDetail in financialContext.ClaimHeader.ClaimDetails join reserve in reservesForMovementType on claimDetail.ClaimDetailReference equals reserve.ClaimDetailReference into cr from groupData in cr.DefaultIfEmpty() where claimDetail.ClaimDetailReference != claimDetailRef orderby groupData != null ? Math.Abs(groupData.TransactionAmountClaimCurrency.GetValueOrDefault()) : 0 descending select claimDetail; foreach (var claimDetail in claimDetails) { incurredTotal = deductibleReserveContext.ResolveCapacity(claimDetail.ClaimDetailReference); ClaimFinancialAmount remainingAmount = reserves.SingleOrDefault(a => a.ClaimDetailReference == claimDetail.ClaimDetailReference && a.MovementType == movementType); decimal remainingAbsAmount = remainingAmount != null ? Math.Abs(remainingAmount.TransactionAmountClaimCurrency.GetValueOrDefault()) : 0; revisedAmount = Math.Max(Math.Min(incurredTotal, remainingAbsAmount + reserveAdjustment), 0); var newClaimTransactionGroup = ResolveClaimTransactionGroup(financialContext.ClaimTransactionHeader, financialContext.ClaimTransactionGroup, claimDetail); revisedAmount = AddReserve(revisedAmount, financialContext, claimDetail, newClaimTransactionGroup, deductibleDefinition, deductibleReserveContext, remainingAmount); reserveAdjustment -= revisedAmount - remainingAbsAmount; if (reserveAdjustment == 0) { break; } } } return new DeductibleResult { Success = true }; }
private static decimal CalculateDeductibleRecoveryReserves(DeductibleDefinition deductibleDefinition, ClaimFinancialAmount latestRecoveryReserve, decimal totalIncurred, decimal totalRecoveryIncurred, decimal sumOfLowerDeductibles, IEnumerable<ClaimFinancialAmount> recoveryReserves) { string deductibleMovementType = deductibleDefinition.RecoveryNonFundedMovementType; decimal deductibleAmount = deductibleDefinition.Amount; // supersede latest if entering a new reserve if (latestRecoveryReserve != null) { recoveryReserves = recoveryReserves.Except(new[] { latestRecoveryReserve }); } decimal sumOfDeductibleReserves = -CalculateSum(recoveryReserves, deductibleMovementType); decimal deductibleTotalIncurred = Math.Min(deductibleAmount, Math.Max(totalIncurred - sumOfLowerDeductibles, 0)); decimal deductibleTotalRecoveryIncurred = Math.Min(deductibleAmount, Math.Max(totalRecoveryIncurred - sumOfLowerDeductibles, 0)); decimal deductibleTotalRecoveryReserve = deductibleTotalRecoveryIncurred - deductibleTotalIncurred; decimal deductibleRecoveryReserve = deductibleTotalRecoveryReserve - sumOfDeductibleReserves; return deductibleRecoveryReserve; }
private static decimal CalculateDeductiblePayment(DeductibleDefinition deductibleDefinition, decimal totalPaid, decimal sumOfLowerDeductibles, IEnumerable<ClaimFinancialAmount> payments) { string deductibleMovementType = deductibleDefinition.NonFundedMovementType; decimal deductibleAmount = deductibleDefinition.Amount; decimal deductiblePaidToDate = -CalculateSum(payments, deductibleMovementType); // calculate payments decimal deductibleTotalPaid = Math.Min(deductibleAmount, Math.Max(totalPaid - sumOfLowerDeductibles, 0)); decimal deductiblePaid = deductibleTotalPaid - deductiblePaidToDate; return deductiblePaid; }