public Set<SavingsAccountCharge> fromSavingsProduct(final SavingsProduct savingsProduct) {

    final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();
    Set<Charge> productCharges = savingsProduct.charges();
    for (Charge charge : productCharges) {
      ChargeTimeType chargeTime = null;
      if (charge.getChargeTime() != null) {
        chargeTime = ChargeTimeType.fromInt(charge.getChargeTime());
      }
      if (chargeTime != null && chargeTime.isOnSpecifiedDueDate()) {
        continue;
      }

      ChargeCalculationType chargeCalculation = null;
      if (charge.getChargeCalculation() != null) {
        chargeCalculation = ChargeCalculationType.fromInt(charge.getChargeCalculation());
      }
      final boolean status = true;
      final SavingsAccountCharge savingsAccountCharge =
          SavingsAccountCharge.createNewWithoutSavingsAccount(
              charge,
              charge.getAmount(),
              chargeTime,
              chargeCalculation,
              null,
              status,
              charge.getFeeOnMonthDay(),
              charge.feeInterval());
      savingsAccountCharges.add(savingsAccountCharge);
    }
    return savingsAccountCharges;
  }
Example #2
0
  public LoanCharge(
      final Loan loan,
      final Charge chargeDefinition,
      final BigDecimal loanPrincipal,
      final BigDecimal amount,
      final ChargeTimeType chargeTime,
      final ChargeCalculationType chargeCalculation,
      final LocalDate dueDate,
      final ChargePaymentMode chargePaymentMode,
      final Integer numberOfRepayments,
      final BigDecimal loanCharge) {
    this.loan = loan;
    this.charge = chargeDefinition;
    this.penaltyCharge = chargeDefinition.isPenalty();
    this.minCap = chargeDefinition.getMinCap();
    this.maxCap = chargeDefinition.getMaxCap();

    this.chargeTime = chargeDefinition.getChargeTime();
    if (chargeTime != null) {
      this.chargeTime = chargeTime.getValue();
    }

    if (ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.SPECIFIED_DUE_DATE)
        || ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.OVERDUE_INSTALLMENT)) {

      if (dueDate == null) {
        final String defaultUserMessage = "Loan charge is missing due date.";
        throw new LoanChargeWithoutMandatoryFieldException(
            "loanCharge",
            "dueDate",
            defaultUserMessage,
            chargeDefinition.getId(),
            chargeDefinition.getName());
      }

      this.dueDate = dueDate.toDate();
    } else {
      this.dueDate = null;
    }

    this.chargeCalculation = chargeDefinition.getChargeCalculation();
    if (chargeCalculation != null) {
      this.chargeCalculation = chargeCalculation.getValue();
    }

    BigDecimal chargeAmount = chargeDefinition.getAmount();
    if (amount != null) {
      chargeAmount = amount;
    }

    this.chargePaymentMode = chargeDefinition.getChargePaymentMode();
    if (chargePaymentMode != null) {
      this.chargePaymentMode = chargePaymentMode.getValue();
    }
    populateDerivedFields(loanPrincipal, chargeAmount, numberOfRepayments, loanCharge);
    this.paid = determineIfFullyPaid();
  }
Example #3
0
  public void update(
      final BigDecimal amount,
      final LocalDate dueDate,
      final BigDecimal loanPrincipal,
      Integer numberOfRepayments,
      BigDecimal loanCharge) {
    if (dueDate != null) {
      this.dueDate = dueDate.toDate();
    }

    if (amount != null) {
      switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
        case INVALID:
          break;
        case FLAT:
          if (isInstalmentFee()) {
            if (numberOfRepayments == null) {
              numberOfRepayments = this.loan.repaymentScheduleDetail().getNumberOfRepayments();
            }
            this.amount = amount.multiply(BigDecimal.valueOf(numberOfRepayments));
          } else {
            this.amount = amount;
          }
          break;
        case PERCENT_OF_AMOUNT:
        case PERCENT_OF_AMOUNT_AND_INTEREST:
        case PERCENT_OF_INTEREST:
          this.percentage = amount;
          this.amountPercentageAppliedTo = loanPrincipal;
          if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
            loanCharge = percentageOf(this.amountPercentageAppliedTo);
          }
          this.amount = minimumAndMaximumCap(loanCharge);
          break;
      }
      this.amountOrPercentage = amount;
      this.amountOutstanding = calculateOutstanding();
      if (this.loan != null && isInstalmentFee()) {
        final Set<LoanInstallmentCharge> chargePerInstallments =
            this.loan.generateInstallmentLoanCharges(this);
        if (this.loanInstallmentCharge.isEmpty()) {
          this.loanInstallmentCharge.addAll(chargePerInstallments);
        } else {
          int index = 0;
          final LoanInstallmentCharge[] loanChargePerInstallments =
              new LoanInstallmentCharge[chargePerInstallments.size()];
          final LoanInstallmentCharge[] loanChargePerInstallmentArray =
              chargePerInstallments.toArray(loanChargePerInstallments);
          for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
            chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
          }
        }
      }
    }
  }
