From 4830b85493b596c6abb6faa0b98c564f336943a9 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Tue, 25 Sep 2012 15:59:45 +0100 Subject: [PATCH] ensure payment of charges due at disbursement are captured on a transaction that is automaticatly entered when disbursement of loan occurs. --- ..._charges_component_to_loan_transaction.sql | 2 + .../platform/api/data/DisbursementData.java | 4 ++ .../platform/api/data/LoanChargeData.java | 64 ++++++++----------- .../api/data/LoanSchedulePeriodData.java | 21 ++++-- .../platform/currency/domain/Money.java | 10 ++- ...RepaymentScheduleTransactionProcessor.java | 16 ++--- ...RepaymentScheduleTransactionProcessor.java | 6 +- ...RepaymentScheduleTransactionProcessor.java | 21 ++---- .../mifosng/platform/loan/domain/Loan.java | 56 +++++++++------- .../platform/loan/domain/LoanTransaction.java | 33 ++++++++-- .../loan/domain/LoanTransactionType.java | 6 +- ...RepaymentScheduleTransactionProcessor.java | 6 +- .../service/LoanReadPlatformServiceImpl.java | 5 +- ...entsAmortizationLoanScheduleGenerator.java | 2 +- ...ipalAmortizationLoanScheduleGenerator.java | 2 +- .../FlatMethodLoanScheduleGenerator.java | 2 +- 16 files changed, 143 insertions(+), 113 deletions(-) create mode 100644 mifosng-db/patches/patch-0007-add_charges_component_to_loan_transaction.sql diff --git a/mifosng-db/patches/patch-0007-add_charges_component_to_loan_transaction.sql b/mifosng-db/patches/patch-0007-add_charges_component_to_loan_transaction.sql new file mode 100644 index 000000000..c876dcf22 --- /dev/null +++ b/mifosng-db/patches/patch-0007-add_charges_component_to_loan_transaction.sql @@ -0,0 +1,2 @@ +ALTER TABLE `m_loan_transaction` +ADD COLUMN `charges_portion_derived` decimal(19,6) DEFAULT NULL AFTER `interest_waived_derived`; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DisbursementData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DisbursementData.java index ae637c4b2..9d20402c5 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DisbursementData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DisbursementData.java @@ -30,4 +30,8 @@ public class DisbursementData { public BigDecimal amount() { return this.principalDisbursed; } + + public boolean isDisbursed() { + return this.actualDisbursementDate != null; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanChargeData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanChargeData.java index ebb183ff1..7004a43a6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanChargeData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanChargeData.java @@ -8,24 +8,36 @@ import java.util.Collection; */ public class LoanChargeData { + @SuppressWarnings("unused") private final Long id; + @SuppressWarnings("unused") private final Long chargeId; - + @SuppressWarnings("unused") private final String name; + @SuppressWarnings("unused") private final CurrencyData currency; - + @SuppressWarnings("unused") private final BigDecimal amount; + @SuppressWarnings("unused") private final EnumOptionData chargeTimeType; + @SuppressWarnings("unused") private final EnumOptionData chargeCalculationType; - private final Collection chargeOptions; + @SuppressWarnings("unused") + private final Collection chargeOptions; public static LoanChargeData template(final Collection chargeOptions){ return new LoanChargeData(null,null,null,null,null,null,null, chargeOptions); } - public LoanChargeData(Long id, Long chargeId, String name, CurrencyData currency, BigDecimal amount, - EnumOptionData chargeTimeType, EnumOptionData chargeCalculationType) { + public LoanChargeData( + final Long id, + final Long chargeId, + final String name, + final CurrencyData currency, + final BigDecimal amount, + final EnumOptionData chargeTimeType, + final EnumOptionData chargeCalculationType) { this.id = id; this.chargeId = chargeId; this.name = name; @@ -37,9 +49,15 @@ public class LoanChargeData { this.chargeOptions = null; } - public LoanChargeData(Long id, Long chargeId, String name, CurrencyData currency, BigDecimal amount, - EnumOptionData chargeTimeType, EnumOptionData chargeCalculationType, - Collection chargeOptions) { + public LoanChargeData( + final Long id, + final Long chargeId, + final String name, + final CurrencyData currency, + final BigDecimal amount, + final EnumOptionData chargeTimeType, + final EnumOptionData chargeCalculationType, + final Collection chargeOptions) { this.id = id; this.chargeId = chargeId; this.name = name; @@ -49,32 +67,4 @@ public class LoanChargeData { this.chargeCalculationType = chargeCalculationType; this.chargeOptions = chargeOptions; } - - public Long getId() { - return id; - } - - public Long getChargeId() { - return chargeId; - } - - public String getName() { - return name; - } - - public CurrencyData getCurrency() { - return currency; - } - - public BigDecimal getAmount() { - return amount; - } - - public EnumOptionData getChargeTimeType() { - return chargeTimeType; - } - - public EnumOptionData getChargeCalculationType() { - return chargeCalculationType; - } -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java index 05bb31368..40645bc63 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java @@ -43,10 +43,11 @@ public class LoanSchedulePeriodData { public static LoanSchedulePeriodData disbursementOnlyPeriod( final LocalDate disbursementDate, final BigDecimal principalDisbursed, - final BigDecimal chargesDueAtTimeOfDisbursement) { + final BigDecimal chargesDueAtTimeOfDisbursement, + final boolean isDisbursed) { Integer periodNumber = Integer.valueOf(0); LocalDate from = null; - return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, chargesDueAtTimeOfDisbursement); + return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, chargesDueAtTimeOfDisbursement, isDisbursed); } public static LoanSchedulePeriodData repaymentOnlyPeriod(final Integer periodNumber, @@ -89,7 +90,8 @@ public class LoanSchedulePeriodData { final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principalDisbursed, - final BigDecimal chargesDueAtTimeOfDisbursement) { + final BigDecimal chargesDueAtTimeOfDisbursement, + final boolean isDisbursed) { this.period = periodNumber; this.fromDate = fromDate; this.dueDate = dueDate; @@ -112,14 +114,19 @@ public class LoanSchedulePeriodData { this.interestOutstanding = null; this.chargesDue = chargesDueAtTimeOfDisbursement; - this.chargesPaid = null; - this.chargesOutstanding = chargesDueAtTimeOfDisbursement; + if (isDisbursed) { + this.chargesPaid = chargesDueAtTimeOfDisbursement; + this.chargesOutstanding = BigDecimal.ZERO; + } else { + this.chargesPaid = BigDecimal.ZERO; + this.chargesOutstanding = chargesDueAtTimeOfDisbursement; + } this.totalOriginalDueForPeriod = chargesDueAtTimeOfDisbursement; this.totalDueForPeriod = chargesDueAtTimeOfDisbursement; - this.totalPaidForPeriod = BigDecimal.ZERO; + this.totalPaidForPeriod = this.chargesPaid; this.totalWaivedForPeriod = null; - this.totalOutstandingForPeriod = chargesDueAtTimeOfDisbursement; + this.totalOutstandingForPeriod = this.chargesOutstanding; if (dueDate.isBefore(new LocalDate())) { this.totalOverdue = this.totalOutstandingForPeriod; } else { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/currency/domain/Money.java b/mifosng-provider/src/main/java/org/mifosng/platform/currency/domain/Money.java index bb3a7cc1f..b1f249e30 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/currency/domain/Money.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/currency/domain/Money.java @@ -39,7 +39,7 @@ public class Money implements Comparable, Serializable { return total; } - public static Money of(MonetaryCurrency currency, BigDecimal newAmount) { + public static Money of(final MonetaryCurrency currency, final BigDecimal newAmount) { return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), newAmount); } @@ -56,8 +56,12 @@ public class Money implements Comparable, Serializable { private Money(final String currencyCode, final int digitsAfterDecimal, final BigDecimal amount) { this.currencyCode = currencyCode; this.currencyDigitsAfterDecimal = digitsAfterDecimal; - BigDecimal amountStripped = amount.stripTrailingZeros(); - this.amount = amountStripped.setScale(this.currencyDigitsAfterDecimal, RoundingMode.HALF_EVEN); + if (amount != null) { + BigDecimal amountStripped = amount.stripTrailingZeros(); + this.amount = amountStripped.setScale(this.currencyDigitsAfterDecimal, RoundingMode.HALF_EVEN); + } else { + this.amount = BigDecimal.ZERO; + } } public Money copy() { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java index c7c83068f..2c70ef6da 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java @@ -79,7 +79,7 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo Money principalPortion = Money.zero(currency); Money interestWaivedPortion = Money.zero(currency); - loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion); + loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); } } @@ -91,7 +91,7 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo Money interestPortion = Money.zero(currency); Money interestWaivedPortion = Money.zero(currency); - loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion); + loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); } } @@ -125,15 +125,11 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo Money interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining); transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion); - Money principalPortion = currentInstallment - .payPrincipalComponent(transactionAmountRemaining); - transactionAmountRemaining = transactionAmountRemaining - .minus(principalPortion); + Money principalPortion = currentInstallment.payPrincipalComponent(transactionAmountRemaining); + transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion); - Money interestWaivedPortion = Money.zero(transactionAmountRemaining - .getCurrency()); - loanTransaction.updateComponents(principalPortion, interestPortion, - interestWaivedPortion); + Money interestWaivedPortion = Money.zero(transactionAmountRemaining.getCurrency()); + loanTransaction.updateComponents(principalPortion, interestPortion,interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); return transactionAmountRemaining; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java index efbef5f60..66d3d37bc 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java @@ -90,10 +90,8 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends transactionAmountRemaining = transactionAmountRemaining .minus(principalPortion); - Money interestWaivedPortion = Money.zero(transactionAmountRemaining - .getCurrency()); - loanTransaction.updateComponents(principalPortion, interestPortion, - interestWaivedPortion); + Money interestWaivedPortion = Money.zero(transactionAmountRemaining.getCurrency()); + loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); return transactionAmountRemaining; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java index 977e9e427..7b8ca1c80 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java @@ -84,8 +84,7 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst .getInterest(currency)); } - loanTransaction.updateComponents(principalPortion, interestPortion, - interestWaivedPortion); + loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); transactionAmountRemaining = transactionAmountRemaining .minus(principalPortion); @@ -105,20 +104,14 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst Money transactionAmountRemaining = transactionAmountUnprocessed; - Money interestPortion = currentInstallment - .payInterestComponent(transactionAmountRemaining); - transactionAmountRemaining = transactionAmountRemaining - .minus(interestPortion); + Money interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining); + transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion); - Money principalPortion = currentInstallment - .payPrincipalComponent(transactionAmountRemaining); - transactionAmountRemaining = transactionAmountRemaining - .minus(principalPortion); + Money principalPortion = currentInstallment.payPrincipalComponent(transactionAmountRemaining); + transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion); - Money interestWaivedPortion = Money.zero(transactionAmountRemaining - .getCurrency()); - loanTransaction.updateComponents(principalPortion, interestPortion, - interestWaivedPortion); + Money interestWaivedPortion = Money.zero(transactionAmountRemaining.getCurrency()); + loanTransaction.updateComponents(principalPortion, interestPortion, interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); return transactionAmountRemaining; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java index d6d26f665..3e76a0525 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java @@ -155,7 +155,6 @@ public class Loan extends AbstractAuditableCustom { @Column(name = "interest_rebate_amount", scale = 6, precision = 19) private BigDecimal interestRebateOwed; - @SuppressWarnings("unused") // derived field used in GETs only at present @Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19) private BigDecimal totalChargesDueAtDisbursement; @@ -322,14 +321,7 @@ public class Loan extends AbstractAuditableCustom { } // if the loan application/contract is modified when repayments are already against it - then need to re-process it - List repaymentsOrWaivers = new ArrayList(); - for (LoanTransaction transaction : this.loanTransactions) { - if (!transaction.isDisbursement() && transaction.isNotContra()) { - repaymentsOrWaivers.add(transaction); - } - } - LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); - Collections.sort(repaymentsOrWaivers, transactionComparator); + final List repaymentsOrWaivers = retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement(); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); loanRepaymentScheduleTransactionProcessor.handleTransaction(repaymentsOrWaivers, getCurrency(), this.repaymentScheduleInstallments); @@ -481,8 +473,7 @@ public class Loan extends AbstractAuditableCustom { disburse(disbursedOn, loanLifecycleStateMachine); } - public void disburse(final LocalDate disbursedOn, - LoanLifecycleStateMachine loanLifecycleStateMachine) { + public void disburse(final LocalDate disbursedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus)); this.loanStatus = statusEnum.getValue(); @@ -492,10 +483,23 @@ public class Loan extends AbstractAuditableCustom { .get(this.repaymentScheduleInstallments.size() - 1) .getDueDate().toDateMidnight().toDate(); - LoanTransaction loanTransaction = LoanTransaction.disbursement( - this.loanRepaymentScheduleDetail.getPrincipal(), disbursedOn); + // add disbursement transaction to track outgoing money from mfi to client + LoanTransaction loanTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), disbursedOn); loanTransaction.updateLoan(this); this.loanTransactions.add(loanTransaction); + + // add repayment transaction to track incoming money from client to mfi for (charges due at time of disbursement) + if (getTotalChargesDueAtDisbursement().isGreaterThanZero()) { + + // FIXME - add charges component to 'transactions' + LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getTotalChargesDueAtDisbursement(), disbursedOn); + Money zero = Money.zero(getCurrency()); + chargesPayment.updateComponents(zero, zero, zero, getTotalChargesDueAtDisbursement()); + chargesPayment.updateLoan(this); + this.loanTransactions.add(chargesPayment); + + // should also pay-off the time-of-disbursement charges + } if (disbursedOn.isBefore(getApprovedOnDate())) { final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: " @@ -619,15 +623,7 @@ public class Loan extends AbstractAuditableCustom { "cannot.be.a.future.date", errorMessage, loanTransactionDate); } - List repaymentsOrWaivers = new ArrayList(); - for (LoanTransaction transaction : this.loanTransactions) { - if (!transaction.isDisbursement() && transaction.isNotContra()) { - repaymentsOrWaivers.add(transaction); - } - } - LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); - Collections.sort(repaymentsOrWaivers, transactionComparator); - + List repaymentsOrWaivers = retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement(); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); if (isTransactionChronologicallyLatest && !adjusted) { @@ -639,6 +635,18 @@ public class Loan extends AbstractAuditableCustom { doPostLoanTransactionChecks(loanTransaction, loanLifecycleStateMachine); } + private List retreiveListOfRepaymentOrWaiverTransactionsPostDisbursement() { + List repaymentsOrWaivers = new ArrayList(); + for (LoanTransaction transaction : this.loanTransactions) { + if (!transaction.isDisbursement() && transaction.isNotContra()) { + repaymentsOrWaivers.add(transaction); + } + } + LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); + Collections.sort(repaymentsOrWaivers, transactionComparator); + return repaymentsOrWaivers; + } + private void doPostLoanTransactionChecks(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { if (this.isOverPaid()) { @@ -1260,4 +1268,8 @@ public class Loan extends AbstractAuditableCustom { public Money getPrincpal() { return this.loanRepaymentScheduleDetail.getPrincipal(); } + + public Money getTotalChargesDueAtDisbursement() { + return Money.of(getCurrency(), this.totalChargesDueAtDisbursement); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransaction.java index 2d6768d43..923ad0eb9 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransaction.java @@ -46,6 +46,9 @@ public class LoanTransaction extends AbstractAuditableCustom { @Column(name = "interest_waived_derived", scale = 6, precision = 19) private BigDecimal interestWaivedPortion = BigDecimal.ZERO; + @Column(name = "charges_portion_derived", scale = 6, precision = 19, nullable = false) + private BigDecimal chargesPortion = BigDecimal.ZERO; + @Temporal(TemporalType.DATE) @Column(name = "transaction_date", nullable=false) private final Date dateOf; @@ -73,6 +76,10 @@ public class LoanTransaction extends AbstractAuditableCustom { return new LoanTransaction(LoanTransactionType.REPAYMENT, amount.getAmount(), paymentDate); } + public static LoanTransaction repaymentAtDisbursement(final Money amount, final LocalDate paymentDate) { + return new LoanTransaction(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, amount.getAmount(), paymentDate); + } + public static LoanTransaction waiver(final Money waived, final LocalDate waiveDate) { return new LoanTransaction(LoanTransactionType.WAIVED, waived.getAmount(), waiveDate); } @@ -130,6 +137,10 @@ public class LoanTransaction extends AbstractAuditableCustom { return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()); } + public boolean isRepaymentAtDisbursement() { + return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()); + } + public boolean isWaiver() { return LoanTransactionType.WAIVED.equals(getTypeOf()) && isNotContra(); } @@ -168,30 +179,40 @@ public class LoanTransaction extends AbstractAuditableCustom { * * This accumulates the values passed to the already existent values for each of the portions. */ - public void updateComponents(final Money principal, final Money interest, final Money interestWaivedPortion) { + public void updateComponents(final Money principal, final Money interest, final Money interestWaivedPortion, final Money charges) { MonetaryCurrency currency = principal.getCurrency(); this.principalPortion = getPrincipalPortion(currency).plus(principal).getAmount(); this.interestPortion = getInterestPortion(currency).plus(interest).getAmount(); this.interestWaivedPortion = getInterestWaivedPortion(currency).plus(interestWaivedPortion).getAmount(); + this.chargesPortion = getChargesPortion(currency).plus(charges).getAmount(); } - public Money getPrincipalPortion(MonetaryCurrency currency) { + public Money getPrincipalPortion(final MonetaryCurrency currency) { return Money.of(currency, principalPortion); } - public Money getInterestPortion(MonetaryCurrency currency) { + public Money getInterestPortion(final MonetaryCurrency currency) { return Money.of(currency, interestPortion); } - public Money getInterestWaivedPortion(MonetaryCurrency currency) { + public Money getInterestWaivedPortion(final MonetaryCurrency currency) { if (this.interestWaivedPortion == null) { this.interestWaivedPortion = BigDecimal.ZERO; } return Money.of(currency, interestWaivedPortion); } + + public Money getChargesPortion(final MonetaryCurrency currency) { + if (this.chargesPortion == null) { + this.chargesPortion = BigDecimal.ZERO; + } + return Money.of(currency, chargesPortion); + } public void resetDerivedComponents() { - this.principalPortion = BigDecimal.ZERO; - this.interestPortion = BigDecimal.ZERO; + this.principalPortion = null; + this.interestPortion = null; + this.interestWaivedPortion = null; + this.chargesPortion = null; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionType.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionType.java index 301564858..a63137fa1 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionType.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionType.java @@ -6,7 +6,8 @@ public enum LoanTransactionType { DISBURSEMENT(1, "loanTransactionType.disbursement"), // REPAYMENT(2, "loanTransactionType.repayment"), // REVERSAL(3, "loanTransactionType.reversal"), // - WAIVED(4, "loanTransactionType.waiver"); + WAIVED(4, "loanTransactionType.waiver"), // + REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement"); private final Integer value; private final String code; @@ -44,6 +45,9 @@ public enum LoanTransactionType { case 4: loanTransactionType = LoanTransactionType.WAIVED; break; + case 5: + loanTransactionType = LoanTransactionType.REPAYMENT_AT_DISBURSEMENT; + break; default: loanTransactionType = LoanTransactionType.INVALID; break; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/MifosStyleLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/MifosStyleLoanRepaymentScheduleTransactionProcessor.java index b4e9fcda5..a9581b285 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/MifosStyleLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/MifosStyleLoanRepaymentScheduleTransactionProcessor.java @@ -81,10 +81,8 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends transactionAmountRemaining = transactionAmountRemaining .minus(principalPortion); - Money interestWaivedPortion = Money.zero(transactionAmountRemaining - .getCurrency()); - loanTransaction.updateComponents(principalPortion, interestPortion, - interestWaivedPortion); + Money interestWaivedPortion = Money.zero(transactionAmountRemaining.getCurrency()); + loanTransaction.updateComponents(principalPortion, interestPortion,interestWaivedPortion, Money.zero(transactionAmountRemaining.getCurrency())); return transactionAmountRemaining; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java index eec141397..66d47c830 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java @@ -103,7 +103,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement); final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment"; - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursement.disbursementDate(), disbursement.amount(), totalChargesAtDisbursement); + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursement.disbursementDate(), disbursement.amount(), totalChargesAtDisbursement, disbursement.isDisbursed()); final Collection repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); @@ -162,9 +162,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { // retrieve all loan transactions that are not invalid (0) and not // disbursements (1) and have not been 'contra'ed by another transaction + // repayments at time of disbursement (e.g. charges) String sql = "select " + rm.LoanPaymentsSchema() - + " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 1) and tr.contra_id is null order by tr.transaction_date ASC"; + + " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 1, 5) and tr.contra_id is null order by tr.transaction_date ASC"; return this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); } catch (EmptyResultDataAccessException e) { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualInstallmentsAmortizationLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualInstallmentsAmortizationLoanScheduleGenerator.java index 001daf76b..08a407a9e 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualInstallmentsAmortizationLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualInstallmentsAmortizationLoanScheduleGenerator.java @@ -69,7 +69,7 @@ public class EqualInstallmentsAmortizationLoanScheduleGenerator implements Amort BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement; // create entries of disbursement period on loan schedule - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement); + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false); periods.add(disbursementPeriod); int loanTermInDays = Integer.valueOf(0); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualPrincipalAmortizationLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualPrincipalAmortizationLoanScheduleGenerator.java index 0b3760898..7309fd264 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualPrincipalAmortizationLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/EqualPrincipalAmortizationLoanScheduleGenerator.java @@ -59,7 +59,7 @@ public class EqualPrincipalAmortizationLoanScheduleGenerator implements Amortiza BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement; // create entries of disbursement period on loan schedule - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement); + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false); periods.add(disbursementPeriod); int loanTermInDays = Integer.valueOf(0); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/FlatMethodLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/FlatMethodLoanScheduleGenerator.java index 401c4541d..b4d024762 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/FlatMethodLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/FlatMethodLoanScheduleGenerator.java @@ -74,7 +74,7 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator { BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement; // create entries of disbursement period on loan schedule - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement); + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false); periods.add(disbursementPeriod); int loanTermInDays = Integer.valueOf(0);