Package com.cedarsoft.business.calc

Source Code of com.cedarsoft.business.calc.VariableInterestCalculationSystem

package com.cedarsoft.business.calc;

import com.cedarsoft.business.Money;
import com.cedarsoft.business.MutableMoney;
import org.jetbrains.annotations.NotNull;
import org.joda.time.LocalDate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Calculates the interests for a given {@link InterestRateProvider}.
*/
public class VariableInterestCalculationSystem {
  @NotNull
  private final InterestRateProvider interestRateProvider;
  @NotNull
  private final InterestCalculationSystem backingCalculationSystem;
  @NotNull
  private final TimeSystem timeSystem;

  /**
   * Creates a new calculation system
   *
   * @param interestRateProvider     the interest rate provider
   * @param backingCalculationSystem the backing calculation system
   * @param timeSystem               the time system
   */
  public VariableInterestCalculationSystem( @NotNull InterestRateProvider interestRateProvider, @NotNull InterestCalculationSystem backingCalculationSystem, @NotNull TimeSystem timeSystem ) {
    this.interestRateProvider = interestRateProvider;
    this.backingCalculationSystem = backingCalculationSystem;
    this.timeSystem = timeSystem;
  }

  /**
   * Calculates the interest for the given amount and dates.
   *
   * @param amount the amount the interest is calculated for
   * @param begin  the begin of the period
   * @param end    the end of the period
   * @return the payment rent
   */
  @NotNull
  public Rent calculateInterest( @NotNull Money amount, @NotNull LocalDate begin, @NotNull LocalDate end ) {
    //Switch over the validity period
    switch ( getInterestRateProvider().getValidityPeriod() ) {
      case CONSTANT:
        return calculateInterestConstantRate( amount, begin, end );
      case MONTHLY:
        return calculateInterestMonthlyPeriod( amount, begin, end );
      default:
        throw new UnsupportedOperationException( "not yet implemented for " + getInterestRateProvider().getValidityPeriod() );
    }
  }

  /**
   * Calculates the interest for a interest rate provider with monthly changing interest rates.
   *
   * @param amount the amount
   * @param begin  the begin
   * @param end    the end
   * @return the interest
   */
  @NotNull
  public Rent calculateInterestMonthlyPeriod( @NotNull Money amount, @NotNull LocalDate begin, @NotNull LocalDate end ) {
    List<InterestDetails> interestDetails = new ArrayList<InterestDetails>();

    //Create a runner that represents the begin of the actual month
    //For the first month this may be another day of month than 1
    LocalDate actualMonthBegin = begin;

    //Now iterate over all months
    MutableMoney rentSummer = new MutableMoney();
    while ( actualMonthBegin.isBefore( end ) ) {
      LocalDate actualMonthEnd = actualMonthBegin.plusMonths( 1 );
      //Check if this month is complete --> else only add the rest
      if ( actualMonthEnd.isAfter( end ) ) {
        actualMonthEnd = end;
      }

      double monthYears = getTimeSystem().calculateYears( actualMonthBegin, actualMonthEnd );
      double monthDays = getTimeSystem().calculateDays( actualMonthBegin, actualMonthEnd );
      double monthRate = getInterestRateProvider().getRate( actualMonthBegin );

      //add the rent for the rent
      Money baseForMonth = rentSummer.immutable();

      Money compoundInterest;
      if ( getBackingCalculationSystem().isCompoundSystem() && baseForMonth.getValue() != 0 ) {
        compoundInterest = getBackingCalculationSystem().calculateInterest( baseForMonth, monthYears, monthDays, monthRate );
        rentSummer.plus( compoundInterest );
      } else {
        compoundInterest = Money.ZERO;
      }

      //add the rent for the amount
      Money interest = getBackingCalculationSystem().calculateInterest( amount, monthYears, monthDays, monthRate );
      rentSummer.plus( interest );

      //Build the information object (if expected)
      interestDetails.add( new InterestDetails( actualMonthBegin, actualMonthEnd, monthRate, baseForMonth, interest.plus( compoundInterest ), monthDays ) );

      //Next month --> now we really need the first day of the month
      actualMonthBegin = actualMonthBegin.plusMonths( 1 ).withDayOfMonth( 1 );
    }

    return new Rent( amount, begin, end, interestDetails );
  }

  /**
   * Calculates the interest for a interest rate provider with a constant rate
   *
   * @param amount the amount
   * @param begin  the begin
   * @param end    the end
   * @return the interest
   */
  @NotNull
  private Rent calculateInterestConstantRate( @NotNull Money amount, @NotNull LocalDate begin, @NotNull LocalDate end ) {
    double years = getTimeSystem().calculateYears( begin, end );
    double days = getTimeSystem().calculateDays( begin, end );
    double rate = getInterestRateProvider().getRate( begin );
    Money interest = getBackingCalculationSystem().calculateInterest( amount, years, days, rate );

    //We need just one interest details since the interest rate is constant
    InterestDetails interestDetails = new InterestDetails( begin, begin.plusDays( 1 ), rate, amount, interest, days );//todo check end date
    return new Rent( amount, begin, end, Collections.singletonList( interestDetails ) );
  }

  @NotNull
  public InterestRateProvider getInterestRateProvider() {
    return interestRateProvider;
  }

  @NotNull
  public InterestCalculationSystem getBackingCalculationSystem() {
    return backingCalculationSystem;
  }

  @NotNull
  public TimeSystem getTimeSystem() {
    return timeSystem;
  }
}
TOP

Related Classes of com.cedarsoft.business.calc.VariableInterestCalculationSystem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.