Example #4
0
 public void update(
     final BigDecimal amount, final LocalDate dueDate, final Integer numberOfRepayments) {
   BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
   if (this.loan != null) {
     switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
       case PERCENT_OF_AMOUNT:
         amountPercentageAppliedTo = this.loan.getPrincpal().getAmount();
         break;
       case PERCENT_OF_AMOUNT_AND_INTEREST:
         amountPercentageAppliedTo =
             this.loan.getPrincpal().getAmount().add(this.loan.getTotalInterest());
         break;
       case PERCENT_OF_INTEREST:
         amountPercentageAppliedTo = this.loan.getTotalInterest();
         break;
       default:
         break;
     }
   }
   update(amount, dueDate, amountPercentageAppliedTo, numberOfRepayments, BigDecimal.ZERO);
 }
  public Set<SavingsAccountCharge> fromParsedJson(
      final JsonElement element, final String productCurrencyCode) {

    final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();

    if (element.isJsonObject()) {
      final JsonObject topLevelJsonElement = element.getAsJsonObject();
      final String dateFormat =
          this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
      final String monthDayFormat =
          this.fromApiJsonHelper.extractMonthDayFormatParameter(topLevelJsonElement);
      final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
      if (topLevelJsonElement.has(chargesParamName)
          && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
        final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
        for (int i = 0; i < array.size(); i++) {

          final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();

          final Long id =
              this.fromApiJsonHelper.extractLongNamed(idParamName, savingsChargeElement);
          final Long chargeId =
              this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
          final BigDecimal amount =
              this.fromApiJsonHelper.extractBigDecimalNamed(
                  amountParamName, savingsChargeElement, locale);
          final Integer chargeTimeType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeTimeTypeParamName, savingsChargeElement, locale);
          final Integer chargeCalculationType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeCalculationTypeParamName, savingsChargeElement, locale);
          final LocalDate dueDate =
              this.fromApiJsonHelper.extractLocalDateNamed(
                  dueAsOfDateParamName, savingsChargeElement, dateFormat, locale);

          final MonthDay feeOnMonthDay =
              this.fromApiJsonHelper.extractMonthDayNamed(
                  feeOnMonthDayParamName, savingsChargeElement, monthDayFormat, locale);
          final Integer feeInterval =
              this.fromApiJsonHelper.extractIntegerNamed(
                  feeIntervalParamName, savingsChargeElement, locale);

          if (id == null) {
            final Charge chargeDefinition =
                this.chargeRepository.findOneWithNotFoundDetection(chargeId);

            if (!chargeDefinition.isSavingsCharge()) {
              final String errorMessage =
                  "Charge with identifier "
                      + chargeDefinition.getId()
                      + " cannot be applied to Savings product.";
              throw new ChargeCannotBeAppliedToException(
                  "savings.product", errorMessage, chargeDefinition.getId());
            }

            ChargeTimeType chargeTime = null;
            if (chargeTimeType != null) {
              chargeTime = ChargeTimeType.fromInt(chargeTimeType);
            }

            ChargeCalculationType chargeCalculation = null;
            if (chargeCalculationType != null) {
              chargeCalculation = ChargeCalculationType.fromInt(chargeCalculationType);
            }

            final boolean status = true;
            final SavingsAccountCharge savingsAccountCharge =
                SavingsAccountCharge.createNewWithoutSavingsAccount(
                    chargeDefinition,
                    amount,
                    chargeTime,
                    chargeCalculation,
                    dueDate,
                    status,
                    feeOnMonthDay,
                    feeInterval);
            savingsAccountCharges.add(savingsAccountCharge);
          } else {
            final Long savingsAccountChargeId = id;
            final SavingsAccountCharge savingsAccountCharge =
                this.savingsAccountChargeRepository.findOne(savingsAccountChargeId);
            if (savingsAccountCharge == null) {
              throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId);
            }

            savingsAccountCharge.update(amount, dueDate, feeOnMonthDay, feeInterval);

            savingsAccountCharges.add(savingsAccountCharge);
          }
        }
      }
    }

    this.validateSavingsCharges(savingsAccountCharges, productCurrencyCode);
    return savingsAccountCharges;
  }
