Пример #1
0
        public void RepeatedDatesWithAmountAndInterestTest_FirstRepayDay()
        {
            RepeatDatesWithAmountAndInterestCalInput vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipal,
                InterestFreeLoan = true,
                StartDate        = new DateTime(2020, 1, 10),
                TotalAmount      = 120000,
                EndDate          = new DateTime(2021, 1, 10),
                TotalMonths      = 12,
                FirstRepayDate   = new DateTime(2020, 2, 15)
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            Assert.Equal(12, results.Count);

            var realdate = results[0].TranDate;

            Assert.Equal(2020, realdate.Year);
            Assert.Equal(2, realdate.Month);
            Assert.Equal(15, realdate.Day);

            foreach (var rst in results)
            {
                Assert.Equal(10000, rst.TranAmount);
                Assert.True(rst.InterestAmount == 0);
            }
        }
Пример #2
0
        public void RepeatedDatesWithAmountAndInterestTest_EqualCEx(Decimal totalAmount, Decimal interestRate)
        {
            var vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = new DateTime(2020, 1, 1),
                TotalAmount      = totalAmount,
                TotalMonths      = 12,
                InterestRate     = interestRate,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipal
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            var     idx      = 0;
            Decimal amtTotal = 0;

            foreach (var rst in results)
            {
                if (idx == 0)
                {
                    //Assert.True(Math.Abs(4166.71M - rst.TranAmount) <= 0.01M);
                }
                else
                {
                    Assert.True(Math.Abs(4166.67M - rst.TranAmount) <= 0.01M);
                }
                idx++;
                amtTotal += rst.TranAmount;
            }

            Assert.True(Math.Abs(amtTotal - totalAmount) <= 0.01M);
        }
Пример #3
0
        public IActionResult GetRepeatedDatesWithAmountAndInterest([FromBody] RepeatDatesWithAmountAndInterestCalInput input)
        {
            if (!ModelState.IsValid)
            {
                HIHAPIUtility.HandleModalStateError(ModelState);
            }

            return(Ok(CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(input)));
        }
Пример #4
0
        public void RepeatedDatesWithAmountAndInterestTest_InterestFreeAndDue()
        {
            RepeatDatesWithAmountAndInterestCalInput vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                RepaymentMethod  = LoanRepaymentMethod.DueRepayment,
                InterestFreeLoan = true,
                StartDate        = new DateTime(2020, 1, 1),
                TotalAmount      = 120000,
                EndDate          = new DateTime(2021, 1, 1)
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            Assert.True(1 == results.Count);
            Assert.Equal(2021, results[0].TranDate.Year);
            Assert.Equal(120000, results[0].TranAmount);
        }
Пример #5
0
        public void RepeatedDatesWithAmountAndInterestTest_DueRepayment()
        {
            var vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = new DateTime(2020, 1, 1),
                TotalAmount      = 100000,
                EndDate          = new DateTime(2021, 1, 1),
                InterestRate     = 0.0435M,
                RepaymentMethod  = LoanRepaymentMethod.DueRepayment
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            Assert.Equal <Decimal>(100000M, results[0].TranAmount);
            Assert.Equal <Decimal>(4350M, results[0].InterestAmount);
        }
Пример #6
0
        public void RepeatedDatesWithAmountAndInterestTest_EqualCAndIAndFirstRepayDay()
        {
            RepeatDatesWithAmountAndInterestCalInput vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = new DateTime(2020, 8, 23),
                TotalAmount      = 2680000,
                TotalMonths      = 360,
                InterestRate     = 0.0441M,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipalAndInterset,
                FirstRepayDate   = new DateTime(2020, 10, 1)
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            Assert.Equal(360, results.Count);

            var realdate = results[0].TranDate;

            Assert.Equal(2020, realdate.Year);
            Assert.Equal(10, realdate.Month);
            Assert.Equal(1, realdate.Day);
            Assert.True(Math.Abs(16062.66M - results[0].TotalAmount) <= 0.01M); // Rounding
        }
