FINERACT-2190: Improve copyFrom of LoanRepaymentScheduleInstallment
This commit is contained in:
+6
-2
@@ -39,8 +39,8 @@ public final class MathUtil {
|
|||||||
return nullToDefault(value, 0L);
|
return nullToDefault(value, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Long nullToDefault(Long value, Long def) {
|
public static Integer nullToZero(Integer value) {
|
||||||
return value == null ? def : value;
|
return nullToDefault(value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Long zeroToNull(Long value) {
|
public static Long zeroToNull(Long value) {
|
||||||
@@ -505,4 +505,8 @@ public final class MathUtil {
|
|||||||
return notNull ? first == null ? second : second == null ? first : max(first, second, false)
|
return notNull ? first == null ? second : second == null ? first : max(first, second, false)
|
||||||
: isGreaterThan(first, second) ? first : second;
|
: isGreaterThan(first, second) ? first : second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isEqualTo(Integer first, Integer second) {
|
||||||
|
return nullToZero(first).equals(nullToZero(second));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-28
@@ -24,6 +24,8 @@ import jakarta.persistence.JoinColumn;
|
|||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
@@ -31,6 +33,7 @@ import org.apache.fineract.organisation.monetary.domain.Money;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
|
@Getter
|
||||||
@Table(name = "m_loan_installment_charge")
|
@Table(name = "m_loan_installment_charge")
|
||||||
public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> implements Comparable<LoanInstallmentCharge> {
|
public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> implements Comparable<LoanInstallmentCharge> {
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
||||||
private LoanCharge loancharge;
|
private LoanCharge loancharge;
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "loan_schedule_id", nullable = false)
|
@JoinColumn(name = "loan_schedule_id", nullable = false)
|
||||||
private LoanRepaymentScheduleInstallment installment;
|
private LoanRepaymentScheduleInstallment installment;
|
||||||
@@ -48,6 +52,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
@Column(name = "amount_paid_derived", scale = 6, precision = 19, nullable = true)
|
@Column(name = "amount_paid_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal amountPaid;
|
private BigDecimal amountPaid;
|
||||||
|
|
||||||
|
@Setter
|
||||||
@Column(name = "amount_waived_derived", scale = 6, precision = 19, nullable = true)
|
@Column(name = "amount_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal amountWaived;
|
private BigDecimal amountWaived;
|
||||||
|
|
||||||
@@ -140,10 +145,6 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
return this.amount.subtract(totalAccountedFor);
|
return this.amount.subtract(totalAccountedFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getAmount() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getAmount(final MonetaryCurrency currency) {
|
public Money getAmount(final MonetaryCurrency currency) {
|
||||||
return Money.of(currency, this.amount);
|
return Money.of(currency, this.amount);
|
||||||
}
|
}
|
||||||
@@ -152,22 +153,10 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
return Money.of(currency, this.amountPaid);
|
return Money.of(currency, this.amountPaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getAmountOutstanding() {
|
|
||||||
return this.amountOutstanding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||||
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
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() {
|
public boolean isPending() {
|
||||||
return !MathUtil.isZero(this.amountOutstanding);
|
return !MathUtil.isZero(this.amountOutstanding);
|
||||||
}
|
}
|
||||||
@@ -228,10 +217,6 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
this.paid = false;
|
this.paid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAmountWaived(final BigDecimal amountWaived) {
|
|
||||||
this.amountWaived = amountWaived;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void undoWaiveFlag() {
|
public void undoWaiveFlag() {
|
||||||
this.waived = false;
|
this.waived = false;
|
||||||
}
|
}
|
||||||
@@ -317,14 +302,6 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom<Long> imple
|
|||||||
return this.loancharge;
|
return this.loancharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment getInstallment() {
|
|
||||||
return this.installment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInstallment(LoanRepaymentScheduleInstallment installment) {
|
|
||||||
this.installment = installment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanInstallmentChargeData toData() {
|
public LoanInstallmentChargeData toData() {
|
||||||
return LoanInstallmentChargeData.builder().installmentNumber(installment.getInstallmentNumber()).dueDate(installment.getDueDate())
|
return LoanInstallmentChargeData.builder().installmentNumber(installment.getInstallmentNumber()).dueDate(installment.getDueDate())
|
||||||
.amount(amount).amountOutstanding(amountOutstanding).amountWaived(amountWaived).paid(paid).waived(waived).build();
|
.amount(amount).amountOutstanding(amountOutstanding).amountWaived(amountWaived).paid(paid).waived(waived).build();
|
||||||
|
|||||||
+4
-15
@@ -25,12 +25,16 @@ import jakarta.persistence.ManyToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_loan_interest_recalculation_additional_details")
|
@Table(name = "m_loan_interest_recalculation_additional_details")
|
||||||
|
@Getter
|
||||||
public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistableCustom<Long> {
|
public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistableCustom<Long> {
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
||||||
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
||||||
@@ -52,19 +56,4 @@ public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersista
|
|||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getEffectiveDate() {
|
|
||||||
return this.effectiveDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getAmount() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
|
||||||
return loanRepaymentScheduleInstallment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
|
||||||
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+125
-96
@@ -33,6 +33,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
@@ -56,7 +57,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
@Column(name = "installment", nullable = false)
|
@Column(name = "installment", nullable = false)
|
||||||
private Integer installmentNumber;
|
private Integer installmentNumber;
|
||||||
|
|
||||||
@Column(name = "fromdate", nullable = true)
|
@Column(name = "fromdate")
|
||||||
private LocalDate fromDate;
|
private LocalDate fromDate;
|
||||||
|
|
||||||
@Column(name = "duedate", nullable = false)
|
@Column(name = "duedate", nullable = false)
|
||||||
@@ -140,11 +141,9 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
// TODO: At some point in time this database column needs to be renamed to credited_principal using the following
|
// TODO: At some point in time this database column needs to be renamed to credited_principal using the following
|
||||||
// approach
|
// approach
|
||||||
// https://blog.thepete.net/blog/2023/12/05/expand/contract-making-a-breaking-change-without-a-big-bang/
|
// https://blog.thepete.net/blog/2023/12/05/expand/contract-making-a-breaking-change-without-a-big-bang/
|
||||||
@Setter
|
|
||||||
@Column(name = "credits_amount", scale = 6, precision = 19)
|
@Column(name = "credits_amount", scale = 6, precision = 19)
|
||||||
private BigDecimal creditedPrincipal;
|
private BigDecimal creditedPrincipal;
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Column(name = "credited_interest", scale = 6, precision = 19)
|
@Column(name = "credited_interest", scale = 6, precision = 19)
|
||||||
private BigDecimal creditedInterest;
|
private BigDecimal creditedInterest;
|
||||||
|
|
||||||
@@ -392,10 +391,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
return getInterestOutstanding(currency).isGreaterThanZero();
|
return getInterestOutstanding(currency).isGreaterThanZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
|
||||||
return getPrincipal(currency).plus(getInterestCharged(currency));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
||||||
return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency))
|
return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency))
|
||||||
.plus(getPenaltyChargesOutstanding(currency));
|
.plus(getPenaltyChargesOutstanding(currency));
|
||||||
@@ -405,10 +400,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
this.loan = loan;
|
this.loan = loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPartlyPaid() {
|
|
||||||
return !this.obligationsMet && (this.interestPaid != null || this.feeChargesPaid != null || this.principalCompleted != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotFullyPaidOff() {
|
public boolean isNotFullyPaidOff() {
|
||||||
return !this.obligationsMet;
|
return !this.obligationsMet;
|
||||||
}
|
}
|
||||||
@@ -734,18 +725,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
this.penaltyAccrued = MathUtil.zeroToNull(MathUtil.toBigDecimal(penalityCharges));
|
this.penaltyAccrued = MathUtil.zeroToNull(MathUtil.toBigDecimal(penalityCharges));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInterestAccrued(BigDecimal interestAccrued) {
|
|
||||||
this.interestAccrued = interestAccrued;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFeeAccrued(BigDecimal feeAccrued) {
|
|
||||||
this.feeAccrued = feeAccrued;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPenaltyAccrued(BigDecimal penaltyAccrued) {
|
|
||||||
this.penaltyAccrued = penaltyAccrued;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateObligationsMet(final MonetaryCurrency currency, final LocalDate transactionDate) {
|
public void updateObligationsMet(final MonetaryCurrency currency, final LocalDate transactionDate) {
|
||||||
if (!this.obligationsMet && getTotalOutstanding(currency).isZero()) {
|
if (!this.obligationsMet && getTotalOutstanding(currency).isZero()) {
|
||||||
this.obligationsMet = true;
|
this.obligationsMet = true;
|
||||||
@@ -802,18 +781,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
return Money.of(currency, this.totalPaidInAdvance);
|
return Money.of(currency, this.totalPaidInAdvance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalPaidLate(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.totalPaidLate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecalculatedInterestComponent() {
|
|
||||||
return this.recalculatedInterestComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecalculatedInterestComponent(boolean recalculatedInterestComponent) {
|
|
||||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateInstallmentNumber(final Integer installmentNumber) {
|
public void updateInstallmentNumber(final Integer installmentNumber) {
|
||||||
if (installmentNumber != null) {
|
if (installmentNumber != null) {
|
||||||
this.installmentNumber = installmentNumber;
|
this.installmentNumber = installmentNumber;
|
||||||
@@ -832,10 +799,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
this.obligationsMetOnDate = obligationsMetOnDate;
|
this.obligationsMetOnDate = obligationsMetOnDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateInterestWrittenOff(final BigDecimal interestWrittenOff) {
|
|
||||||
this.interestWrittenOff = interestWrittenOff;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updatePrincipal(final BigDecimal principal) {
|
public void updatePrincipal(final BigDecimal principal) {
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
}
|
}
|
||||||
@@ -1007,41 +970,15 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
.plus(getPenaltyChargesCharged(currency));
|
.plus(getPenaltyChargesCharged(currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
|
||||||
return this.loanCompoundingDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getAccruedInterestOutstanding(final MonetaryCurrency currency) {
|
|
||||||
final Money interestAccountedFor = getInterestPaid(currency).plus(getInterestWaived(currency))
|
|
||||||
.plus(getInterestWrittenOff(currency));
|
|
||||||
return getInterestAccrued(currency).minus(interestAccountedFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getTotalPaid(final MonetaryCurrency currency) {
|
public Money getTotalPaid(final MonetaryCurrency currency) {
|
||||||
return getPenaltyChargesPaid(currency).plus(getFeeChargesPaid(currency)).plus(getInterestPaid(currency))
|
return getPenaltyChargesPaid(currency).plus(getFeeChargesPaid(currency)).plus(getInterestPaid(currency))
|
||||||
.plus(getPrincipalCompleted(currency));
|
.plus(getPrincipalCompleted(currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
|
|
||||||
this.rescheduleInterestPortion = rescheduleInterestPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFeeChargesWaived(final BigDecimal newFeeChargesCharged) {
|
|
||||||
this.feeChargesWaived = newFeeChargesCharged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPenaltyChargesWaived(final BigDecimal newPenaltyChargesCharged) {
|
|
||||||
this.penaltyChargesWaived = newPenaltyChargesCharged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markAsAdditional() {
|
public void markAsAdditional() {
|
||||||
this.additional = true;
|
this.additional = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<LoanTransactionToRepaymentScheduleMapping> getLoanTransactionToRepaymentScheduleMappings() {
|
|
||||||
return this.loanTransactionToRepaymentScheduleMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetBalances() {
|
public void resetBalances() {
|
||||||
resetDerivedComponents();
|
resetDerivedComponents();
|
||||||
resetPrincipalDue();
|
resetPrincipalDue();
|
||||||
@@ -1071,57 +1008,149 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(final LoanScheduleModelPeriod period) {
|
public void copyFrom(final LoanScheduleModelPeriod period) {
|
||||||
|
// Reset fields and relations
|
||||||
resetBalances();
|
resetBalances();
|
||||||
|
updateLoanCompoundingDetails(period.getLoanCompoundingDetails());
|
||||||
|
getInstallmentCharges().clear();
|
||||||
|
getPostDatedChecks().clear();
|
||||||
|
getLoanTransactionToRepaymentScheduleMappings().clear();
|
||||||
|
// Update fields
|
||||||
setFromDate(period.periodFromDate());
|
setFromDate(period.periodFromDate());
|
||||||
setDueDate(period.periodDueDate());
|
setDueDate(period.periodDueDate());
|
||||||
setPrincipal(period.principalDue());
|
setPrincipal(period.principalDue());
|
||||||
setInterestCharged(period.interestDue());
|
setInterestCharged(period.interestDue());
|
||||||
setFeeChargesCharged(period.feeChargesDue());
|
setFeeChargesCharged(period.feeChargesDue());
|
||||||
setPenaltyCharges(period.penaltyChargesDue());
|
setPenaltyCharges(period.penaltyChargesDue());
|
||||||
|
|
||||||
setRecalculatedInterestComponent(period.isRecalculatedInterestComponent());
|
setRecalculatedInterestComponent(period.isRecalculatedInterestComponent());
|
||||||
if (getLoanCompoundingDetails() != null) {
|
|
||||||
getLoanCompoundingDetails().clear();
|
|
||||||
}
|
|
||||||
if (period.getLoanCompoundingDetails() != null) {
|
|
||||||
period.getLoanCompoundingDetails().forEach(lcd -> {
|
|
||||||
lcd.setLoanRepaymentScheduleInstallment(this);
|
|
||||||
getLoanCompoundingDetails().add(lcd);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setRescheduleInterestPortion(period.rescheduleInterestPortion());
|
setRescheduleInterestPortion(period.rescheduleInterestPortion());
|
||||||
setDownPayment(period.isDownPaymentPeriod());
|
setDownPayment(period.isDownPaymentPeriod());
|
||||||
|
|
||||||
setAdditional(false);
|
setAdditional(false);
|
||||||
setReAged(false);
|
setReAged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(final LoanRepaymentScheduleInstallment installment) {
|
public void copyFrom(final LoanRepaymentScheduleInstallment installment) {
|
||||||
|
if (getId().equals(installment.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reset balances
|
||||||
|
resetBalances();
|
||||||
|
// Dates
|
||||||
setFromDate(installment.getFromDate());
|
setFromDate(installment.getFromDate());
|
||||||
setDueDate(installment.getDueDate());
|
setDueDate(installment.getDueDate());
|
||||||
|
setObligationsMetOnDate(installment.getObligationsMetOnDate());
|
||||||
setPrincipal(installment.getPrincipal());
|
// Flags
|
||||||
setInterestCharged(installment.getInterestCharged());
|
setObligationsMet(installment.isObligationsMet());
|
||||||
setFeeChargesCharged(installment.getFeeChargesCharged());
|
|
||||||
setPenaltyCharges(installment.getPenaltyCharges());
|
|
||||||
setRecalculatedInterestComponent(installment.isRecalculatedInterestComponent());
|
|
||||||
if (getLoanCompoundingDetails() != null) {
|
|
||||||
getLoanCompoundingDetails().clear();
|
|
||||||
}
|
|
||||||
if (installment.getLoanCompoundingDetails() != null) {
|
|
||||||
installment.getLoanCompoundingDetails().forEach(lcd -> {
|
|
||||||
lcd.setLoanRepaymentScheduleInstallment(this);
|
|
||||||
getLoanCompoundingDetails().add(lcd);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<LoanInstallmentCharge> installmentCharges = installment.getInstallmentCharges();
|
|
||||||
installmentCharges.forEach(c -> c.setInstallment(this));
|
|
||||||
getInstallmentCharges().addAll(installmentCharges);
|
|
||||||
|
|
||||||
setAdditional(installment.isAdditional());
|
setAdditional(installment.isAdditional());
|
||||||
setReAged(installment.isReAged());
|
setReAged(installment.isReAged());
|
||||||
setDownPayment(installment.isDownPayment());
|
setDownPayment(installment.isDownPayment());
|
||||||
|
// Principal
|
||||||
|
setPrincipal(installment.getPrincipal());
|
||||||
|
setPrincipalCompleted(installment.getPrincipalCompleted());
|
||||||
|
setPrincipalWrittenOff(installment.getPrincipalWrittenOff());
|
||||||
|
// Interest
|
||||||
|
setInterestCharged(installment.getInterestCharged());
|
||||||
|
setInterestAccrued(installment.getInterestAccrued());
|
||||||
|
setInterestPaid(installment.getInterestPaid());
|
||||||
|
setInterestWaived(installment.getInterestWaived());
|
||||||
|
setInterestWrittenOff(installment.getInterestWrittenOff());
|
||||||
|
setRescheduleInterestPortion(installment.getRescheduleInterestPortion());
|
||||||
|
setRecalculatedInterestComponent(installment.isRecalculatedInterestComponent());
|
||||||
|
// Fee
|
||||||
|
setFeeChargesCharged(installment.getFeeChargesCharged());
|
||||||
|
setFeeChargesPaid(installment.getFeeChargesPaid());
|
||||||
|
setFeeAccrued(installment.getFeeAccrued());
|
||||||
|
setFeeChargesWaived(installment.getFeeChargesWaived());
|
||||||
|
setFeeChargesWrittenOff(installment.getFeeChargesWrittenOff());
|
||||||
|
// Penalty
|
||||||
|
setPenaltyCharges(installment.getPenaltyCharges());
|
||||||
|
setPenaltyAccrued(installment.getPenaltyAccrued());
|
||||||
|
setPenaltyChargesWaived(installment.getPenaltyChargesWaived());
|
||||||
|
setPenaltyChargesPaid(installment.getPenaltyChargesPaid());
|
||||||
|
setPenaltyChargesWrittenOff(installment.getPenaltyChargesWrittenOff());
|
||||||
|
// paid in advance / late
|
||||||
|
setTotalPaidInAdvance(installment.getTotalPaidInAdvance());
|
||||||
|
setTotalPaidLate(installment.getTotalPaidLate());
|
||||||
|
// Credits (Chargeback)
|
||||||
|
setCreditedFee(installment.getCreditedFee());
|
||||||
|
setCreditedPenalty(installment.getCreditedPenalty());
|
||||||
|
setCreditedInterest(installment.getCreditedInterest());
|
||||||
|
setCreditedPrincipal(installment.getCreditedPrincipal());
|
||||||
|
// Compounding details
|
||||||
|
updateLoanCompoundingDetails(installment.getLoanCompoundingDetails());
|
||||||
|
// Installment charges
|
||||||
|
updateLoaInstallmentCharges(installment.getInstallmentCharges());
|
||||||
|
// Post dated checks
|
||||||
|
updatePostDatedChecks(installment.getPostDatedChecks());
|
||||||
|
// Loan transaction repayment schedule mapping
|
||||||
|
updateTransactionRepaymentScheduleMapping(installment.getLoanTransactionToRepaymentScheduleMappings());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateLoanCompoundingDetails(Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails) {
|
||||||
|
Set<LoanInterestRecalcualtionAdditionalDetails> retainedLoanCompoundingDetails = new HashSet<>();
|
||||||
|
if (loanCompoundingDetails != null) {
|
||||||
|
loanCompoundingDetails.forEach(nlcd -> {
|
||||||
|
nlcd.setLoanRepaymentScheduleInstallment(this);
|
||||||
|
getLoanCompoundingDetails().stream().filter(lcd -> MathUtil.isEqualTo(lcd.getAmount(), nlcd.getAmount()) //
|
||||||
|
&& DateUtils.isEqual(lcd.getEffectiveDate(), nlcd.getEffectiveDate())) //
|
||||||
|
.findAny().ifPresentOrElse(retainedLoanCompoundingDetails::add, () -> retainedLoanCompoundingDetails.add(nlcd));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoanCompoundingDetails(retainedLoanCompoundingDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLoaInstallmentCharges(Set<LoanInstallmentCharge> installmentCharges) {
|
||||||
|
Set<LoanInstallmentCharge> retainedInstallmentCharges = new HashSet<>();
|
||||||
|
if (installmentCharges != null) {
|
||||||
|
installmentCharges.forEach(nic -> {
|
||||||
|
nic.setInstallment(this);
|
||||||
|
getInstallmentCharges().stream().filter(ic -> MathUtil.isEqualTo(ic.getAmountOutstanding(), nic.getAmountOutstanding()) //
|
||||||
|
&& MathUtil.isEqualTo(ic.getAmountWrittenOff(), nic.getAmountWrittenOff()) //
|
||||||
|
&& MathUtil.isEqualTo(ic.getAmountPaid(), nic.getAmountPaid()) //
|
||||||
|
&& MathUtil.isEqualTo(ic.getAmountThroughChargePayment(), nic.getAmountThroughChargePayment()) //
|
||||||
|
&& MathUtil.isEqualTo(ic.getAmountWaived(), nic.getAmountWaived()) //
|
||||||
|
&& MathUtil.isEqualTo(ic.getAmount(), nic.getAmount()) //
|
||||||
|
&& Boolean.logicalAnd(ic.isPaid(), nic.isPaid()) //
|
||||||
|
&& Boolean.logicalAnd(ic.isWaived(), nic.isWaived()) //
|
||||||
|
&& Boolean.logicalAnd(ic.isPending(), nic.isPending())) //
|
||||||
|
.findAny().ifPresentOrElse(retainedInstallmentCharges::add, () -> retainedInstallmentCharges.add(nic));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setInstallmentCharges(retainedInstallmentCharges);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePostDatedChecks(Set<PostDatedChecks> postDatedChecks) {
|
||||||
|
Set<PostDatedChecks> retainedPostDatedChecks = new HashSet<>();
|
||||||
|
if (postDatedChecks != null) {
|
||||||
|
postDatedChecks.forEach(npdc -> {
|
||||||
|
npdc.setLoanRepaymentScheduleInstallment(this);
|
||||||
|
getPostDatedChecks().stream().filter(pdc -> MathUtil.isEqualTo(pdc.getCheckNo(), npdc.getCheckNo()) //
|
||||||
|
&& MathUtil.isEqualTo(pdc.getAccountNo(), npdc.getAccountNo()) //
|
||||||
|
&& MathUtil.isEqualTo(pdc.getAmount(), npdc.getAmount()) //
|
||||||
|
&& StringUtils.equals(pdc.getBankName(), npdc.getBankName()) //
|
||||||
|
&& MathUtil.isEqualTo(pdc.getStatus(), npdc.getStatus()) //
|
||||||
|
&& DateUtils.isEqual(pdc.getRepaymentDate(), npdc.getRepaymentDate())) //
|
||||||
|
.findAny().ifPresentOrElse(retainedPostDatedChecks::add, () -> retainedPostDatedChecks.add(npdc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setPostDatedChecks(retainedPostDatedChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTransactionRepaymentScheduleMapping(
|
||||||
|
Set<LoanTransactionToRepaymentScheduleMapping> transactionToRepaymentScheduleMappings) {
|
||||||
|
Set<LoanTransactionToRepaymentScheduleMapping> retainedTransactionRepaymentScheduleMapping = new HashSet<>();
|
||||||
|
if (transactionToRepaymentScheduleMappings != null) {
|
||||||
|
transactionToRepaymentScheduleMappings.forEach(ntrsm -> {
|
||||||
|
ntrsm.setInstallment(this);
|
||||||
|
getLoanTransactionToRepaymentScheduleMappings().stream()
|
||||||
|
.filter(trsm -> MathUtil.isEqualTo(trsm.getAmount(), ntrsm.getAmount()) //
|
||||||
|
&& MathUtil.isEqualTo(trsm.getFeeChargesPortion(), ntrsm.getFeeChargesPortion()) //
|
||||||
|
&& MathUtil.isEqualTo(trsm.getInterestPortion(), ntrsm.getInterestPortion()) //
|
||||||
|
&& MathUtil.isEqualTo(trsm.getPrincipalPortion(), ntrsm.getPrincipalPortion()) //
|
||||||
|
&& MathUtil.isEqualTo(trsm.getPenaltyChargesPortion(), ntrsm.getPenaltyChargesPortion())) //
|
||||||
|
.findAny().ifPresentOrElse(retainedTransactionRepaymentScheduleMapping::add,
|
||||||
|
() -> retainedTransactionRepaymentScheduleMapping.add(ntrsm));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoanTransactionToRepaymentScheduleMappings(retainedTransactionRepaymentScheduleMapping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-33
@@ -25,20 +25,24 @@ import jakarta.persistence.JoinColumn;
|
|||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_loan_transaction_repayment_schedule_mapping")
|
@Table(name = "m_loan_transaction_repayment_schedule_mapping")
|
||||||
|
@Getter
|
||||||
public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistableCustom<Long> {
|
public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistableCustom<Long> {
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||||
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
||||||
private LoanTransaction loanTransaction;
|
private LoanTransaction loanTransaction;
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||||
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
||||||
private LoanRepaymentScheduleInstallment installment;
|
private LoanRepaymentScheduleInstallment installment;
|
||||||
@@ -137,36 +141,4 @@ public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistab
|
|||||||
return Money.of(currency, this.penaltyChargesPortion);
|
return Money.of(currency, this.penaltyChargesPortion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getPortion(AllocationType allocationType) {
|
|
||||||
return switch (allocationType) {
|
|
||||||
case PRINCIPAL -> getPrincipalPortion();
|
|
||||||
case INTEREST -> getInterestPortion();
|
|
||||||
case FEE -> getFeeChargesPortion();
|
|
||||||
case PENALTY -> getPenaltyChargesPortion();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanTransaction getLoanTransaction() {
|
|
||||||
return loanTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getPrincipalPortion() {
|
|
||||||
return this.principalPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getInterestPortion() {
|
|
||||||
return this.interestPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getFeeChargesPortion() {
|
|
||||||
return this.feeChargesPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getPenaltyChargesPortion() {
|
|
||||||
return this.penaltyChargesPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoanTransaction(LoanTransaction loanTransaction) {
|
|
||||||
this.loanTransaction = loanTransaction;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-41
@@ -27,6 +27,8 @@ import java.math.BigDecimal;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -34,11 +36,14 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
|
|||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_repayment_with_post_dated_checks")
|
@Table(name = "m_repayment_with_post_dated_checks")
|
||||||
|
@Getter
|
||||||
public class PostDatedChecks extends AbstractPersistableCustom<Long> {
|
public class PostDatedChecks extends AbstractPersistableCustom<Long> {
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "loan_id", referencedColumnName = "id", nullable = false)
|
@JoinColumn(name = "loan_id", referencedColumnName = "id", nullable = false)
|
||||||
private Loan loan;
|
private Loan loan;
|
||||||
|
@Setter
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "repayment_id", referencedColumnName = "id", nullable = false)
|
@JoinColumn(name = "repayment_id", referencedColumnName = "id", nullable = false)
|
||||||
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
||||||
@@ -50,6 +55,7 @@ public class PostDatedChecks extends AbstractPersistableCustom<Long> {
|
|||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
@Column(name = "repayment_date", nullable = false)
|
@Column(name = "repayment_date", nullable = false)
|
||||||
private LocalDate repaymentDate;
|
private LocalDate repaymentDate;
|
||||||
|
@Setter
|
||||||
@Column(name = "status", columnDefinition = "0")
|
@Column(name = "status", columnDefinition = "0")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
@Column(name = "check_no", nullable = false, unique = true)
|
@Column(name = "check_no", nullable = false, unique = true)
|
||||||
@@ -75,14 +81,6 @@ public class PostDatedChecks extends AbstractPersistableCustom<Long> {
|
|||||||
loanRepaymentScheduleInstallment.getDueDate(), loan, checkNo);
|
loanRepaymentScheduleInstallment.getDueDate(), loan, checkNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoan(Loan loan) {
|
|
||||||
this.loan = loan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoanRepaymentScheduleInstallment(final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
|
||||||
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> updatePostDatedChecks(JsonCommand command) {
|
public Map<String, Object> updatePostDatedChecks(JsonCommand command) {
|
||||||
final Map<String, Object> changes = new HashMap<>();
|
final Map<String, Object> changes = new HashMap<>();
|
||||||
|
|
||||||
@@ -112,37 +110,4 @@ public class PostDatedChecks extends AbstractPersistableCustom<Long> {
|
|||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Loan getLoan() {
|
|
||||||
return this.loan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
|
||||||
return this.loanRepaymentScheduleInstallment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(Integer status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBankName() {
|
|
||||||
return this.bankName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getCheckNo() {
|
|
||||||
return this.checkNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getAccountNo() {
|
|
||||||
return this.accountNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getAmount() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getStatus() {
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -425,8 +425,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
loanApplicationTerms.getInterestMethod());
|
loanApplicationTerms.getInterestMethod());
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
|
final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
|
||||||
loan.setHelpers(loanLifecycleStateMachine);
|
loan.setHelpers(loanLifecycleStateMachine);
|
||||||
final LoanScheduleDTO loanScheduleDTO = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, loan,
|
final LoanScheduleDTO loanScheduleDTO = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms,
|
||||||
loanApplicationTerms.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
|
loan, loanApplicationTerms.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
|
||||||
|
|
||||||
// Either the installments got recalculated or the model
|
// Either the installments got recalculated or the model
|
||||||
if (loanScheduleDTO.getInstallments() != null) {
|
if (loanScheduleDTO.getInstallments() != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user