MIFOSX-175: break out overdue fields into one-to-one table with shared primary key.
This commit is contained in:
+8
@@ -24,6 +24,7 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
@@ -242,6 +243,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
@Embedded
|
||||
private LoanSummary summary;
|
||||
|
||||
@OneToOne(mappedBy = "loan", cascade = CascadeType.ALL)
|
||||
private LoanSummaryArrearsAging summaryArrearsAging;
|
||||
|
||||
@Transient
|
||||
private boolean accountNumberRequiresAutoGeneration = false;
|
||||
@Transient
|
||||
@@ -315,9 +319,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (loanCharges != null && !loanCharges.isEmpty()) {
|
||||
this.charges = associateChargesWithThisLoan(loanCharges);
|
||||
this.summary = updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
this.summaryArrearsAging = new LoanSummaryArrearsAging(this);
|
||||
} else {
|
||||
this.charges = null;
|
||||
this.summary = new LoanSummary();
|
||||
this.summaryArrearsAging = new LoanSummaryArrearsAging(this);
|
||||
}
|
||||
if (collateral != null && !collateral.isEmpty()) {
|
||||
this.collateral = associateWithThisLoan(collateral);
|
||||
@@ -668,9 +674,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
if (isNotDisbursed()) {
|
||||
this.summary.zeroFields();
|
||||
this.summaryArrearsAging.zeroFields();
|
||||
} else {
|
||||
final Money principal = this.loanRepaymentScheduleDetail.getPrincipal();
|
||||
this.summary.updateSummary(loanCurrency(), principal, this.repaymentScheduleInstallments, this.loanSummaryWrapper);
|
||||
this.summaryArrearsAging.updateSummary(loanCurrency(), this.repaymentScheduleInstallments, this.loanSummaryWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-52
@@ -1,16 +1,11 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
@@ -33,9 +28,6 @@ public final class LoanSummary {
|
||||
@Column(name = "principal_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOutstanding;
|
||||
|
||||
@Column(name = "principal_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOverdue;
|
||||
|
||||
@Column(name = "interest_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestCharged;
|
||||
|
||||
@@ -51,9 +43,6 @@ public final class LoanSummary {
|
||||
@Column(name = "interest_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOutstanding;
|
||||
|
||||
@Column(name = "interest_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOverdue;
|
||||
|
||||
@Column(name = "fee_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesCharged;
|
||||
|
||||
@@ -72,9 +61,6 @@ public final class LoanSummary {
|
||||
@Column(name = "fee_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOutstanding;
|
||||
|
||||
@Column(name = "fee_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOverdue;
|
||||
|
||||
@Column(name = "penalty_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesCharged;
|
||||
|
||||
@@ -90,9 +76,6 @@ public final class LoanSummary {
|
||||
@Column(name = "penalty_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOutstanding;
|
||||
|
||||
@Column(name = "penalty_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_expected_repayment_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalExpectedRepayment;
|
||||
@@ -120,15 +103,6 @@ public final class LoanSummary {
|
||||
@Column(name = "total_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOutstanding;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "overdue_since_date_derived")
|
||||
private Date overdueSinceDate;
|
||||
|
||||
public static LoanSummary create(final BigDecimal totalFeeChargesDueAtDisbursement) {
|
||||
return new LoanSummary(totalFeeChargesDueAtDisbursement);
|
||||
}
|
||||
@@ -166,25 +140,21 @@ public final class LoanSummary {
|
||||
this.totalPrincipalRepaid = BigDecimal.ZERO;
|
||||
this.totalPrincipalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPrincipalOutstanding = BigDecimal.ZERO;
|
||||
this.totalPrincipalOverdue = BigDecimal.ZERO;
|
||||
this.totalInterestCharged = BigDecimal.ZERO;
|
||||
this.totalInterestRepaid = BigDecimal.ZERO;
|
||||
this.totalInterestWaived = BigDecimal.ZERO;
|
||||
this.totalInterestWrittenOff = BigDecimal.ZERO;
|
||||
this.totalInterestOutstanding = BigDecimal.ZERO;
|
||||
this.totalInterestOverdue = BigDecimal.ZERO;
|
||||
this.totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
this.totalFeeChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalExpectedRepayment = BigDecimal.ZERO;
|
||||
this.totalRepayment = BigDecimal.ZERO;
|
||||
this.totalExpectedCostOfLoan = BigDecimal.ZERO;
|
||||
@@ -192,8 +162,6 @@ public final class LoanSummary {
|
||||
this.totalWaived = BigDecimal.ZERO;
|
||||
this.totalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalOutstanding = BigDecimal.ZERO;
|
||||
this.totalOverdue = BigDecimal.ZERO;
|
||||
this.overdueSinceDate = null;
|
||||
}
|
||||
|
||||
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
||||
@@ -205,8 +173,6 @@ public final class LoanSummary {
|
||||
.getAmount();
|
||||
|
||||
this.totalPrincipalOutstanding = principal.minus(totalPrincipalRepaid).minus(totalPrincipalWrittenOff).getAmount();
|
||||
this.totalPrincipalOverdue = summaryWrapper.calculateTotalPrincipalOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
|
||||
final Money totalInterestCharged = summaryWrapper.calculateTotalInterestCharged(repaymentScheduleInstallments, currency);
|
||||
this.totalInterestCharged = totalInterestCharged.getAmount();
|
||||
@@ -217,8 +183,6 @@ public final class LoanSummary {
|
||||
if (totalInterestCharged.isGreaterThanZero()) {
|
||||
this.totalInterestOutstanding = totalInterestCharged.minus(this.totalInterestRepaid).minus(this.totalInterestWaived)
|
||||
.minus(this.totalInterestWrittenOff).getAmount();
|
||||
this.totalInterestOverdue = summaryWrapper.calculateTotalInterestOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalFeeChargesCharged = summaryWrapper.calculateTotalFeeChargesCharged(repaymentScheduleInstallments, currency);
|
||||
@@ -231,8 +195,6 @@ public final class LoanSummary {
|
||||
if (totalFeeChargesCharged.isGreaterThanZero()) {
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesCharged.minus(this.totalFeeChargesRepaid).minus(this.totalFeeChargesWaived)
|
||||
.minus(this.totalFeeChargesWrittenOff).getAmount();
|
||||
this.totalFeeChargesOverdue = summaryWrapper.calculateTotalFeeChargesOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalPenaltyChargesCharged = summaryWrapper
|
||||
@@ -248,8 +210,6 @@ public final class LoanSummary {
|
||||
if (totalPenaltyChargesCharged.isGreaterThanZero()) {
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged.minus(this.totalPenaltyChargesRepaid)
|
||||
.minus(this.totalPenaltyChargesWaived).minus(this.totalPenaltyChargesWrittenOff).getAmount();
|
||||
this.totalPenaltyChargesOverdue = summaryWrapper.calculateTotalPenaltyChargesOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
}
|
||||
|
||||
final Money totalExpectedRepayment = Money.of(currency, this.totalPrincipalDisbursed).plus(this.totalInterestCharged)
|
||||
@@ -279,17 +239,5 @@ public final class LoanSummary {
|
||||
final Money totalOutstanding = Money.of(currency, this.totalPrincipalOutstanding).plus(this.totalInterestOutstanding)
|
||||
.plus(this.totalFeeChargesOutstanding).plus(this.totalPenaltyChargesOutstanding);
|
||||
this.totalOutstanding = totalOutstanding.getAmount();
|
||||
|
||||
final Money totalOverdue = Money.of(currency, this.totalPrincipalOverdue).plus(this.totalInterestOverdue)
|
||||
.plus(this.totalFeeChargesOverdue).plus(this.totalPenaltyChargesOverdue);
|
||||
this.totalOverdue = totalOverdue.getAmount();
|
||||
|
||||
final LocalDate overdueSinceLocalDate = summaryWrapper.determineOverdueSinceDateFrom(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
if (overdueSinceLocalDate != null) {
|
||||
this.overdueSinceDate = overdueSinceLocalDate.toDate();
|
||||
} else {
|
||||
this.overdueSinceDate = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A specialist view of arrears & aging summary details of a {@link Loan}.
|
||||
* <p>
|
||||
*
|
||||
* <p>
|
||||
* This is intentionally split from the loan summary concept and maps to its own
|
||||
* table that contains only arrears and aging information. The reason is to make
|
||||
* any overnight batch update of these details simpler and improve performance.
|
||||
* </p>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_loan_arrears_aging")
|
||||
public final class LoanSummaryArrearsAging implements Persistable<Long> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "SharedPrimaryKeyGenerator")
|
||||
@GenericGenerator(name = "SharedPrimaryKeyGenerator", strategy = "foreign", parameters = @Parameter(name = "property", value = "loan"))
|
||||
@Column(name = "loan_id", unique = true, nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "principal_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOverdue;
|
||||
|
||||
@Column(name = "interest_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOverdue;
|
||||
|
||||
@Column(name = "fee_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOverdue;
|
||||
|
||||
@Column(name = "penalty_charges_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_overdue_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverdue;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "overdue_since_date_derived")
|
||||
private Date overdueSinceDate;
|
||||
|
||||
@OneToOne
|
||||
@PrimaryKeyJoinColumn
|
||||
private Loan loan;
|
||||
|
||||
protected LoanSummaryArrearsAging() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanSummaryArrearsAging(final Loan loan) {
|
||||
this.loan = loan;
|
||||
zeroFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return null == getId();
|
||||
}
|
||||
|
||||
public void zeroFields() {
|
||||
this.totalPrincipalOverdue = BigDecimal.ZERO;
|
||||
this.totalInterestOverdue = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOverdue = BigDecimal.ZERO;
|
||||
this.totalOverdue = BigDecimal.ZERO;
|
||||
this.overdueSinceDate = null;
|
||||
}
|
||||
|
||||
public void updateSummary(final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final LoanSummaryWrapper summaryWrapper) {
|
||||
|
||||
this.totalPrincipalOverdue = summaryWrapper.calculateTotalPrincipalOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
this.totalInterestOverdue = summaryWrapper.calculateTotalInterestOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
this.totalFeeChargesOverdue = summaryWrapper.calculateTotalFeeChargesOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
this.totalPenaltyChargesOverdue = summaryWrapper.calculateTotalPenaltyChargesOverdueOn(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant()).getAmount();
|
||||
|
||||
final Money totalOverdue = Money.of(currency, this.totalPrincipalOverdue).plus(this.totalInterestOverdue)
|
||||
.plus(this.totalFeeChargesOverdue).plus(this.totalPenaltyChargesOverdue);
|
||||
this.totalOverdue = totalOverdue.getAmount();
|
||||
|
||||
final LocalDate overdueSinceLocalDate = summaryWrapper.determineOverdueSinceDateFrom(repaymentScheduleInstallments, currency,
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
if (overdueSinceLocalDate != null) {
|
||||
this.overdueSinceDate = overdueSinceLocalDate.toDate();
|
||||
} else {
|
||||
this.overdueSinceDate = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -283,26 +283,22 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.principal_repaid_derived as principalPaid,"
|
||||
+ " l.principal_writtenoff_derived as principalWrittenOff,"
|
||||
+ " l.principal_outstanding_derived as principalOutstanding,"
|
||||
+ " l.principal_overdue_derived as principalOverdue,"
|
||||
+ " l.interest_charged_derived as interestCharged,"
|
||||
+ " l.interest_repaid_derived as interestPaid,"
|
||||
+ " l.interest_waived_derived as interestWaived,"
|
||||
+ " l.interest_writtenoff_derived as interestWrittenOff,"
|
||||
+ " l.interest_outstanding_derived as interestOutstanding,"
|
||||
+ " l.interest_overdue_derived as interestOverdue,"
|
||||
+ " l.fee_charges_charged_derived as feeChargesCharged,"
|
||||
+ " l.total_charges_due_at_disbursement_derived as feeChargesDueAtDisbursementCharged,"
|
||||
+ " l.fee_charges_repaid_derived as feeChargesPaid,"
|
||||
+ " l.fee_charges_waived_derived as feeChargesWaived,"
|
||||
+ " l.fee_charges_writtenoff_derived as feeChargesWrittenOff,"
|
||||
+ " l.fee_charges_outstanding_derived as feeChargesOutstanding,"
|
||||
+ " l.fee_charges_overdue_derived as feeChargesOverdue,"
|
||||
+ " l.penalty_charges_charged_derived as penaltyChargesCharged,"
|
||||
+ " l.penalty_charges_repaid_derived as penaltyChargesPaid,"
|
||||
+ " l.penalty_charges_waived_derived as penaltyChargesWaived,"
|
||||
+ " l.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff,"
|
||||
+ " l.penalty_charges_outstanding_derived as penaltyChargesOutstanding,"
|
||||
+ " l.penalty_charges_overdue_derived as penaltyChargesOverdue,"
|
||||
+ " l.total_expected_repayment_derived as totalExpectedRepayment,"
|
||||
+ " l.total_repayment_derived as totalRepayment,"
|
||||
+ " l.total_expected_costofloan_derived as totalExpectedCostOfLoan,"
|
||||
@@ -310,13 +306,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.total_waived_derived as totalWaived,"
|
||||
+ " l.total_writtenoff_derived as totalWrittenOff,"
|
||||
+ " l.total_outstanding_derived as totalOutstanding,"
|
||||
+ " l.total_overdue_derived as totalOverdue,"
|
||||
+ " l.overdue_since_date_derived as overdueSinceDate"
|
||||
+ " la.principal_overdue_derived as principalOverdue,"
|
||||
+ " la.interest_overdue_derived as interestOverdue,"
|
||||
+ " la.fee_charges_overdue_derived as feeChargesOverdue,"
|
||||
+ " la.penalty_charges_overdue_derived as penaltyChargesOverdue,"
|
||||
+ " la.total_overdue_derived as totalOverdue,"
|
||||
+ " la.overdue_since_date_derived as overdueSinceDate"
|
||||
+ " from m_loan l" //
|
||||
+ " left join m_client c on c.id = l.client_id" //
|
||||
+ " left join m_group g on g.id = l.group_id" //
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||
+ " join m_currency rc on rc.`code` = l.currency_code" //
|
||||
+ " join m_loan_arrears_aging la on la.loan_id = l.id" //
|
||||
+ " left join m_fund f on f.id = l.fund_id" //
|
||||
+ " left join m_staff s on s.id = l.loan_officer_id" //
|
||||
+ " left join m_appuser sbu on sbu.id = l.submittedon_userid"
|
||||
|
||||
Reference in New Issue
Block a user