diff --git a/mifosng-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql b/mifosng-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql index de1a33e6e..57a96b78e 100644 --- a/mifosng-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql +++ b/mifosng-db/multi-tenant-demo-backups/ceda/bk_ceda_trial.sql @@ -1085,7 +1085,6 @@ CREATE TABLE `m_loan_transaction` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `loan_id` bigint(20) NOT NULL, `transaction_type_enum` smallint(5) NOT NULL, - `contra_id` bigint(20) DEFAULT NULL, `transaction_date` date NOT NULL, `amount` decimal(19,6) NOT NULL, `createdby_id` bigint(20) DEFAULT NULL, @@ -1096,11 +1095,10 @@ CREATE TABLE `m_loan_transaction` ( `interest_portion_derived` decimal(19,6) DEFAULT NULL, `fee_charges_portion_derived` decimal(19,6) DEFAULT NULL, `penalty_charges_portion_derived` decimal(19,6) DEFAULT NULL, + `is_reversed` tinyint(1) NOT NULL, PRIMARY KEY (`id`), KEY `FKCFCEA42640BE0710` (`loan_id`), - KEY `FKCFCEA426FC69F3F1` (`contra_id`), - CONSTRAINT `FKCFCEA42640BE0710` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`), - CONSTRAINT `FKCFCEA426FC69F3F1` FOREIGN KEY (`contra_id`) REFERENCES `m_loan_transaction` (`id`) + CONSTRAINT `FKCFCEA42640BE0710` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1939,4 +1937,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2013-02-14 23:47:02 +-- Dump completed on 2013-02-18 13:20:24 diff --git a/mifosng-db/patches/10-refactor-contra-reversal-transactions-for-loan-portfolio.sql b/mifosng-db/patches/10-refactor-contra-reversal-transactions-for-loan-portfolio.sql new file mode 100644 index 000000000..1a5b66983 --- /dev/null +++ b/mifosng-db/patches/10-refactor-contra-reversal-transactions-for-loan-portfolio.sql @@ -0,0 +1,11 @@ +ALTER TABLE `m_loan_transaction` +ADD COLUMN `is_reversed` TINYINT(1) NOT NULL AFTER `penalty_charges_portion_derived`; + +-- === update is_reversed column to true for all fields where contra_id is not null + +UPDATE `m_loan_transaction` SET `is_reversed` = 1 WHERE contra_id is not null; + +ALTER TABLE `m_loan_transaction` DROP FOREIGN KEY `FKCFCEA426FC69F3F1`; +ALTER TABLE `m_loan_transaction` +DROP COLUMN `contra_id` , +DROP INDEX `FKCFCEA426FC69F3F1`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java index d7f427a5d..209892770 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java @@ -221,7 +221,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa } /*** Debit loan Portfolio and credit Fund source for Disbursal **/ - if (loanTransactionDTO.isDisbursement()) { + if (loanTransactionDTO.isDisbursement() && !loanTransactionDTO.isContra()) { final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index f50e84f00..5620abb8f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -1106,40 +1106,6 @@ public class Loan extends AbstractAuditableCustom { handleDisbursementTransaction(expectedDisbursedOnLocalDate); } - public Map deriveDisbursementData(final CurrencyData currencyData, final List existingTransactionIds) { - - final Map accountingBridgeData = new LinkedHashMap(20); - - accountingBridgeData.put("loanId", this.getId()); - accountingBridgeData.put("loanProductId", this.productId()); - accountingBridgeData.put("officeId", this.getOfficeId()); - accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnLoanProduct()); - accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnLoanProduct()); - - final List> newLoanTransactions = new ArrayList>(); - final List disbursementTransactions = findDisbursementTransactions(); - for (LoanTransaction loanTransaction : disbursementTransactions) { - if (!existingTransactionIds.contains(loanTransaction.getId())) { - newLoanTransactions.add(loanTransaction.toMapData(currencyData)); - } - } - - accountingBridgeData.put("newLoanTransactions", newLoanTransactions); - - return accountingBridgeData; - } - - private List findDisbursementTransactions() { - List found = new ArrayList(); - for (LoanTransaction transaction : this.loanTransactions) { - if (transaction.isDisbursement() || transaction.isRepaymentAtDisbursement()) { - found.add(transaction); - } - } - - return found; - } - private Collection findExistingTransactionIds() { Collection ids = new ArrayList(); @@ -1151,9 +1117,22 @@ public class Loan extends AbstractAuditableCustom { return ids; } + private Collection findExistingReversedTransactionIds() { + + final Collection ids = new ArrayList(); + + for (LoanTransaction transaction : this.loanTransactions) { + if (transaction.isReversed()) { + ids.add(transaction.getId()); + } + } + + return ids; + } + public Map disburse(final AppUser currentUser, final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency, - final List existingTransactionIds) { + final List existingTransactionIds, final List existingReversedTransactionIds) { final Map actualChanges = new LinkedHashMap(); @@ -1161,6 +1140,10 @@ public class Loan extends AbstractAuditableCustom { final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus)); if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) { + + existingTransactionIds.addAll(findExistingTransactionIds()); + existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); + this.loanStatus = statusEnum.getValue(); actualChanges.put("status", LoanEnumerations.status(this.loanStatus)); @@ -1186,8 +1169,6 @@ public class Loan extends AbstractAuditableCustom { if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) { regenerateRepaymentSchedule(currency); } - - existingTransactionIds.addAll(findExistingTransactionIds()); } return actualChanges; @@ -1276,7 +1257,7 @@ public class Loan extends AbstractAuditableCustom { } public Map undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine, - final List existingTransactionIds) { + final List existingTransactionIds, final List existingReversedTransactionIds) { final Map actualChanges = new LinkedHashMap(); @@ -1291,8 +1272,9 @@ public class Loan extends AbstractAuditableCustom { actualChanges.put("disbursedOnDate", ""); existingTransactionIds.addAll(findExistingTransactionIds()); + existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); - contraExistingTransactions(); + reverseExistingTransactions(); updateLoanToPreDisbursalState(); } @@ -1300,18 +1282,11 @@ public class Loan extends AbstractAuditableCustom { return actualChanges; } - private final void contraExistingTransactions() { + private final void reverseExistingTransactions() { - // final List contras = new - // ArrayList(); for (LoanTransaction transaction : this.loanTransactions) { - if (transaction.isNotContra()) { - LoanTransaction contra = transaction.contra(); - // contras.add(contra); - } + transaction.reverse(); } - - // this.loanTransactions.addAll(contras); } private void updateLoanToPreDisbursalState() { @@ -1415,7 +1390,7 @@ public class Loan extends AbstractAuditableCustom { private List retreiveListOfTransactionsPostDisbursement() { List repaymentsOrWaivers = new ArrayList(); for (LoanTransaction transaction : this.loanTransactions) { - if (!transaction.isDisbursement() && transaction.isNotContra()) { + if (!transaction.isDisbursement() && transaction.isNotReversed()) { repaymentsOrWaivers.add(transaction); } } @@ -1462,7 +1437,7 @@ public class Loan extends AbstractAuditableCustom { LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); for (LoanTransaction previousTransaction : loanTransactions) { - if (!previousTransaction.isDisbursement() && previousTransaction.isNotContra()) { + if (!previousTransaction.isDisbursement() && previousTransaction.isNotReversed()) { if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) || currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { isChronologicallyLatestRepaymentOrWaiver = false; @@ -1480,7 +1455,7 @@ public class Loan extends AbstractAuditableCustom { LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); for (LoanTransaction previousTransaction : loanTransactions) { - if (previousTransaction.isNotContra()) { + if (previousTransaction.isNotReversed()) { if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) || currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { isChronologicallyLatestRepaymentOrWaiver = false; @@ -1574,7 +1549,7 @@ public class Loan extends AbstractAuditableCustom { throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.not.allowed.on.closed.loan", errorMessage); } - transactionForAdjustment.contra(); + transactionForAdjustment.reverse(); if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) { handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment); } @@ -2137,7 +2112,7 @@ public class Loan extends AbstractAuditableCustom { return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode); } - private String getCurrencyCode() { + public String getCurrencyCode() { return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode(); } @@ -2256,7 +2231,8 @@ public class Loan extends AbstractAuditableCustom { return this.loanOfficer; } - public Map deriveAccountingBridgeData(final CurrencyData currencyData, final List existingTransactionIds) { + public Map deriveAccountingBridgeData(final CurrencyData currencyData, final List existingTransactionIds, + final List existingReversedTransactionIds) { final Map accountingBridgeData = new LinkedHashMap(); accountingBridgeData.put("loanId", this.getId()); @@ -2267,7 +2243,9 @@ public class Loan extends AbstractAuditableCustom { final List> newLoanTransactions = new ArrayList>(); for (LoanTransaction transaction : this.loanTransactions) { - if (!existingTransactionIds.contains(transaction.getId())) { + if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) { + newLoanTransactions.add(transaction.toMapData(currencyData)); + } else if (!existingTransactionIds.contains(transaction.getId())) { newLoanTransactions.add(transaction.toMapData(currencyData)); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java index db1335489..c0c2de6ee 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java @@ -28,82 +28,76 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus @ManyToOne(optional = false) @JoinColumn(name = "loan_id") - private Loan loan; + private Loan loan; - @Column(name = "installment", nullable=false) + @Column(name = "installment", nullable = false) private final Integer installmentNumber; - + @Temporal(TemporalType.DATE) - @Column(name = "fromdate", nullable=true) - private final Date fromDate; - + @Column(name = "fromdate", nullable = true) + private final Date fromDate; + @Temporal(TemporalType.DATE) - @Column(name = "duedate", nullable=false) - private final Date dueDate; - - @Column(name = "principal_amount", scale=6, precision=19, nullable=true) - private BigDecimal principal; - - @Column(name = "principal_completed_derived", scale=6, precision=19, nullable=true) - private BigDecimal principalCompleted; - - @Column(name = "principal_writtenoff_derived", scale=6, precision=19, nullable=true) - private BigDecimal principalWrittenOff; - - @Column(name = "interest_amount", scale=6, precision=19, nullable=true) - private BigDecimal interest; - - @Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable=true) - private BigDecimal interestCompleted; - - @Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable=true) - private BigDecimal interestWaived; - - @Column(name = "interest_writtenoff_derived", scale=6, precision=19, nullable=true) - private BigDecimal interestWrittenOff; - - @Column(name = "fee_charges_amount", scale=6, precision=19, nullable=true) - private BigDecimal feeCharges; - - @Column(name = "fee_charges_completed_derived", scale=6, precision=19, nullable=true) - private BigDecimal feeChargesCompleted; - - @Column(name = "fee_charges_writtenoff_derived", scale=6, precision=19, nullable=true) - private BigDecimal feeChargesWrittenOff; - - @Column(name = "fee_charges_waived_derived", scale=6, precision=19, nullable=true) - private BigDecimal feeChargesWaived; - - @Column(name = "penalty_charges_amount", scale=6, precision=19, nullable=true) - private BigDecimal penaltyCharges; - - @Column(name = "penalty_charges_completed_derived", scale=6, precision=19, nullable=true) - private BigDecimal penaltyChargesCompleted; - - @Column(name = "penalty_charges_writtenoff_derived", scale=6, precision=19, nullable=true) - private BigDecimal penaltyChargesWrittenOff; - - @Column(name = "penalty_charges_waived_derived", scale=6, precision=19, nullable=true) - private BigDecimal penaltyChargesWaived; - - @Column(name="completed_derived", nullable=false) + @Column(name = "duedate", nullable = false) + private final Date dueDate; + + @Column(name = "principal_amount", scale = 6, precision = 19, nullable = true) + private BigDecimal principal; + + @Column(name = "principal_completed_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal principalCompleted; + + @Column(name = "principal_writtenoff_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal principalWrittenOff; + + @Column(name = "interest_amount", scale = 6, precision = 19, nullable = true) + private BigDecimal interest; + + @Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal interestCompleted; + + @Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal interestWaived; + + @Column(name = "interest_writtenoff_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal interestWrittenOff; + + @Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true) + private BigDecimal feeCharges; + + @Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal feeChargesCompleted; + + @Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal feeChargesWrittenOff; + + @Column(name = "fee_charges_waived_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal feeChargesWaived; + + @Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true) + private BigDecimal penaltyCharges; + + @Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal penaltyChargesCompleted; + + @Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal penaltyChargesWrittenOff; + + @Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal penaltyChargesWaived; + + @Column(name = "completed_derived", nullable = false) private boolean completed; protected LoanRepaymentScheduleInstallment() { - this.installmentNumber = null; - this.fromDate = null; - this.dueDate = null; + this.installmentNumber = null; + this.fromDate = null; + this.dueDate = null; this.completed = false; } - public LoanRepaymentScheduleInstallment( - final Loan loan, - final Integer installmentNumber, - final LocalDate fromDate, - final LocalDate dueDate, - final BigDecimal principal, - final BigDecimal interest, - final BigDecimal feeCharges, + public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate, + final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, final BigDecimal penaltyCharges) { this.loan = loan; this.installmentNumber = installmentNumber; @@ -116,15 +110,15 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus this.completed = false; } - private BigDecimal defaultToNullIfZero(final BigDecimal value) { - BigDecimal result = value; - if (BigDecimal.ZERO.compareTo(value) == 0) { - result = null; - } - return result; - } + private BigDecimal defaultToNullIfZero(final BigDecimal value) { + BigDecimal result = value; + if (BigDecimal.ZERO.compareTo(value) == 0) { + result = null; + } + return result; + } - public Loan getLoan() { + public Loan getLoan() { return this.loan; } @@ -133,324 +127,323 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus } public LocalDate getFromDate() { - LocalDate fromLocalDate = null; - if (this.fromDate != null) { - fromLocalDate = new LocalDate(this.fromDate); - } - - return fromLocalDate; + LocalDate fromLocalDate = null; + if (this.fromDate != null) { + fromLocalDate = new LocalDate(this.fromDate); + } + + return fromLocalDate; } - + public LocalDate getDueDate() { return new LocalDate(this.dueDate); } - public Money getPrincipal(final MonetaryCurrency currency) { - return Money.of(currency, this.principal); - } - - public Money getPrincipalCompleted(final MonetaryCurrency currency) { - return Money.of(currency, this.principalCompleted); - } - - public Money getPrincipalWrittenOff(final MonetaryCurrency currency) { - return Money.of(currency, this.principalWrittenOff); - } - - public Money getPrincipalOutstanding(final MonetaryCurrency currency) { - final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency)); - return getPrincipal(currency).minus(principalAccountedFor); - } - - public Money getInterest(final MonetaryCurrency currency) { - return Money.of(currency, this.interest); - } - - public Money getInterestCompleted(final MonetaryCurrency currency) { - return Money.of(currency, this.interestCompleted); - } - - public Money getInterestWaived(final MonetaryCurrency currency) { - return Money.of(currency, this.interestWaived); - } - - public Money getInterestWrittenOff(final MonetaryCurrency currency) { - return Money.of(currency, this.interestWrittenOff); - } - - public Money getInterestOutstanding(final MonetaryCurrency currency) { - final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus(getInterestWrittenOff(currency)); - return getInterest(currency).minus(interestAccountedFor); - } - - public Money getFeeCharges(final MonetaryCurrency currency) { - return Money.of(currency, this.feeCharges); - } - - public Money getFeeChargesCompleted(final MonetaryCurrency currency) { - return Money.of(currency, this.feeChargesCompleted); - } - - public Money getFeeChargesWaived(final MonetaryCurrency currency) { - return Money.of(currency, this.feeChargesWaived); - } - - public Money getFeeChargesWrittenOff(final MonetaryCurrency currency) { - return Money.of(currency, this.feeChargesWrittenOff); - } - - public Money getFeeChargesOutstanding(final MonetaryCurrency currency) { - final Money feeChargesAccountedFor = getFeeChargesCompleted(currency).plus(getFeeChargesWaived(currency)).plus(getFeeChargesWrittenOff(currency)); - return getFeeCharges(currency).minus(feeChargesAccountedFor); - } - - public Money getPenaltyCharges(final MonetaryCurrency currency) { - return Money.of(currency, this.penaltyCharges); - } - - public Money getPenaltyChargesCompleted(final MonetaryCurrency currency) { - return Money.of(currency, this.penaltyChargesCompleted); - } - - public Money getPenaltyChargesWaived(final MonetaryCurrency currency) { - return Money.of(currency, this.penaltyChargesWaived); - } - - public Money getPenaltyChargesWrittenOff(final MonetaryCurrency currency) { - return Money.of(currency, this.penaltyChargesWrittenOff); - } - - public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) { - final Money feeChargesAccountedFor = getPenaltyChargesCompleted(currency).plus(getPenaltyChargesWaived(currency)).plus(getPenaltyChargesWrittenOff(currency)); - return getPenaltyCharges(currency).minus(feeChargesAccountedFor); - } + public Money getPrincipal(final MonetaryCurrency currency) { + return Money.of(currency, this.principal); + } - public boolean isInterestDue(final MonetaryCurrency currency) { - return getInterestOutstanding(currency).isGreaterThanZero(); - } - - public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) { - return getPrincipal(currency).plus(getInterest(currency)); - } - - public Money getTotalOutstanding(final MonetaryCurrency currency) { - return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency)).plus(getPenaltyChargesOutstanding(currency)); - } - - public void updateLoan(final Loan loan) { - this.loan = loan; - } - - public boolean isFullyCompleted() { - return this.completed; - } + public Money getPrincipalCompleted(final MonetaryCurrency currency) { + return Money.of(currency, this.principalCompleted); + } - public boolean isNotFullyCompleted() { - return !this.completed; - } - - public boolean isPrincipalNotCompleted(final MonetaryCurrency currency) { - return !isPrincipalCompleted(currency); - } - - public boolean isPrincipalCompleted(final MonetaryCurrency currency) { - return getPrincipalOutstanding(currency).isZero(); - } + public Money getPrincipalWrittenOff(final MonetaryCurrency currency) { + return Money.of(currency, this.principalWrittenOff); + } - public void resetDerivedComponents() { - this.principalCompleted = null; - this.principalWrittenOff = null; - this.interestCompleted = null; - this.interestWaived = null; - this.interestWrittenOff = null; - this.feeChargesCompleted = null; - this.feeChargesWaived = null; - this.feeChargesWrittenOff = null; - this.penaltyChargesCompleted = null; - this.penaltyChargesWaived = null; - this.penaltyChargesWrittenOff = null; - - this.completed = false; - } + public Money getPrincipalOutstanding(final MonetaryCurrency currency) { + final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency)); + return getPrincipal(currency).minus(principalAccountedFor); + } - public Money payPenaltyChargesComponent(final Money transactionAmountRemaining) { - - final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money penaltyPortionOfTransaction = Money.zero(currency); - - final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) { - this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(penaltyChargesDue).getAmount(); - penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue); - } else { - this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(transactionAmountRemaining).getAmount(); - penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.penaltyChargesCompleted = defaultToNullIfZero(this.penaltyChargesCompleted); - - this.completed = getTotalOutstanding(currency).isZero(); - - return penaltyPortionOfTransaction; - } - - public Money payFeeChargesComponent(final Money transactionAmountRemaining) { - - final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money feePortionOfTransaction = Money.zero(currency); - - final Money feeChargesDue = getFeeChargesOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) { - this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(feeChargesDue).getAmount(); - feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue); - } else { - this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(transactionAmountRemaining).getAmount(); - feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining); - } - - this.feeChargesCompleted = defaultToNullIfZero(this.feeChargesCompleted); - - this.completed = getTotalOutstanding(currency).isZero(); - - return feePortionOfTransaction; - } - - public Money payInterestComponent(final Money transactionAmountRemaining) { - - final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money interestPortionOfTransaction = Money.zero(currency); - - final Money interestDue = getInterestOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) { - this.interestCompleted = getInterestCompleted(currency).plus(interestDue).getAmount(); - interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue); - } else { - this.interestCompleted = getInterestCompleted(currency).plus(transactionAmountRemaining).getAmount(); - interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.interestCompleted = defaultToNullIfZero(this.interestCompleted); - - this.completed = getTotalOutstanding(currency).isZero(); - - return interestPortionOfTransaction; - } + public Money getInterest(final MonetaryCurrency currency) { + return Money.of(currency, this.interest); + } - public Money payPrincipalComponent(final Money transactionAmountRemaining) { - - final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money principalPortionOfTransaction = Money.zero(currency); - - final Money principalDue = getPrincipalOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) { - this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount(); - principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue); - } else { - this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount(); - principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.principalCompleted = defaultToNullIfZero(this.principalCompleted); - - this.completed = getTotalOutstanding(currency).isZero(); - - return principalPortionOfTransaction; - } + public Money getInterestCompleted(final MonetaryCurrency currency) { + return Money.of(currency, this.interestCompleted); + } - public Money waiveInterestComponent(final Money transactionAmountRemaining) { - MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money waivedInterestPortionOfTransaction = Money.zero(currency); - - Money interestDue = getInterestOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) { - this.interestWaived = getInterestWaived(currency).plus(interestDue).getAmount(); - waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(interestDue); - } else { - this.interestWaived = getInterestWaived(currency).plus(transactionAmountRemaining).getAmount(); - waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.interestWaived = defaultToNullIfZero(this.interestWaived); - - this.completed = getTotalOutstanding(currency).isZero(); - - return waivedInterestPortionOfTransaction; - } - - public Money waivePenaltyChargesComponent(final Money transactionAmountRemaining) { - MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money waivedPenaltyChargesPortionOfTransaction = Money.zero(currency); - - Money penanltiesDue = getPenaltyChargesOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) { - this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount(); - waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue); - } else { - this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount(); - waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.penaltyChargesWaived = defaultToNullIfZero(this.penaltyChargesWaived); - - this.completed = getTotalOutstanding(currency).isZero(); - - return waivedPenaltyChargesPortionOfTransaction; - } - - public Money waiveFeeChargesComponent(final Money transactionAmountRemaining) { - MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); - Money waivedFeeChargesPortionOfTransaction = Money.zero(currency); - - Money feesDue = getPenaltyChargesOutstanding(currency); - if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) { - this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount(); - waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue); - } else { - this.feeChargesWaived = getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount(); - waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining); - } - - this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived); - - this.completed = getTotalOutstanding(currency).isZero(); - - return waivedFeeChargesPortionOfTransaction; - } - - public Money writeOffOutstandingPrincipal(final MonetaryCurrency currency) { - - final Money principalDue = getPrincipalOutstanding(currency); - this.principalWrittenOff = defaultToNullIfZero(principalDue.getAmount()); - this.completed = getTotalOutstanding(currency).isZero(); - - return principalDue; - } - - public Money writeOffOutstandingInterest(final MonetaryCurrency currency) { - - final Money interestDue = getInterestOutstanding(currency); - this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount()); - this.completed = getTotalOutstanding(currency).isZero(); - - return interestDue; - } + public Money getInterestWaived(final MonetaryCurrency currency) { + return Money.of(currency, this.interestWaived); + } - public boolean isOverdueOn(final LocalDate transactionDate) { - return this.getDueDate().isBefore(transactionDate); - } + public Money getInterestWrittenOff(final MonetaryCurrency currency) { + return Money.of(currency, this.interestWrittenOff); + } - public void updateChargePortion( - final Money feeChargesDue, - final Money feeChargesWaived, - final Money feeChargesWrittenOff, - final Money penaltyChargesDue, - final Money penaltyChargesWaived, - final Money penaltyChargesWrittenOff) { - this.feeCharges = defaultToNullIfZero(feeChargesDue.getAmount()); - this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount()); - this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount()); - this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount()); - this.penaltyChargesWaived = defaultToNullIfZero(penaltyChargesWaived.getAmount()); - this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesWrittenOff.getAmount()); - } + public Money getInterestOutstanding(final MonetaryCurrency currency) { + final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus( + getInterestWrittenOff(currency)); + return getInterest(currency).minus(interestAccountedFor); + } + + public Money getFeeCharges(final MonetaryCurrency currency) { + return Money.of(currency, this.feeCharges); + } + + public Money getFeeChargesCompleted(final MonetaryCurrency currency) { + return Money.of(currency, this.feeChargesCompleted); + } + + public Money getFeeChargesWaived(final MonetaryCurrency currency) { + return Money.of(currency, this.feeChargesWaived); + } + + public Money getFeeChargesWrittenOff(final MonetaryCurrency currency) { + return Money.of(currency, this.feeChargesWrittenOff); + } + + public Money getFeeChargesOutstanding(final MonetaryCurrency currency) { + final Money feeChargesAccountedFor = getFeeChargesCompleted(currency).plus(getFeeChargesWaived(currency)).plus( + getFeeChargesWrittenOff(currency)); + return getFeeCharges(currency).minus(feeChargesAccountedFor); + } + + public Money getPenaltyCharges(final MonetaryCurrency currency) { + return Money.of(currency, this.penaltyCharges); + } + + public Money getPenaltyChargesCompleted(final MonetaryCurrency currency) { + return Money.of(currency, this.penaltyChargesCompleted); + } + + public Money getPenaltyChargesWaived(final MonetaryCurrency currency) { + return Money.of(currency, this.penaltyChargesWaived); + } + + public Money getPenaltyChargesWrittenOff(final MonetaryCurrency currency) { + return Money.of(currency, this.penaltyChargesWrittenOff); + } + + public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) { + final Money feeChargesAccountedFor = getPenaltyChargesCompleted(currency).plus(getPenaltyChargesWaived(currency)).plus( + getPenaltyChargesWrittenOff(currency)); + return getPenaltyCharges(currency).minus(feeChargesAccountedFor); + } + + public boolean isInterestDue(final MonetaryCurrency currency) { + return getInterestOutstanding(currency).isGreaterThanZero(); + } + + public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) { + return getPrincipal(currency).plus(getInterest(currency)); + } + + public Money getTotalOutstanding(final MonetaryCurrency currency) { + return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency)) + .plus(getPenaltyChargesOutstanding(currency)); + } + + public void updateLoan(final Loan loan) { + this.loan = loan; + } + + public boolean isFullyCompleted() { + return this.completed; + } + + public boolean isNotFullyCompleted() { + return !this.completed; + } + + public boolean isPrincipalNotCompleted(final MonetaryCurrency currency) { + return !isPrincipalCompleted(currency); + } + + public boolean isPrincipalCompleted(final MonetaryCurrency currency) { + return getPrincipalOutstanding(currency).isZero(); + } + + public void resetDerivedComponents() { + this.principalCompleted = null; + this.principalWrittenOff = null; + this.interestCompleted = null; + this.interestWaived = null; + this.interestWrittenOff = null; + this.feeChargesCompleted = null; + this.feeChargesWaived = null; + this.feeChargesWrittenOff = null; + this.penaltyChargesCompleted = null; + this.penaltyChargesWaived = null; + this.penaltyChargesWrittenOff = null; + + this.completed = false; + } + + public Money payPenaltyChargesComponent(final Money transactionAmountRemaining) { + + final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money penaltyPortionOfTransaction = Money.zero(currency); + + final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) { + this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(penaltyChargesDue).getAmount(); + penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue); + } else { + this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(transactionAmountRemaining).getAmount(); + penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.penaltyChargesCompleted = defaultToNullIfZero(this.penaltyChargesCompleted); + + this.completed = getTotalOutstanding(currency).isZero(); + + return penaltyPortionOfTransaction; + } + + public Money payFeeChargesComponent(final Money transactionAmountRemaining) { + + final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money feePortionOfTransaction = Money.zero(currency); + + final Money feeChargesDue = getFeeChargesOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) { + this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(feeChargesDue).getAmount(); + feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue); + } else { + this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(transactionAmountRemaining).getAmount(); + feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining); + } + + this.feeChargesCompleted = defaultToNullIfZero(this.feeChargesCompleted); + + this.completed = getTotalOutstanding(currency).isZero(); + + return feePortionOfTransaction; + } + + public Money payInterestComponent(final Money transactionAmountRemaining) { + + final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money interestPortionOfTransaction = Money.zero(currency); + + final Money interestDue = getInterestOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) { + this.interestCompleted = getInterestCompleted(currency).plus(interestDue).getAmount(); + interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue); + } else { + this.interestCompleted = getInterestCompleted(currency).plus(transactionAmountRemaining).getAmount(); + interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.interestCompleted = defaultToNullIfZero(this.interestCompleted); + + this.completed = getTotalOutstanding(currency).isZero(); + + return interestPortionOfTransaction; + } + + public Money payPrincipalComponent(final Money transactionAmountRemaining) { + + final MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money principalPortionOfTransaction = Money.zero(currency); + + final Money principalDue = getPrincipalOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) { + this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount(); + principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue); + } else { + this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount(); + principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.principalCompleted = defaultToNullIfZero(this.principalCompleted); + + this.completed = getTotalOutstanding(currency).isZero(); + + return principalPortionOfTransaction; + } + + public Money waiveInterestComponent(final Money transactionAmountRemaining) { + MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money waivedInterestPortionOfTransaction = Money.zero(currency); + + Money interestDue = getInterestOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) { + this.interestWaived = getInterestWaived(currency).plus(interestDue).getAmount(); + waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(interestDue); + } else { + this.interestWaived = getInterestWaived(currency).plus(transactionAmountRemaining).getAmount(); + waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.interestWaived = defaultToNullIfZero(this.interestWaived); + + this.completed = getTotalOutstanding(currency).isZero(); + + return waivedInterestPortionOfTransaction; + } + + public Money waivePenaltyChargesComponent(final Money transactionAmountRemaining) { + MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money waivedPenaltyChargesPortionOfTransaction = Money.zero(currency); + + Money penanltiesDue = getPenaltyChargesOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) { + this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount(); + waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue); + } else { + this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount(); + waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.penaltyChargesWaived = defaultToNullIfZero(this.penaltyChargesWaived); + + this.completed = getTotalOutstanding(currency).isZero(); + + return waivedPenaltyChargesPortionOfTransaction; + } + + public Money waiveFeeChargesComponent(final Money transactionAmountRemaining) { + MonetaryCurrency currency = transactionAmountRemaining.getCurrency(); + Money waivedFeeChargesPortionOfTransaction = Money.zero(currency); + + Money feesDue = getPenaltyChargesOutstanding(currency); + if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) { + this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount(); + waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue); + } else { + this.feeChargesWaived = getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount(); + waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining); + } + + this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived); + + this.completed = getTotalOutstanding(currency).isZero(); + + return waivedFeeChargesPortionOfTransaction; + } + + public Money writeOffOutstandingPrincipal(final MonetaryCurrency currency) { + + final Money principalDue = getPrincipalOutstanding(currency); + this.principalWrittenOff = defaultToNullIfZero(principalDue.getAmount()); + this.completed = getTotalOutstanding(currency).isZero(); + + return principalDue; + } + + public Money writeOffOutstandingInterest(final MonetaryCurrency currency) { + + final Money interestDue = getInterestOutstanding(currency); + this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount()); + this.completed = getTotalOutstanding(currency).isZero(); + + return interestDue; + } + + public boolean isOverdueOn(final LocalDate transactionDate) { + return this.getDueDate().isBefore(transactionDate); + } + + public void updateChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff, + final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) { + this.feeCharges = defaultToNullIfZero(feeChargesDue.getAmount()); + this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount()); + this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount()); + this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount()); + this.penaltyChargesWaived = defaultToNullIfZero(penaltyChargesWaived.getAmount()); + this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesWrittenOff.getAmount()); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java index 316307431..87ae169f7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java @@ -10,12 +10,10 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -36,7 +34,7 @@ import org.mifosplatform.useradministration.domain.AppUser; */ @Entity @Table(name = "m_loan_transaction") -public class LoanTransaction extends AbstractAuditableCustom { +public final class LoanTransaction extends AbstractAuditableCustom { @ManyToOne(optional = false) @JoinColumn(name = "loan_id", nullable = false) @@ -64,9 +62,8 @@ public class LoanTransaction extends AbstractAuditableCustom { @Column(name = "transaction_type_enum", nullable = false) private final Integer typeOf; - @OneToOne(optional = true, cascade = { CascadeType.PERSIST }) - @JoinColumn(name = "contra_id") - private LoanTransaction contra; + @Column(name = "is_reversed", nullable = false) + private boolean reversed; protected LoanTransaction() { this.loan = null; @@ -98,21 +95,10 @@ public class LoanTransaction extends AbstractAuditableCustom { return waiver; } - private static LoanTransaction contra(final LoanTransaction originalTransaction) { - LoanTransaction contra = new LoanTransaction(null, LoanTransactionType.CONTRA, originalTransaction.getAmount().negate(), - new LocalDate(originalTransaction.getDateOf())); - contra.updateContra(originalTransaction); - return contra; - } - public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate) { return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate); } - public void updateContra(final LoanTransaction transaction) { - this.contra = transaction; - } - private LoanTransaction(final Loan loan, final LoanTransactionType type, final BigDecimal amount, final LocalDate date) { this.loan = loan; this.typeOf = type.getValue(); @@ -120,108 +106,21 @@ public class LoanTransaction extends AbstractAuditableCustom { this.dateOf = date.toDateMidnight().toDate(); } - public BigDecimal getAmount() { - return this.amount; + public void reverse() { + this.reversed = true; } - public Money getAmount(final MonetaryCurrency currency) { - return Money.of(currency, this.amount); + public void resetDerivedComponents() { + this.principalPortion = null; + this.interestPortion = null; + this.feeChargesPortion = null; + this.penaltyChargesPortion = null; } - public LocalDate getTransactionDate() { - return new LocalDate(this.dateOf); - } - - public Date getDateOf() { - return dateOf; - } - - public LoanTransactionType getTypeOf() { - return LoanTransactionType.fromInt(this.typeOf); - } - - public boolean isRepayment() { - return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotContra(); - } - - public boolean isNotRepayment() { - return !isRepayment(); - } - - public boolean isNotContra() { - return this.contra == null; - } - - public boolean isContra() { - return this.contra != null; - } - - public boolean isDisbursement() { - return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()); - } - - public boolean isRepaymentAtDisbursement() { - return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()); - } - - public boolean isInterestWaiver() { - return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotContra(); - } - - public boolean isChargesWaiver() { - return LoanTransactionType.WAIVE_CHARGES.equals(getTypeOf()) && isNotContra(); - } - - public boolean isNotInterestWaiver() { - return !isInterestWaiver(); - } - - public boolean isWaiver() { - return isInterestWaiver() || isChargesWaiver(); - } - - public boolean isNotWaiver() { - return !isInterestWaiver() && !isChargesWaiver(); - } - - public boolean isWriteOff() { - return getTypeOf().isWriteOff() && isNotContra(); - } - - public boolean isIdentifiedBy(final Long identifier) { - return this.getId().equals(identifier); - } - - public boolean isBelongingToLoanOf(final Loan check) { - return this.loan.getId().equals(check.getId()); - } - - public boolean isNotBelongingToLoanOf(final Loan check) { - return !isBelongingToLoanOf(check); - } - - public LoanTransaction contra() { - this.contra = LoanTransaction.contra(this); - contra.updateLoan(this.loan); - - return this.contra; - } - - // public LoanTransaction newContra() { - // // should update some flag old entry being contra'd - // LoanTransaction contra = LoanTransaction.contra(this); - // contra.updateLoan(this.loan); - // return contra; - // } - public void updateLoan(final Loan loan) { this.loan = loan; } - public boolean isNonZero() { - return this.amount.subtract(BigDecimal.ZERO).doubleValue() > 0; - } - /** * This updates the derived fields of a loan transaction for the principal, * interest and interest waived portions. @@ -282,11 +181,92 @@ public class LoanTransaction extends AbstractAuditableCustom { return this.penaltyChargesPortion; } - public void resetDerivedComponents() { - this.principalPortion = null; - this.interestPortion = null; - this.feeChargesPortion = null; - this.penaltyChargesPortion = null; + public BigDecimal getAmount() { + return this.amount; + } + + public Money getAmount(final MonetaryCurrency currency) { + return Money.of(currency, this.amount); + } + + public LocalDate getTransactionDate() { + return new LocalDate(this.dateOf); + } + + public Date getDateOf() { + return dateOf; + } + + public LoanTransactionType getTypeOf() { + return LoanTransactionType.fromInt(this.typeOf); + } + + public boolean isReversed() { + return this.reversed; + } + + public boolean isNotReversed() { + return !isReversed(); + } + + public boolean isRepayment() { + return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotReversed(); + } + + public boolean isNotRepayment() { + return !isRepayment(); + } + + public boolean isDisbursement() { + return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()) && isNotReversed(); + } + + public boolean isRepaymentAtDisbursement() { + return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()) && isNotReversed(); + } + + private boolean isRecoveryRepayment() { + return LoanTransactionType.RECOVERY_REPAYMENT.equals(getTypeOf()) && isNotReversed(); + } + + public boolean isInterestWaiver() { + return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotReversed(); + } + + public boolean isChargesWaiver() { + return LoanTransactionType.WAIVE_CHARGES.equals(getTypeOf()) && isNotReversed(); + } + + public boolean isNotInterestWaiver() { + return !isInterestWaiver(); + } + + public boolean isWaiver() { + return isInterestWaiver() || isChargesWaiver(); + } + + public boolean isNotWaiver() { + return !isInterestWaiver() && !isChargesWaiver(); + } + + public boolean isWriteOff() { + return getTypeOf().isWriteOff() && isNotReversed(); + } + + public boolean isIdentifiedBy(final Long identifier) { + return this.getId().equals(identifier); + } + + public boolean isBelongingToLoanOf(final Loan check) { + return this.loan.getId().equals(check.getId()); + } + + public boolean isNotBelongingToLoanOf(final Loan check) { + return !isBelongingToLoanOf(check); + } + + public boolean isNonZero() { + return this.amount.subtract(BigDecimal.ZERO).doubleValue() > 0; } public boolean isGreaterThan(final Money monetaryAmount) { @@ -318,19 +298,18 @@ public class LoanTransaction extends AbstractAuditableCustom { public Map toMapData(final CurrencyData currencyData) { final Map thisTransactionData = new LinkedHashMap(); - LoanTransactionType type = LoanTransactionType.fromInt(this.typeOf); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf); thisTransactionData.put("id", this.getId()); thisTransactionData.put("type", transactionType); - thisTransactionData.put("disbursement", type.isDisbursement()); - thisTransactionData.put("repaymentAtDisbursement", type.isRepaymentAtDisbursement()); - thisTransactionData.put("repayment", type.isRepayment()); - thisTransactionData.put("recoveryRepayment", type.isRecoveryRepayment()); - thisTransactionData.put("contra", type.isContra()); - thisTransactionData.put("waiveInterest", type.isWaiveInterest()); - thisTransactionData.put("waiveCharges", type.isWaiveCharges()); - thisTransactionData.put("writeOff", type.isWriteOff()); + thisTransactionData.put("disbursement", Boolean.valueOf(this.isDisbursement())); + thisTransactionData.put("repaymentAtDisbursement", Boolean.valueOf(this.isRepaymentAtDisbursement())); + thisTransactionData.put("repayment", Boolean.valueOf(this.isRepayment())); + thisTransactionData.put("recoveryRepayment", Boolean.valueOf(this.isRecoveryRepayment())); + thisTransactionData.put("contra", Boolean.valueOf(this.isReversed())); + thisTransactionData.put("waiveInterest", Boolean.valueOf(this.isInterestWaiver())); + thisTransactionData.put("waiveCharges", Boolean.valueOf(this.isChargesWaiver())); + thisTransactionData.put("writeOff", Boolean.valueOf(this.isWriteOff())); thisTransactionData.put("date", this.getTransactionDate()); thisTransactionData.put("currency", currencyData); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java index 955194f98..62f6c3cad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java @@ -77,35 +77,31 @@ public enum LoanTransactionType { return loanTransactionType; } - public Boolean isDisbursement() { + public boolean isDisbursement() { return this.value.equals(LoanTransactionType.DISBURSEMENT.getValue()); } - public Boolean isRepaymentAtDisbursement() { + public boolean isRepaymentAtDisbursement() { return this.value.equals(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue()); } - public Boolean isRepayment() { + public boolean isRepayment() { return this.value.equals(LoanTransactionType.REPAYMENT.getValue()); } - public Boolean isRecoveryRepayment() { + public boolean isRecoveryRepayment() { return this.value.equals(LoanTransactionType.RECOVERY_REPAYMENT.getValue()); } - public Boolean isContra() { - return this.value.equals(LoanTransactionType.CONTRA.getValue()); - } - - public Boolean isWaiveInterest() { + public boolean isWaiveInterest() { return this.value.equals(LoanTransactionType.WAIVE_INTEREST.getValue()); } - public Boolean isWaiveCharges() { + public boolean isWaiveCharges() { return this.value.equals(LoanTransactionType.WAIVE_CHARGES.getValue()); } - public Boolean isWriteOff() { + public boolean isWriteOff() { return this.value.equals(LoanTransactionType.WRITEOFF.getValue()); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanNotFoundException.java index 25aafb7bc..4d3074205 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanNotFoundException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanNotFoundException.java @@ -12,7 +12,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN */ public class LoanNotFoundException extends AbstractPlatformResourceNotFoundException { - public LoanNotFoundException(Long id) { - super("error.msg.loan.id.invalid", "Loan with identifier " + id + " does not exist", id); - } + public LoanNotFoundException(final Long id) { + super("error.msg.loan.id.invalid", "Loan with identifier " + id + " does not exist", id); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 5611acc85..48f3733c8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -200,7 +200,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { // 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, 3) and tr.contra_id is null order by tr.transaction_date ASC"; + + " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.is_reversed=0 order by tr.transaction_date ASC"; return this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); } catch (EmptyResultDataAccessException e) { return null; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index ff9d9f7e6..dce196baf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -130,13 +130,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode()); - /*** - * In cases where an "Undo disbursement is done and the loan is - * disbursed again, we need to ensure the old transactions are entered - * again in accounting - ***/ final List existingTransactionIds = new ArrayList(); - final Map changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency, existingTransactionIds); + final List existingReversedTransactionIds = new ArrayList(); + final Map changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency, + existingTransactionIds, existingReversedTransactionIds); if (!changes.isEmpty()) { this.loanRepository.save(loan); @@ -144,8 +141,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf Note note = Note.loanNote(loan, noteText); this.noteRepository.save(note); } - - final Map accountingBridgeData = loan.deriveDisbursementData(currency.toData(), existingTransactionIds); + + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds, + existingReversedTransactionIds); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -169,7 +167,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Loan loan = retrieveLoanBy(loanId); final List existingTransactionIds = new ArrayList(); - final Map changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds); + final List existingReversedTransactionIds = new ArrayList(); + final Map changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds, + existingReversedTransactionIds); if (!changes.isEmpty()) { this.loanRepository.saveAndFlush(loan); @@ -179,10 +179,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.noteRepository.save(note); } - final Loan loanRefetch = retrieveLoanBy(loanId); - - final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode()); - final Map accountingBridgeData = loanRefetch.deriveAccountingBridgeData(currency.toData(), existingTransactionIds); + final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode()); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds, + existingReversedTransactionIds); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -736,7 +735,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(), loanTransaction.getAmount(), loanTransaction.getPrincipalPortion(), loanTransaction.getInterestPortion(), loanTransaction.getFeePortion(), loanTransaction.getPenaltyChargesPortion(), loanTransaction.isDisbursement(), - loanTransaction.isRepayment(), loanTransaction.isRepaymentAtDisbursement(), loanTransaction.isContra(), + loanTransaction.isRepayment(), loanTransaction.isRepaymentAtDisbursement(), loanTransaction.isReversed(), loanTransaction.isWriteOff()); loanTransactionDTOs.add(loanTransactionDTO); }