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;
        }