Example #6
0
 public ChargeCalculationType getChargeCalculation() {
   return ChargeCalculationType.fromInt(this.chargeCalculation);
 }
Example #7
0
  public Map<String, Object> update(final JsonCommand command, final BigDecimal amount) {

    final Map<String, Object> actualChanges = new LinkedHashMap<>(7);

    final String dateFormatAsInput = command.dateFormat();
    final String localeAsInput = command.locale();

    final String dueDateParamName = "dueDate";
    if (command.isChangeInLocalDateParameterNamed(dueDateParamName, getDueLocalDate())) {
      final String valueAsInput = command.stringValueOfParameterNamed(dueDateParamName);
      actualChanges.put(dueDateParamName, valueAsInput);
      actualChanges.put("dateFormat", dateFormatAsInput);
      actualChanges.put("locale", localeAsInput);

      final LocalDate newValue = command.localDateValueOfParameterNamed(dueDateParamName);
      this.dueDate = newValue.toDate();
    }

    final String amountParamName = "amount";
    if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
      final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
      actualChanges.put(amountParamName, newValue);
      actualChanges.put("locale", localeAsInput);
      switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
        case INVALID:
          break;
        case FLAT:
          if (isInstalmentFee()) {
            this.amount =
                newValue.multiply(
                    BigDecimal.valueOf(
                        this.loan.repaymentScheduleDetail().getNumberOfRepayments()));
          } else {
            this.amount = newValue;
          }
          this.amountOutstanding = calculateOutstanding();
          break;
        case PERCENT_OF_AMOUNT:
        case PERCENT_OF_AMOUNT_AND_INTEREST:
        case PERCENT_OF_INTEREST:
          this.percentage = newValue;
          this.amountPercentageAppliedTo = amount;
          BigDecimal loanCharge = BigDecimal.ZERO;
          if (isInstalmentFee()) {
            loanCharge =
                this.loan.calculatePerInstallmentChargeAmount(
                    ChargeCalculationType.fromInt(this.chargeCalculation), this.percentage);
          }
          if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
            loanCharge = percentageOf(this.amountPercentageAppliedTo);
          }
          this.amount = minimumAndMaximumCap(loanCharge);
          this.amountOutstanding = calculateOutstanding();
          break;
      }
      this.amountOrPercentage = newValue;
      if (isInstalmentFee()) {
        final Set<LoanInstallmentCharge> chargePerInstallments =
            this.loan.generateInstallmentLoanCharges(this);
        if (this.loanInstallmentCharge.isEmpty()) {
          this.loanInstallmentCharge.addAll(chargePerInstallments);
        } else {
          int index = 0;
          final LoanInstallmentCharge[] loanChargePerInstallments =
              new LoanInstallmentCharge[chargePerInstallments.size()];
          final LoanInstallmentCharge[] loanChargePerInstallmentArray =
              chargePerInstallments.toArray(loanChargePerInstallments);
          for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
            chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
          }
        }
      }
    }
    return actualChanges;
  }
