private static OCurrency CalculateNonRepaymentPenalties(Loan pContract, DateTime pDate, int installmentNumber,
            OLateRepaymentTypes repaymentType, ApplicationSettings pGeneralSettings, NonWorkingDateSingleton pNonWorkingDate)
        {
            Installment installment = pContract.GetInstallment(installmentNumber - 1);

            DateTime date = installment.ExpectedDate;

            // Calulating of fee in case of previous installment's fee is written off
            if (installment.PaidCapital + installment.PaidInterests > 0 && installment.PaidFees == 0 && installment.FeesUnpaid > 0)
            {
                if (pDate < installment.ExpectedDate)
                    date = pDate;
                else
                {
                    var last = pContract.InstallmentList.FindLast(i => i.PaidDate != null);
                    if (last != null && last.PaidDate != null) date = last.PaidDate.Value;
                }
            }
            //

            foreach (RepaymentEvent rPayment in pContract.Events.GetRepaymentEvents())
            {
                if (rPayment.Date == pDate && rPayment.Deleted == false && installmentNumber == rPayment.InstallmentNumber)
                {
                    date = pDate;
                }

                if (rPayment.InstallmentNumber <= installment.Number && rPayment.Deleted == false && rPayment.Date != pDate && pDate > installment.ExpectedDate && installment.PaidFees != 0)
                {
                    date = rPayment.Date <= installment.ExpectedDate ? installment.ExpectedDate : rPayment.Date;
                }
            }

            int nbOfDays = (pDate - date).Days < 0 ? 0 : (pDate - date).Days;
            nbOfDays = nbOfDays - CountDaysOff(date, pDate, pGeneralSettings, pNonWorkingDate);
            nbOfDays = _CalculatePastDueWithGeneralParameterForRepayment(nbOfDays, pGeneralSettings);

            if (pContract.GracePeriodOfLateFees >= nbOfDays)
            {
                nbOfDays = 0;
            }

            double penalties;
            OCurrency amountHasToPay;

            if (repaymentType == OLateRepaymentTypes.Principal)
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }
            else if (repaymentType == OLateRepaymentTypes.Interest)
            {
                amountHasToPay = installment.InterestHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDueInterest;
            }
            else if (repaymentType == OLateRepaymentTypes.Olb)
            {
                amountHasToPay = installment.OLB - installment.PaidCapital;
                penalties = pContract.NonRepaymentPenalties.OLB;
            }
            else if (repaymentType == OLateRepaymentTypes.Amount)
            {
                amountHasToPay = installment.Amount;
                penalties = pContract.NonRepaymentPenalties.InitialAmount;
            }
            else // Fixed method of late repayments for future implementation; Principal is set for now
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }

            decimal amount = amountHasToPay.Value * Convert.ToDecimal(penalties) * nbOfDays;
            amount = pContract.UseCents ? Math.Round(amount, 2, MidpointRounding.AwayFromZero) : Math.Round(amount, 0, MidpointRounding.AwayFromZero);

            if (pContract.WrittenOff && pGeneralSettings.IsStopWriteOffPenalty)
                amount = 0;
            return amount;
        }
        private static OCurrency _CalculateNonRepaymentPenaltiesForClosure(Loan pContract, DateTime pDate, int pInstallmentNumber,
            OLateRepaymentTypes repaymentType, ApplicationSettings pGeneralSettings, NonWorkingDateSingleton pNonWorkingDate)
        {
            Installment installment = pContract.GetInstallment(pInstallmentNumber - 1);
            if (pDate <= installment.ExpectedDate) return 0;
            
            DateTime baseDate = DateTime.MinValue;

            DateTime dateForInstallment = installment.PaidDate.HasValue ? installment.PaidDate.Value : installment.ExpectedDate;

            if (baseDate == DateTime.MinValue)
            {
                baseDate = dateForInstallment;
            }
            else
            {
                if (baseDate < dateForInstallment)
                    baseDate = dateForInstallment;
            }

            int pstDueDays = (pDate - baseDate).Days < 0 ? 0 : (pDate - baseDate).Days;
            pstDueDays = pstDueDays - CountDaysOff(baseDate, pDate, pGeneralSettings, pNonWorkingDate);
            
            if(pContract.GracePeriodOfLateFees >= pstDueDays)
            {
                pstDueDays = 0;
            }

            double penalties;
            OCurrency amountHasToPay;

            if (repaymentType == OLateRepaymentTypes.Principal)
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }
            else if (repaymentType == OLateRepaymentTypes.Interest)
            {
                amountHasToPay = installment.InterestHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDueInterest;
            }
            else if (repaymentType == OLateRepaymentTypes.Olb)
            {
                amountHasToPay = installment.OLB;
                penalties = pContract.NonRepaymentPenalties.OLB;
            }
            else if (repaymentType == OLateRepaymentTypes.Amount)
            {
                amountHasToPay = installment.Amount;
                penalties = pContract.NonRepaymentPenalties.InitialAmount;
            }
            else // Fixed method of late repayments for future implementation; Principal is set for now
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }

            return amountHasToPay * penalties * pstDueDays;
        }
        private static OCurrency CalculateNonRepaymentPenalties(Loan pContract, DateTime pDate, int installmentNumber,
                                                                OLateRepaymentTypes repaymentType, ApplicationSettings pGeneralSettings, NonWorkingDateSingleton pNonWorkingDate)
        {
            Installment installment = pContract.GetInstallment(installmentNumber - 1);

            DateTime date = installment.ExpectedDate;

            // Calulating of fee in case of previous installment's fee is written off
            if (installment.PaidCapital + installment.PaidInterests > 0 && installment.PaidFees == 0 && installment.FeesUnpaid > 0)
            {
                if (pDate < installment.ExpectedDate)
                {
                    date = pDate;
                }
                else
                {
                    var last = pContract.InstallmentList.FindLast(i => i.PaidDate != null);
                    if (last != null && last.PaidDate != null)
                    {
                        date = last.PaidDate.Value;
                    }
                }
            }
            //

            foreach (RepaymentEvent rPayment in pContract.Events.GetRepaymentEvents())
            {
                if (rPayment.Date == pDate && rPayment.Deleted == false && installmentNumber == rPayment.InstallmentNumber)
                {
                    date = pDate;
                }

                if (rPayment.InstallmentNumber <= installment.Number && rPayment.Deleted == false && rPayment.Date != pDate && pDate > installment.ExpectedDate && installment.PaidFees != 0)
                {
                    date = rPayment.Date <= installment.ExpectedDate ? installment.ExpectedDate : rPayment.Date;
                }
            }

            int nbOfDays = (pDate - date).Days < 0 ? 0 : (pDate - date).Days;

            nbOfDays = nbOfDays - CountDaysOff(date, pDate, pGeneralSettings, pNonWorkingDate);
            nbOfDays = _CalculatePastDueWithGeneralParameterForRepayment(nbOfDays, pGeneralSettings);

            if (pContract.GracePeriodOfLateFees >= nbOfDays)
            {
                nbOfDays = 0;
            }

            double    penalties;
            OCurrency amountHasToPay;

            if (repaymentType == OLateRepaymentTypes.Principal)
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }
            else if (repaymentType == OLateRepaymentTypes.Interest)
            {
                amountHasToPay = installment.InterestHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDueInterest;
            }
            else if (repaymentType == OLateRepaymentTypes.Olb)
            {
                amountHasToPay = installment.OLB - installment.PaidCapital;
                penalties      = pContract.NonRepaymentPenalties.OLB;
            }
            else if (repaymentType == OLateRepaymentTypes.Amount)
            {
                amountHasToPay = installment.Amount;
                penalties      = pContract.NonRepaymentPenalties.InitialAmount;
            }
            else // Fixed method of late repayments for future implementation; Principal is set for now
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }

            decimal amount = amountHasToPay.Value * Convert.ToDecimal(penalties) * nbOfDays;

            amount = pContract.UseCents ? Math.Round(amount, 2, MidpointRounding.AwayFromZero) : Math.Round(amount, 0, MidpointRounding.AwayFromZero);

            if (pContract.WrittenOff && pGeneralSettings.IsStopWriteOffPenalty)
            {
                amount = 0;
            }
            return(amount);
        }
        private static OCurrency _CalculateNonRepaymentPenalties(Loan pContract, DateTime pDate, int installmentNumber,
            OLateRepaymentTypes repaymentType, ApplicationSettings pGeneralSettings, NonWorkingDateSingleton pNonWorkingDate)
        {
            Installment installment = pContract.GetInstallment(installmentNumber - 1);

            DateTime date = installment.ExpectedDate;

            foreach (RepaymentEvent rPayment in pContract.Events.GetRepaymentEvents())
            {
                if (rPayment.Date == pDate && rPayment.Deleted == false && installmentNumber == rPayment.InstallmentNumber)
                {
                    date = pDate;
                }

                if (rPayment.InstallmentNumber <= installment.Number && rPayment.Deleted == false && rPayment.Date != pDate && pDate > installment.ExpectedDate && installment.PaidFees != 0)
                {
                    date = rPayment.Date <= installment.ExpectedDate ? installment.ExpectedDate : rPayment.Date;
                }
            }

            int nbOfDays = (pDate - date).Days < 0 ? 0 : (pDate - date).Days;
            nbOfDays = nbOfDays - CountDaysOff(date, pDate, pGeneralSettings, pNonWorkingDate);
            nbOfDays = _CalculatePastDueWithGeneralParameterForRepayment(nbOfDays, pGeneralSettings);

            if (pContract.GracePeriodOfLateFees >= nbOfDays)
            {
                nbOfDays = 0;
            }

            double penalties;
            OCurrency amountHasToPay;

            if (repaymentType == OLateRepaymentTypes.Principal)
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }
            else if (repaymentType == OLateRepaymentTypes.Interest)
            {
                amountHasToPay = installment.InterestHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDueInterest;
            }
            else if (repaymentType == OLateRepaymentTypes.Olb)
            {
                amountHasToPay = installment.OLB;
                penalties = pContract.NonRepaymentPenalties.OLB;
            }
            else if (repaymentType == OLateRepaymentTypes.Amount)
            {
                amountHasToPay = installment.Amount;
                penalties = pContract.NonRepaymentPenalties.InitialAmount;
            }
            else // Fixed method of late repayments for future implementation; Principal is set for now
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }

            return amountHasToPay * penalties * nbOfDays;
        }
        private static OCurrency _CalculateNonRepaymentPenaltiesForClosure(Loan pContract, DateTime pDate, int pInstallmentNumber,
                                                                           OLateRepaymentTypes repaymentType, ApplicationSettings pGeneralSettings, NonWorkingDateSingleton pNonWorkingDate)
        {
            Installment installment = pContract.GetInstallment(pInstallmentNumber - 1);

            if (pDate <= installment.ExpectedDate)
            {
                return(0);
            }

            DateTime baseDate = DateTime.MinValue;

            DateTime dateForInstallment = installment.PaidDate.HasValue ? installment.PaidDate.Value : installment.ExpectedDate;

            if (baseDate == DateTime.MinValue)
            {
                baseDate = dateForInstallment;
            }
            else
            {
                if (baseDate < dateForInstallment)
                {
                    baseDate = dateForInstallment;
                }
            }

            int pstDueDays = (pDate - baseDate).Days < 0 ? 0 : (pDate - baseDate).Days;

            pstDueDays = pstDueDays - CountDaysOff(baseDate, pDate, pGeneralSettings, pNonWorkingDate);

            if (pContract.GracePeriodOfLateFees >= pstDueDays)
            {
                pstDueDays = 0;
            }

            double    penalties;
            OCurrency amountHasToPay;

            if (repaymentType == OLateRepaymentTypes.Principal)
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }
            else if (repaymentType == OLateRepaymentTypes.Interest)
            {
                amountHasToPay = installment.InterestHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDueInterest;
            }
            else if (repaymentType == OLateRepaymentTypes.Olb)
            {
                amountHasToPay = installment.OLB;
                penalties      = pContract.NonRepaymentPenalties.OLB;
            }
            else if (repaymentType == OLateRepaymentTypes.Amount)
            {
                amountHasToPay = installment.Amount;
                penalties      = pContract.NonRepaymentPenalties.InitialAmount;
            }
            else // Fixed method of late repayments for future implementation; Principal is set for now
            {
                amountHasToPay = installment.PrincipalHasToPay;
                penalties      = pContract.NonRepaymentPenalties.OverDuePrincipal;
            }

            return(amountHasToPay * penalties * pstDueDays);
        }