From af0e17fbc900dd8926a2bc83d3b506445020818c Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Wed, 9 Oct 2013 10:35:08 +0530 Subject: [PATCH] handled external id for loan transaction --- .../portfolio/loanaccount/domain/Loan.java | 19 +++++--- .../domain/LoanAccountDomainServiceJpa.java | 31 +++++++++---- .../loanaccount/domain/LoanTransaction.java | 16 ++++--- ...RepaymentScheduleTransactionProcessor.java | 1 + ...WritePlatformServiceJpaRepositoryImpl.java | 45 +++++++++++++++---- 5 files changed, 84 insertions(+), 28 deletions(-) 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 f726df573..c718ebfba 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 @@ -444,10 +444,10 @@ public class Loan extends AbstractPersistable { final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges()); - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { mapEntry.getValue().updateLoan(this); } - this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); + // this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); } else { // just reprocess the loan schedule only for now. final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper(); @@ -1454,7 +1454,7 @@ public class Loan extends AbstractPersistable { **/ Money disbursentMoney = Money.zero(getCurrency()); final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, null, disbursedOn, - txnExternalId); + null); for (final LoanCharge charge : setOfLoanCharges()) { if (charge.isDueAtDisbursement()) { if (totalFeeChargesDueAtDisbursement.isGreaterThanZero() && !charge.getChargePaymentMode().isPaymentModeAccountTransfer()) { @@ -1493,8 +1493,8 @@ public class Loan extends AbstractPersistable { return disbursementTransaction; } - public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment, - final List existingTransactionIds,final List existingReversedTransactionIds) { + public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment, + final List existingTransactionIds, final List existingReversedTransactionIds) { existingTransactionIds.addAll(findExistingTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); LoanCharge charge = null; @@ -1713,10 +1713,15 @@ public class Loan extends AbstractPersistable { final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges()); - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { mapEntry.getValue().updateLoan(this); } - this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); + /*** + * Commented since throwing exception if external id present for one + * of the transactions. for this need to save the reversed + * transactions first and then new transactions. + */ + // this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); } updateLoanSummaryDerivedFields(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index 93b146826..fa75c87fa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -15,7 +15,10 @@ import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.organisation.holiday.domain.Holiday; import org.mifosplatform.organisation.holiday.domain.HolidayRepository; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; @@ -35,6 +38,7 @@ import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.NoteRepository; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -110,7 +114,18 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay); - this.loanTransactionRepository.save(newRepaymentTransaction); + try { + this.loanTransactionRepository.save(newRepaymentTransaction); + } catch (DataIntegrityViolationException e) { + final Throwable realCause = e.getCause(); + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction"); + if (realCause.getMessage().toLowerCase().contains("external_id_unique")) { + baseDataValidator.reset().parameter("externalId").value(newRepaymentTransaction.getExternalId()).failWithCode("value.must.be.unique"); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } /*** * TODO Vishwas Batch save is giving me a @@ -119,20 +134,20 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { * only in edge cases (when a payment is made before the latest payment * recorded against the loan) ***/ + + this.loanRepository.saveAndFlush(loan); + if (changedTransactionDetail != null) { - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { this.loanTransactionRepository.save(mapEntry.getValue()); updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } - this.loanRepository.save(loan); if (StringUtils.isNotBlank(noteText)) { final Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText); this.noteRepository.save(note); } - - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); @@ -255,10 +270,10 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { loanTransaction.reverse(); this.loanTransactionRepository.save(loanTransaction); } - - private void updateLoanTransaction(final Long loanTransactionId,final LoanTransaction newLoanTransaction){ + + private void updateLoanTransaction(final Long loanTransactionId, final LoanTransaction newLoanTransaction) { final AccountTransfer transferTransaction = this.accountTransferRepository.findByToLoanTransactionId(loanTransactionId); - if(transferTransaction!=null){ + if (transferTransaction != null) { transferTransaction.updateToLoanTransaction(newLoanTransaction); this.accountTransferRepository.save(transferTransaction); } 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 db8a2f419..05e5ea811 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 @@ -136,21 +136,21 @@ public final class LoanTransaction extends AbstractPersistable { return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() - .getTotalPenaltyChargesOutstanding(), null, false, null); + .getTotalPenaltyChargesOutstanding(), null, false, null,null); } public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate) { return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() - .getTotalPenaltyChargesOutstanding(), null, false, null); + .getTotalPenaltyChargesOutstanding(), null, false, null,null); } public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) { return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() - .getTotalPenaltyChargesOutstanding(), null, false, null); + .getTotalPenaltyChargesOutstanding(), null, false, null,null); } public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail, @@ -162,7 +162,7 @@ public final class LoanTransaction extends AbstractPersistable { return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf, loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.overPaymentPortion, - loanTransaction.reversed, loanTransaction.paymentDetail); + loanTransaction.reversed, loanTransaction.paymentDetail,loanTransaction.externalId); } public static LoanTransaction applyLoanCharge(final Loan loan, final Office office, final Money amount, final LocalDate applyDate, @@ -187,7 +187,7 @@ public final class LoanTransaction extends AbstractPersistable { private LoanTransaction(final Loan loan, final Office office, final Integer typeOf, final Date dateOf, final BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overPaymentPortion, final boolean reversed, - final PaymentDetail paymentDetail) { + final PaymentDetail paymentDetail,String externalId) { super(); this.loan = loan; this.typeOf = typeOf; @@ -201,6 +201,7 @@ public final class LoanTransaction extends AbstractPersistable { this.reversed = reversed; this.paymentDetail = paymentDetail; this.office = office; + this.externalId = externalId; } public static LoanTransaction waiveLoanCharge(final Loan loan, final Office office, final Money waived, final LocalDate waiveDate, @@ -502,4 +503,9 @@ public final class LoanTransaction extends AbstractPersistable { return LoanTransactionType.REFUND.equals(getTypeOf()) && isNotReversed(); } + + public void updateExternalId(String externalId) { + this.externalId = externalId; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java index 244f87bfd..8baf86e32 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java @@ -118,6 +118,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen **/ if (!LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) { loanTransaction.reverse(); + loanTransaction.updateExternalId(null); changedTransactionDetail.getNewTransactionMappings().put(loanTransaction.getId(), newLoanTransaction); } } 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 57eb08c83..a3890e644 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 @@ -23,8 +23,10 @@ import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException; import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; @@ -106,6 +108,7 @@ import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatf import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -234,7 +237,18 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay); if (!changes.isEmpty()) { - this.loanRepository.saveAndFlush(loan); + try { + this.loanRepository.saveAndFlush(loan); + } catch (DataIntegrityViolationException e) { + final Throwable realCause = e.getCause(); + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction"); + if (realCause.getMessage().toLowerCase().contains("external_id_unique")) { + baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique"); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException( + "validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } + } final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -346,7 +360,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay); if (!changes.isEmpty()) { - this.loanRepository.save(loan); + try { + this.loanRepository.save(loan); + } catch (DataIntegrityViolationException e) { + final Throwable realCause = e.getCause(); + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource("loan.transaction"); + if (realCause.getMessage().toLowerCase().contains("external_id_unique")) { + baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique"); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException( + "validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } + } final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -522,14 +548,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf * only in edge cases (when a adjustment is made before the latest * payment recorded against the loan) ***/ + this.loanRepository.saveAndFlush(loan); if (changedTransactionDetail != null) { - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { this.loanTransactionRepository.save(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } - this.loanRepository.save(loan); + final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { changes.put("note", noteText); @@ -598,14 +625,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf * only in edge cases (when a waiver is made before the latest payment * recorded against the loan) ***/ + this.loanRepository.saveAndFlush(loan); if (changedTransactionDetail != null) { - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { this.loanTransactionRepository.save(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } - this.loanRepository.save(loan); + final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -820,14 +848,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf * entered only in edge cases (when a payment is made before the * latest payment recorded against the loan) ***/ + this.loanRepository.saveAndFlush(loan); if (changedTransactionDetail != null) { - for(Map.Entry mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){ + for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { this.loanTransactionRepository.save(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } - this.loanRepository.save(loan); + // we post Journal entries only for loans in active status postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); }