Пример #7
0
        public void RepeatedDatesWithAmountAndInterestTest_EqualCAndI()
        {
            var vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = new DateTime(2020, 1, 1),
                TotalAmount      = 100000,
                TotalMonths      = 12,
                InterestRate     = 0.0435M,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipalAndInterset
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            //1   8530.99 8168.50 362.50  91831.51
            Assert.True(Math.Abs(8168.50M - results[0].TranAmount) <= 0.01M);
            //Assert.Equal(8168.50M, results[0].TranAmount);
            Assert.True(Math.Abs(362.50M - results[0].InterestAmount) <= 0.01M);
            //Assert.Equal(362.50M, results[0].InterestAmount);
            Assert.True(Math.Abs(8530.99M - (results[0].TranAmount + results[0].InterestAmount)) <= 0.01M);

            //2   8530.99 8198.11 332.89  83633.41
            //Assert.Equal(8198.11M, results[1].TranAmount);
            //Assert.Equal(332.89M, results[1].InterestAmount);
            Assert.True(Math.Abs(8198.11M - results[1].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(332.89M - results[1].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[1].TranAmount + results[1].InterestAmount)) <= 0.01M);

            //3   8530.99 8227.82 303.17  75405.59
            //Assert.Equal(8227.82M, results[2].TranAmount);
            //Assert.Equal(303.17M, results[2].InterestAmount);
            Assert.True(Math.Abs(8227.82M - results[2].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(303.17M - results[2].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[2].TranAmount + results[2].InterestAmount)) <= 0.01M);

            //4   8530.99 8257.65 273.35  67147.95
            //Assert.Equal(8257.65M, results[3].TranAmount);
            //Assert.Equal(273.35M, results[3].InterestAmount);
            Assert.True(Math.Abs(8257.65M - results[3].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(273.35M - results[3].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[3].TranAmount + results[3].InterestAmount)) <= 0.01M);

            //5   8530.99 8287.58 243.41  58860.37
            Assert.True(Math.Abs(8287.58M - results[4].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(243.41M - results[4].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[4].TranAmount + results[4].InterestAmount)) <= 0.01M);

            //6   8530.99 8317.63 213.37  50542.75
            Assert.True(Math.Abs(8317.63M - results[5].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(213.37M - results[5].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[5].TranAmount + results[5].InterestAmount)) <= 0.01M);

            //7   8530.99 8347.78 183.22  42194.97
            Assert.True(Math.Abs(8347.78M - results[6].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(183.22M - results[6].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[6].TranAmount + results[6].InterestAmount)) <= 0.01M);

            //8   8530.99 8378.04 152.96  33816.94
            Assert.True(Math.Abs(8378.04M - results[7].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(152.96M - results[7].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[7].TranAmount + results[7].InterestAmount)) <= 0.01M);

            //9   8530.99 8408.41 122.59  25408.54
            Assert.True(Math.Abs(8408.41M - results[8].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(122.59M - results[8].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[8].TranAmount + results[8].InterestAmount)) <= 0.01M);

            //10  8530.99 8438.89 92.11   16969.65
            Assert.True(Math.Abs(8438.89M - results[9].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(92.11M - results[9].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[9].TranAmount + results[9].InterestAmount)) <= 0.01M);

            //11  8530.99 8469.48 61.51   8500.18
            Assert.True(Math.Abs(8469.48M - results[10].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(61.51M - results[10].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[10].TranAmount + results[10].InterestAmount)) <= 0.01M);

            //12  8530.99 8500.18 30.81   00.00
            Assert.True(Math.Abs(8500.18M - results[11].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(30.81M - results[11].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8530.99M - (results[11].TranAmount + results[11].InterestAmount)) <= 0.01M);
        }
Пример #8
0
        public void RepeatedDatesWithAmountAndInterestTest_InputChecks()
        {
            // Scenario 0. No input
            // Arrange
            List <RepeatedDatesWithAmountAndInterest> results = null;
            // Act
            Action act = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(null);
            // Assert
            var exception = Assert.Throws <Exception>(act);

            Assert.Null(results);
            Assert.Equal("Input the data!", exception.Message);

            // Scenario 1. Interest free VS Interest rate
            RepeatDatesWithAmountAndInterestCalInput vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = true,
                StartDate        = DateTime.Now,
                TotalAmount      = 300000,
                InterestRate     = 3
            };

            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Cannot input interest rate for Interest-Free loan", exception.Message);

            // Scenario 2. Negative interest rate
            vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = DateTime.Now,
                TotalAmount      = 300000,
                InterestRate     = -3
            };
            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Interest rate can not be negative", exception.Message);

            // Scenario 3. Missing Total amount
            vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = DateTime.Now,
                TotalAmount      = 0,
                InterestRate     = 3
            };
            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Total amount must large than zero!", exception.Message);

            // Scenario 4. Missing total month
            vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = DateTime.Now,
                TotalAmount      = 20,
                InterestRate     = 3
            };
            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Not supported method", exception.Message);

            // Scenario 5. Missing Start date
            //vm = new RepeatDatesWithAmountAndInterestCalInput
            //{
            //    InterestFreeLoan = false,
            //    TotalAmount = 20,
            //    InterestRate = 3,
            //    TotalMonths = 3,
            //    RepaymentMethod = LoanRepaymentMethod.EqualPrincipal,
            //};
            //act = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            //exception = Assert.Throws<Exception>(act);
            //Assert.Null(results);
            //Assert.Equal("Start date is must", exception.Message);

            // Scenario 6. Different repay day with first repay date
            vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                TotalAmount      = 10000,
                InterestRate     = 3,
                TotalMonths      = 12,
                StartDate        = new DateTime(2020, 1, 3),
                EndDate          = new DateTime(2021, 1, 3),
                RepayDayInMonth  = 15,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipal,
                FirstRepayDate   = new DateTime(2020, 2, 13)
            };
            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Inconsistency in first payment data and repay day", exception.Message);

            // Scenario 7. Invalid repay day
            vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                TotalAmount      = 10000,
                InterestRate     = 3,
                TotalMonths      = 12,
                StartDate        = new DateTime(2018, 1, 3),
                EndDate          = new DateTime(2019, 1, 3),
                RepayDayInMonth  = 30,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipal,
            };
            act       = () => CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);
            exception = Assert.Throws <Exception>(act);
            Assert.Null(results);
            Assert.Equal("Invalid repay. date", exception.Message);

            // Scenario 8. Others?
        }
