/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mifosplatform.portfolio.loanaccount.domain; import java.math.BigDecimal; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; import org.springframework.data.jpa.domain.AbstractPersistable; @Entity @Table(name = "m_loan_installment_charge") public class LoanInstallmentCharge extends AbstractPersistable<Long> { @ManyToOne(optional = false) @JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false) private LoanCharge loancharge; @ManyToOne(optional = false) @JoinColumn(name = "loan_schedule_id", referencedColumnName = "id", nullable = false) private LoanRepaymentScheduleInstallment installment; @Column(name = "amount", scale = 6, precision = 19, nullable = false) private BigDecimal amount; @Column(name = "amount_paid_derived", scale = 6, precision = 19, nullable = true) private BigDecimal amountPaid; @Column(name = "amount_waived_derived", scale = 6, precision = 19, nullable = true) private BigDecimal amountWaived; @Column(name = "amount_writtenoff_derived", scale = 6, precision = 19, nullable = true) private BigDecimal amountWrittenOff; @Column(name = "amount_outstanding_derived", scale = 6, precision = 19, nullable = false) private BigDecimal amountOutstanding; @Column(name = "amount_through_charge_payment", scale = 6, precision = 19, nullable = true) private BigDecimal amountThroughChargePayment; @Column(name = "is_paid_derived", nullable = false) private boolean paid = false; @Column(name = "waived", nullable = false) private boolean waived = false; public LoanInstallmentCharge() { // TODO Auto-generated constructor stub } public LoanInstallmentCharge(final BigDecimal amount, final LoanCharge loanCharge, final LoanRepaymentScheduleInstallment installment) { this.loancharge = loanCharge; this.installment = installment; this.amount = amount; this.amountOutstanding = amount; this.amountPaid = null; this.amountWaived = null; this.amountWrittenOff = null; } public void copyFrom(final LoanInstallmentCharge loanChargePerInstallment) { this.amount = loanChargePerInstallment.amount; this.installment = loanChargePerInstallment.installment; this.amountOutstanding = calculateOutstanding(); this.paid = determineIfFullyPaid(); } public Money waive(final MonetaryCurrency currency) { this.amountWaived = this.amountOutstanding; this.amountOutstanding = BigDecimal.ZERO; this.paid = false; this.waived = true; return getAmountWaived(currency); } public Money getAmountWaived(final MonetaryCurrency currency) { return Money.of(currency, this.amountWaived); } private boolean determineIfFullyPaid() { if (this.amount == null) { return true; } return BigDecimal.ZERO.compareTo(calculateOutstanding()) == 0; } private BigDecimal calculateOutstanding() { if (this.amount == null) { return null; } BigDecimal amountPaidLocal = BigDecimal.ZERO; if (this.amountPaid != null) { amountPaidLocal = this.amountPaid; } BigDecimal amountWaivedLocal = BigDecimal.ZERO; if (this.amountWaived != null) { amountWaivedLocal = this.amountWaived; } BigDecimal amountWrittenOffLocal = BigDecimal.ZERO; if (this.amountWrittenOff != null) { amountWrittenOffLocal = this.amountWrittenOff; } final BigDecimal totalAccountedFor = amountPaidLocal.add(amountWaivedLocal).add(amountWrittenOffLocal); return this.amount.subtract(totalAccountedFor); } public BigDecimal getAmount() { return this.amount; } public Money getAmount(final MonetaryCurrency currency) { return Money.of(currency, this.amount); } public Money getAmountPaid(final MonetaryCurrency currency) { return Money.of(currency, this.amountPaid); } public BigDecimal getAmountOutstanding() { return this.amountOutstanding; } private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) { return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount(); } public boolean isPaid() { return this.paid; } public boolean isWaived() { return this.waived; } public boolean isPending() { return !(isPaid() || isWaived()); } public boolean isChargeAmountpaid(MonetaryCurrency currency) { Money amounPaidThroughChargePayment = Money.of(currency, this.amountThroughChargePayment); Money paid = Money.of(currency, this.amountPaid); return amounPaidThroughChargePayment.isEqualTo(paid); } public LoanRepaymentScheduleInstallment getRepaymentInstallment() { return this.installment; } public Money updatePaidAmountBy(final Money incrementBy, final Money feeAmount) { Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid); final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding); Money amountPaidPreviously = amountPaidToDate; Money amountPaidOnThisCharge = Money.zero(incrementBy.getCurrency()); if (incrementBy.isGreaterThanOrEqualTo(amountOutstanding)) { amountPaidOnThisCharge = amountOutstanding; amountPaidToDate = amountPaidToDate.plus(amountOutstanding); this.amountPaid = amountPaidToDate.getAmount(); this.amountOutstanding = BigDecimal.ZERO; } else { amountPaidOnThisCharge = incrementBy; amountPaidToDate = amountPaidToDate.plus(incrementBy); this.amountPaid = amountPaidToDate.getAmount(); this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency()); } Money amountFromChargePayment = Money.of(incrementBy.getCurrency(), this.amountThroughChargePayment); if (amountPaidPreviously.isGreaterThanZero()) { amountFromChargePayment = amountFromChargePayment.plus(feeAmount); } else { amountFromChargePayment = feeAmount; } this.amountThroughChargePayment = amountFromChargePayment.getAmount(); if (determineIfFullyPaid()) { Money waivedAmount = getAmountWaived(incrementBy.getCurrency()); if (waivedAmount.isGreaterThanZero()) { this.waived = true; } else { this.paid = true; } } return amountPaidOnThisCharge; } public Money getAmountWrittenOff(final MonetaryCurrency currency) { return Money.of(currency, this.amountWrittenOff); } public void resetPaidAmount(final MonetaryCurrency currency) { this.amountPaid = BigDecimal.ZERO; this.amountOutstanding = calculateAmountOutstanding(currency); this.paid = false; } public void resetToOriginal(final MonetaryCurrency currency) { this.amountPaid = BigDecimal.ZERO; this.amountWaived = BigDecimal.ZERO; this.amountWrittenOff = BigDecimal.ZERO; this.amountThroughChargePayment = BigDecimal.ZERO; this.amountOutstanding = calculateAmountOutstanding(currency); this.paid = false; this.waived = false; } public Money getAmountThroughChargePayment(final MonetaryCurrency currency) { return Money.of(currency, this.amountThroughChargePayment); } public Money getUnpaidAmountThroughChargePayment(final MonetaryCurrency currency) { return Money.of(currency, this.amountThroughChargePayment).minus(this.amountPaid); } private void updateAmountThroughChargePayment(final MonetaryCurrency currency) { Money amountThroughChargePayment = getAmountThroughChargePayment(currency); if (amountThroughChargePayment.isGreaterThanZero() && amountThroughChargePayment.isGreaterThan(this.getAmount(currency))) { this.amountThroughChargePayment = this.getAmount(); } } public Money updateWaivedAndAmountPaidThroughChargePaymentAmount(final MonetaryCurrency currency) { updateWaivedAmount(currency); updateAmountThroughChargePayment(currency); return getAmountWaived(currency); } private void updateWaivedAmount(final MonetaryCurrency currency) { Money waivedAmount = getAmountWaived(currency); if (waivedAmount.isGreaterThanZero()) { if (waivedAmount.isGreaterThan(this.getAmount(currency))) { this.amountWaived = this.getAmount(); this.amountOutstanding = BigDecimal.ZERO; this.paid = false; this.waived = true; } else if (waivedAmount.isLessThan(this.getAmount(currency))) { this.paid = false; this.waived = false; } } } public void updateInstallment(LoanRepaymentScheduleInstallment installment) { this.installment = installment; } public Money undoPaidAmountBy(final Money incrementBy, final Money feeAmount) { Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid); Money amountToDeductOnThisCharge = Money.zero(incrementBy.getCurrency()); if (incrementBy.isGreaterThanOrEqualTo(amountPaidToDate)) { amountToDeductOnThisCharge = amountPaidToDate; amountPaidToDate = Money.zero(incrementBy.getCurrency()); this.amountPaid = amountPaidToDate.getAmount(); this.amountOutstanding = this.amount; } else { amountToDeductOnThisCharge = incrementBy; amountPaidToDate = amountPaidToDate.minus(incrementBy); this.amountPaid = amountPaidToDate.getAmount(); this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency()); } this.amountThroughChargePayment = feeAmount.getAmount(); this.paid = determineIfFullyPaid(); return amountToDeductOnThisCharge; } }