Example #8
0
  private void populateDerivedFields(
      final BigDecimal amountPercentageAppliedTo,
      final BigDecimal chargeAmount,
      Integer numberOfRepayments,
      BigDecimal loanCharge) {

    switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
      case INVALID:
        this.percentage = null;
        this.amount = null;
        this.amountPercentageAppliedTo = null;
        this.amountPaid = null;
        this.amountOutstanding = BigDecimal.ZERO;
        this.amountWaived = null;
        this.amountWrittenOff = null;
        break;
      case FLAT:
        this.percentage = null;
        this.amountPercentageAppliedTo = null;
        this.amountPaid = null;
        if (isInstalmentFee()) {
          if (numberOfRepayments == null) {
            numberOfRepayments = this.loan.repaymentScheduleDetail().getNumberOfRepayments();
          }
          this.amount = chargeAmount.multiply(BigDecimal.valueOf(numberOfRepayments));
        } else {
          this.amount = chargeAmount;
        }
        this.amountOutstanding = this.amount;
        this.amountWaived = null;
        this.amountWrittenOff = null;
        break;
      case PERCENT_OF_AMOUNT:
      case PERCENT_OF_AMOUNT_AND_INTEREST:
      case PERCENT_OF_INTEREST:
        this.percentage = chargeAmount;
        this.amountPercentageAppliedTo = amountPercentageAppliedTo;
        if (loanCharge.compareTo(BigDecimal.ZERO) == 0) {
          loanCharge = percentageOf(this.amountPercentageAppliedTo);
        }
        this.amount = minimumAndMaximumCap(loanCharge);
        this.amountPaid = null;
        this.amountOutstanding = calculateOutstanding();
        this.amountWaived = null;
        this.amountWrittenOff = null;
        break;
    }
    this.amountOrPercentage = chargeAmount;
    if (this.loan != null && isInstalmentFee()) {
      final Set<LoanInstallmentCharge> chargePerInstallments =
          this.loan.generateInstallmentLoanCharges(this);
      if (this.loanInstallmentCharge.isEmpty()) {
        this.loanInstallmentCharge.addAll(chargePerInstallments);
      } else {
        int index = 0;
        final LoanInstallmentCharge[] loanChargePerInstallments =
            new LoanInstallmentCharge[chargePerInstallments.size()];
        final LoanInstallmentCharge[] loanChargePerInstallmentArray =
            chargePerInstallments.toArray(loanChargePerInstallments);
        for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
          chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
        }
      }
    }
  }
Example #9
0
  public static LoanCharge createNewFromJson(
      final Loan loan,
      final Charge chargeDefinition,
      final JsonCommand command,
      final LocalDate dueDate) {
    final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");

    final ChargeTimeType chargeTime = null;
    final ChargeCalculationType chargeCalculation = null;
    final ChargePaymentMode chargePaymentMode = null;
    BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
    switch (ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation())) {
      case PERCENT_OF_AMOUNT:
        if (command.hasParameter("principal")) {
          amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal");
        } else {
          amountPercentageAppliedTo = loan.getPrincpal().getAmount();
        }
        break;
      case PERCENT_OF_AMOUNT_AND_INTEREST:
        if (command.hasParameter("principal") && command.hasParameter("interest")) {
          amountPercentageAppliedTo =
              command
                  .bigDecimalValueOfParameterNamed("principal")
                  .add(command.bigDecimalValueOfParameterNamed("interest"));
        } else {
          amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
        }
        break;
      case PERCENT_OF_INTEREST:
        if (command.hasParameter("interest")) {
          amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("interest");
        } else {
          amountPercentageAppliedTo = loan.getTotalInterest();
        }
        break;
      default:
        break;
    }

    BigDecimal loanCharge = BigDecimal.ZERO;
    if (ChargeTimeType.fromInt(chargeDefinition.getChargeTime())
        .equals(ChargeTimeType.INSTALMENT_FEE)) {
      BigDecimal percentage = amount;
      if (percentage == null) {
        percentage = chargeDefinition.getAmount();
      }
      loanCharge =
          loan.calculatePerInstallmentChargeAmount(
              ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation()), percentage);
    }

    return new LoanCharge(
        loan,
        chargeDefinition,
        amountPercentageAppliedTo,
        amount,
        chargeTime,
        chargeCalculation,
        dueDate,
        chargePaymentMode,
        null,
        loanCharge);
  }