Пример #9
0
        public void RepeatedDatesWithAmountAndInterestTest_EqualC()
        {
            var vm = new RepeatDatesWithAmountAndInterestCalInput
            {
                InterestFreeLoan = false,
                StartDate        = new DateTime(2020, 1, 1),
                TotalAmount      = 100000,
                TotalMonths      = 12,
                InterestRate     = 0.0435M,
                RepaymentMethod  = LoanRepaymentMethod.EqualPrincipal
            };
            List <RepeatedDatesWithAmountAndInterest> results = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(vm);

            //1   8695.83 8333.34 362.50  91666.67
            Assert.True(Math.Abs(8333.37M - results[0].TranAmount) <= 0.01M);
            //Assert.Equal(8168.50M, results[0].TranAmount);
            Assert.True(Math.Abs(362.50M - results[0].InterestAmount) <= 0.01M);
            //Assert.Equal(362.50M, results[0].InterestAmount);
            Assert.True(Math.Abs(8695.87M - (results[0].TranAmount + results[0].InterestAmount)) <= 0.01M);

            //2   8665.63 8333.34 332.29  83333.33
            Assert.True(Math.Abs(8333.34M - results[1].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(332.29M - results[1].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8665.63M - (results[1].TranAmount + results[1].InterestAmount)) <= 0.01M);

            //3   8635.42 8333.34 302.08  75000.00
            Assert.True(Math.Abs(8333.34M - results[2].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(302.08M - results[2].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8635.42M - (results[2].TranAmount + results[2].InterestAmount)) <= 0.01M);

            //4   8605.21 8333.34 271.88  66666.67
            Assert.True(Math.Abs(8333.34M - results[3].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(271.88M - results[3].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8605.21M - (results[3].TranAmount + results[3].InterestAmount)) <= 0.01M);

            //5   8575.00 8333.34 241.67  58333.33
            Assert.True(Math.Abs(8333.34M - results[4].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(241.67M - results[4].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8575.00M - (results[4].TranAmount + results[4].InterestAmount)) <= 0.01M);

            //6   8544.79 8333.34 211.46  50000.00
            Assert.True(Math.Abs(8333.34M - results[5].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(211.46M - results[5].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8544.79M - (results[5].TranAmount + results[5].InterestAmount)) <= 0.01M);

            //7   8514.58 8333.34 181.25  41666.67
            Assert.True(Math.Abs(8333.34M - results[6].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(181.25M - results[6].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8514.58M - (results[6].TranAmount + results[6].InterestAmount)) <= 0.01M);

            //8   8484.38 8333.34 151.04  33333.33
            Assert.True(Math.Abs(8333.34M - results[7].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(151.04M - results[7].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8484.38M - (results[7].TranAmount + results[7].InterestAmount)) <= 0.01M);

            //9   8454.17 8333.34 120.83  25000.00
            Assert.True(Math.Abs(8333.34M - results[8].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(120.83M - results[8].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8454.17M - (results[8].TranAmount + results[8].InterestAmount)) <= 0.01M);

            //10  8423.96 8333.34 90.63   16666.67
            Assert.True(Math.Abs(8333.34M - results[9].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(90.63M - results[9].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8423.96M - (results[9].TranAmount + results[9].InterestAmount)) <= 0.01M);

            //11  8393.75 8333.34 60.42   8333.33
            Assert.True(Math.Abs(8333.34M - results[10].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(60.42M - results[10].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8393.75M - (results[10].TranAmount + results[10].InterestAmount)) <= 0.01M);

            //12  8363.54 8333.34 30.21   00.00
            Assert.True(Math.Abs(8333.34M - results[11].TranAmount) <= 0.01M);
            Assert.True(Math.Abs(30.21M - results[11].InterestAmount) <= 0.01M);
            Assert.True(Math.Abs(8363.54M - (results[11].TranAmount + results[11].InterestAmount)) <= 0.01M);

            // Total amount shall be equal
            decimal amttotalpaid = 0;

            foreach (var rst in results)
            {
                amttotalpaid += rst.TranAmount;
            }
            Assert.True(Math.Abs(amttotalpaid - vm.TotalAmount) < 0.01M);
        }
Пример #10
0
        public static List <RepeatedDatesWithAmountAndInterest> WorkoutRepeatedDatesWithAmountAndInterest(RepeatDatesWithAmountAndInterestCalInput datInput)
        {
            List <RepeatedDatesWithAmountAndInterest> listResults = new List <RepeatedDatesWithAmountAndInterest>();

            // Input checks
            if (datInput == null)
            {
                throw new Exception("Input the data!");
            }
            datInput.doVerify();

            var realStartDate = datInput.StartDate;

            if (datInput.FirstRepayDate.HasValue)
            {
                realStartDate = datInput.FirstRepayDate.Value;
            }
            if (datInput.RepayDayInMonth.HasValue && datInput.RepayDayInMonth.Value != realStartDate.Day)
            {
                if (datInput.RepayDayInMonth.Value > realStartDate.Day)
                {
                    realStartDate = realStartDate.AddDays(datInput.RepayDayInMonth.Value - realStartDate.Day);
                }
                else
                {
                    realStartDate = realStartDate.AddMonths(1);
                    realStartDate = realStartDate.AddDays(datInput.RepayDayInMonth.Value - realStartDate.Day);
                }
            }
            var nInitDelay = (int)((DateTime)realStartDate - (DateTime)datInput.StartDate).TotalDays - 30;

            if (datInput.InterestFreeLoan)
            {
                switch (datInput.RepaymentMethod)
                {
                case LoanRepaymentMethod.EqualPrincipal:
                case LoanRepaymentMethod.EqualPrincipalAndInterset:
                {
                    for (int i = 0; i < datInput.TotalMonths; i++)
                    {
                        listResults.Add(new RepeatedDatesWithAmountAndInterest
                            {
                                TranDate       = realStartDate.AddMonths(i),
                                TranAmount     = Math.Round(datInput.TotalAmount / datInput.TotalMonths, 2),
                                InterestAmount = 0
                            });
                    }
                }
                break;

                case LoanRepaymentMethod.DueRepayment:
                default:
                {
                    if (datInput.EndDate.HasValue)
                    {
                        listResults.Add(new RepeatedDatesWithAmountAndInterest
                            {
                                TranDate       = datInput.EndDate.Value,
                                TranAmount     = datInput.TotalAmount,
                                InterestAmount = 0
                            });
                    }
                    else
                    {
                        listResults.Add(new RepeatedDatesWithAmountAndInterest
                            {
                                TranDate       = datInput.StartDate,
                                TranAmount     = datInput.TotalAmount,
                                InterestAmount = 0
                            });
                    }
                }
                break;
                }
            }
            else
            {
                // Have interest rate inputted
                switch (datInput.RepaymentMethod)
                {
                case LoanRepaymentMethod.EqualPrincipalAndInterset:
                {
                    // Decimal dInitMonthIntere = 0;
                    Decimal monthRate = datInput.InterestRate / 12;
                    Decimal totalAmt  = datInput.TotalAmount;
                    //if (nInitDelay > 0)
                    //    dInitMonthIntere = Math.Round(datInput.TotalAmount * (monthRate / 30) * nInitDelay, 2);
                    Decimal d3         = (Decimal)Math.Pow((double)(1 + monthRate), datInput.TotalMonths) - 1;
                    Decimal monthRepay = datInput.TotalAmount * monthRate * (Decimal)Math.Pow((double)(1 + monthRate), datInput.TotalMonths) / d3;

                    Decimal totalInterestAmt = 0;
                    for (int i = 0; i < datInput.TotalMonths; i++)
                    {
                        var rst = new RepeatedDatesWithAmountAndInterest
                        {
                            TranDate       = realStartDate.AddMonths(i),
                            TranAmount     = Math.Round(datInput.TotalAmount * monthRate * (Decimal)Math.Pow((double)(1 + monthRate), i) / d3, 2),
                            InterestAmount = Math.Round(datInput.TotalAmount * monthRate * ((Decimal)Math.Pow((double)(1 + monthRate), datInput.TotalMonths) - (Decimal)Math.Pow((double)(1 + monthRate), i)) / d3, 2)
                        };

                        if (i == 0 && nInitDelay > 0)
                        {
                            rst.InterestAmount = Math.Round(rst.InterestAmount + (nInitDelay - 1) * datInput.TotalAmount * monthRate / 30, 2);
                        }

                        totalAmt -= rst.TranAmount;
                        //var diff = rst.TranAmount + rst.InterestAmount - monthRepay;
                        //if (diff != 0)
                        //{
                        //    rst.TranAmount -= diff;
                        //    rst.TranAmount = Math.Round(rst.TranAmount, 2);
                        //}

                        totalInterestAmt += rst.InterestAmount;

                        listResults.Add(rst);
                    }
                    // Rounding
                    if (totalAmt != 0)
                    {
                        // Add it to first item
                        listResults[0].TranAmount += totalAmt;
                    }
                }
                break;

                case LoanRepaymentMethod.EqualPrincipal:
                {
                    Decimal monthRate      = datInput.InterestRate / 12;
                    Decimal totalAmt       = datInput.TotalAmount;
                    var     monthPrincipal = datInput.TotalAmount / datInput.TotalMonths;

                    for (int i = 0; i < datInput.TotalMonths; i++)
                    {
                        var rst = new RepeatedDatesWithAmountAndInterest
                        {
                            TranDate       = realStartDate.AddMonths(i + 1),
                            TranAmount     = Math.Round(monthPrincipal, 2),
                            InterestAmount = Math.Round(totalAmt * monthRate, 2)
                        };
                        if (i == 0 && nInitDelay > 0)
                        {
                            rst.InterestAmount = Math.Round(rst.InterestAmount + (nInitDelay - 1) * datInput.TotalAmount * monthRate / 30, 2);
                        }

                        totalAmt -= rst.TranAmount;

                        listResults.Add(rst);
                    }
                    // Rounding
                    if (totalAmt != 0)
                    {
                        // Real paid is lower, substract fromfirst item
                        listResults[0].TranAmount += totalAmt;
                    }
                }
                break;

                case LoanRepaymentMethod.DueRepayment:
                {
                    Decimal monthRate   = datInput.InterestRate / 12;
                    Decimal amtInterest = 0;
                    if (datInput.EndDate.HasValue)
                    {
                        TimeSpan ts = (DateTime)datInput.EndDate.Value - (DateTime)datInput.StartDate;
                        amtInterest = datInput.TotalAmount * (Int32)Math.Round(ts.TotalDays / 30) * monthRate;
                    }
                    else if (datInput.TotalAmount > 0)
                    {
                        amtInterest = datInput.TotalAmount * datInput.TotalMonths * monthRate;
                    }

                    var rst = new RepeatedDatesWithAmountAndInterest
                    {
                        TranDate       = datInput.StartDate.AddMonths(datInput.TotalMonths),
                        TranAmount     = datInput.TotalAmount,
                        InterestAmount = amtInterest
                    };

                    listResults.Add(rst);
                }
                break;

                default: throw new Exception("Unsupported repayment method");
                }
            }

            // Before return, ensure the tranamount is correct
            decimal realamt = 0;

            if (listResults.Count > 0)
            {
                listResults.ForEach(rst =>
                {
                    realamt += rst.TranAmount;
                });
                if (realamt != datInput.TotalAmount)
                {
                    listResults[0].TranAmount -= (realamt - datInput.TotalAmount);
                }
            }

            return(listResults);
        }