@Test
  public void testGetPaymentsAmortizedWithOverPayment() {

    AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate();
    amAttrs.setLoanAmount(ofUSD(10000));
    amAttrs.setInterestRateAsPercent(3.);
    amAttrs.setInterestOnly(false);
    amAttrs.setRegularPayment(ofUSD(400));
    amAttrs.setPaymentFrequency(TimePeriod.SemiMonthly.getPeriodsPerYear());
    int termInMonths = 24;
    amAttrs.setTermInMonths(termInMonths);
    amAttrs.setAmortizationPeriodInMonths(24);
    amAttrs.setCompoundingPeriodsPerYear(2);

    List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs);

    assertEquals(
        "Amortized payment count",
        amAttrs.getPaymentFrequency() * termInMonths / 12,
        schedule.size());

    MonetaryAmount interestTotal =
        schedule.stream().map(payment -> payment.getInterest()).reduce((a, b) -> a.add(b)).get();

    assertEquals("Amortized Interest total", ofUSD(164.81), interestTotal);
  }
  @Test
  public void testGetPaymentsAmortizedFully() {

    AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate();
    MonetaryAmount loanAmount = ofUSD(10000);
    amAttrs.setLoanAmount(loanAmount);
    amAttrs.setInterestRateAsPercent(7.);
    amAttrs.setInterestOnly(false);
    amAttrs.setPaymentFrequency(TimePeriod.Monthly.getPeriodsPerYear());
    int termInMonths = 12;
    amAttrs.setTermInMonths(termInMonths);
    amAttrs.setAmortizationPeriodInMonths(12);
    amAttrs.setCompoundingPeriodsPerYear(2);
    amAttrs.setRegularPayment(AmortizationCalculator.getPeriodicPayment(amAttrs));

    List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs);

    MonetaryAmount interestTotal =
        schedule.stream().map(payment -> payment.getInterest()).reduce((a, b) -> a.add(b)).get();

    assertEquals("Amortized Interest total", ofUSD(377.67), interestTotal);

    MonetaryAmount principalTotal =
        schedule.stream().map(payment -> payment.getPrincipal()).reduce((a, b) -> a.add(b)).get();

    assertEquals("Amortized Principal fully paid", loanAmount, principalTotal);
  }
 @Test
 public void testGetPeriodicPaymentAmortizedMonthlyCompoundPeriod() {
   AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate();
   amAttrs.setLoanAmount(USD50000.multiply(2));
   amAttrs.setInterestRateAsPercent(12.);
   amAttrs.setCompoundingPeriodsPerYear(12);
   amAttrs.setPaymentFrequency(12);
   MonetaryAmount result = AmortizationCalculator.getPeriodicPayment(amAttrs);
   MonetaryAmount expectedResult = ofUSD(1053.23);
   assertEquals("Monthly amortized payment compounded monthly", expectedResult, result);
 }
 @Test
 public void testGetPeriodicPaymentCompoundSemiPaymentSemiAnnually() {
   AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate();
   amAttrs.setLoanAmount(USD50000.divide(5));
   amAttrs.setInterestRateAsPercent(10.);
   amAttrs.setCompoundingPeriodsPerYear(TimePeriod.SemiAnnually.getPeriodsPerYear());
   amAttrs.setAmortizationPeriodInMonths(12);
   amAttrs.setPaymentFrequency(TimePeriod.SemiAnnually.getPeriodsPerYear());
   MonetaryAmount result = AmortizationCalculator.getPeriodicPayment(amAttrs);
   MonetaryAmount expectedResult = ofUSD(5378.05);
   assertEquals("Amortized, compounded semi-annual, payment semimonthly", expectedResult, result);
 }
  private AmortizationAttributes generateAmortizationAttributesObjectTemplate() {

    AmortizationAttributes amAttrs = new AmortizationAttributes();
    amAttrs.setLoanAmount(USD50000);
    amAttrs.setRegularPayment(USD50000.divide(100));
    amAttrs.setStartDate(LocalDate.of(2015, Month.DECEMBER, 28));
    amAttrs.setAdjustmentDate(LocalDate.of(2016, Month.JANUARY, 1));
    amAttrs.setTermInMonths(24);
    amAttrs.setInterestOnly(false);
    amAttrs.setAmortizationPeriodInMonths(300);
    amAttrs.setCompoundingPeriodsPerYear(2);
    amAttrs.setPaymentFrequency(12);
    amAttrs.setInterestRateAsPercent(12.);

    return amAttrs;
  }
  @Test
  public void testGetPeriodInterest_Amortized() {

    AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate();
    amAttrs.setLoanAmount(USD50000.multiply(2));
    amAttrs.setInterestRateAsPercent(12.);
    amAttrs.setCompoundingPeriodsPerYear(2);
    amAttrs.setPaymentFrequency(12);

    List<ScheduledPayment> generatedSchedule = AmortizationCalculator.generateSchedule(amAttrs);
    generatedSchedule
        .stream()
        .forEachOrdered(
            p -> {
              MonetaryAmount periodInterest = AmortizationCalculator.getPeriodInterest(amAttrs);
              assertEquals(
                  "Monthly amortized payment interest matches peirod interest",
                  p.getInterest(),
                  periodInterest);
              amAttrs.setLoanAmount(p.getBalance());
            });
  }