wip:improving tracebililty for loan transaction updates

This commit is contained in:
Vishwas Babu AJ
2013-03-21 02:03:38 +05:30
parent 043e8dc4fd
commit d811304841
6 changed files with 175 additions and 44 deletions
@@ -29,8 +29,9 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
* existing in which case the entire loan schedule needs to be re-processed. * existing in which case the entire loan schedule needs to be re-processed.
*/ */
@Override @Override
public void handleTransaction(final LocalDate disbursementDate, final List<LoanTransaction> transactionsPostDisbursement, public ChangedTransactionDetail handleTransaction(final LocalDate disbursementDate,
final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) { final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
if (charges != null) { if (charges != null) {
for (LoanCharge loanCharge : charges) { for (LoanCharge loanCharge : charges) {
@@ -49,16 +50,36 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper(); LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(currency, disbursementDate, installments, charges); wrapper.reprocess(currency, disbursementDate, installments, charges);
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
for (LoanTransaction loanTransaction : transactionsPostDisbursement) { for (LoanTransaction loanTransaction : transactionsPostDisbursement) {
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver()) { if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver()) {
loanTransaction.resetDerivedComponents(); // pass through for new transactions
handleTransaction(loanTransaction, currency, installments, charges); if (loanTransaction.getId() == null) {
loanTransaction.resetDerivedComponents();
handleTransaction(loanTransaction, currency, installments, charges);
} else {
/**
* reverse existing transactions and create new transactions
* in their Lieu
**/
LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
// Reverse the original loan transaction
loanTransaction.reverse();
changedTransactionDetail.getReversedTransactions().add(loanTransaction);
// Reset derived component of new loan transaction
newLoanTransaction.resetDerivedComponents();
changedTransactionDetail.getNewTransactions().add(newLoanTransaction);
handleTransaction(newLoanTransaction, currency, installments, charges);
}
} else if (loanTransaction.isWriteOff()) { } else if (loanTransaction.isWriteOff()) {
loanTransaction.resetDerivedComponents(); loanTransaction.resetDerivedComponents();
handleWriteOff(loanTransaction, currency, installments); handleWriteOff(loanTransaction, currency, installments);
} }
} }
return changedTransactionDetail;
} }
/** /**
@@ -149,8 +170,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
for (LoanCharge loanCharge : charges) { for (LoanCharge loanCharge : charges) {
if (loanCharge.isNotFullyPaid() && !loanCharge.isDueAtDisbursement()) { if (loanCharge.isNotFullyPaid() && !loanCharge.isDueAtDisbursement()) {
if (earliestUnpaidCharge == null if (earliestUnpaidCharge == null || loanCharge.getDueLocalDate().isBefore(earliestUnpaidCharge.getDueLocalDate())) {
|| loanCharge.getDueLocalDate().isBefore(earliestUnpaidCharge.getDueLocalDate())) {
earliestUnpaidCharge = loanCharge; earliestUnpaidCharge = loanCharge;
} }
} }
@@ -0,0 +1,28 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.ArrayList;
import java.util.List;
public class ChangedTransactionDetail {
private List<LoanTransaction> newTransactions = new ArrayList<LoanTransaction>();
private List<LoanTransaction> reversedTransactions = new ArrayList<LoanTransaction>();
public List<LoanTransaction> getNewTransactions() {
return this.newTransactions;
}
public void setNewTransactions(List<LoanTransaction> newTransactions) {
this.newTransactions = newTransactions;
}
public List<LoanTransaction> getReversedTransactions() {
return this.reversedTransactions;
}
public void setReversedTransactions(List<LoanTransaction> reversedTransactions) {
this.reversedTransactions = reversedTransactions;
}
}
@@ -378,8 +378,9 @@ public class Loan extends AbstractPersistable<Long> {
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration; this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
} }
public LoanTransaction addLoanCharge(final LoanCharge loanCharge, final List<Long> existingTransactionIds, public ChangedTransactionDetail addLoanCharge(final LoanCharge loanCharge, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds) {
ChangedTransactionDetail changedTransactionDetail = null;
validateLoanIsNotClosed(loanCharge); validateLoanIsNotClosed(loanCharge);
@@ -412,8 +413,11 @@ public class Loan extends AbstractPersistable<Long> {
if (!loanCharge.isDueAtDisbursement()) { if (!loanCharge.isDueAtDisbursement()) {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges()); allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
for (LoanTransaction transaction : changedTransactionDetail.getNewTransactions()) {
transaction.updateLoan(this);
}
} else { } else {
// just reprocess the loan schedule only for now. // just reprocess the loan schedule only for now.
LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper(); LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
@@ -424,9 +428,8 @@ public class Loan extends AbstractPersistable<Long> {
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LoanTransaction applyLoanChargeTransaction = getChargeAppliedTransaction(loanCharge, null);
return applyLoanChargeTransaction; return changedTransactionDetail;
} }
/** /**
@@ -441,7 +444,7 @@ public class Loan extends AbstractPersistable<Long> {
* @param suppliedTransactionDate * @param suppliedTransactionDate
* @return * @return
*/ */
private LoanTransaction getChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) { public LoanTransaction getChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) {
final Money chargeAmount = loanCharge.getAmount(getCurrency()); final Money chargeAmount = loanCharge.getAmount(getCurrency());
Money feeCharges = chargeAmount; Money feeCharges = chargeAmount;
Money penaltyCharges = Money.zero(loanCurrency()); Money penaltyCharges = Money.zero(loanCurrency());
@@ -615,6 +618,14 @@ public class Loan extends AbstractPersistable<Long> {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy); .determineProcessor(this.transactionProcessingStrategy);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) {
/****
* TODO vishwas Currently we do not allow waiving fully paid loan
* charge and waiving partially paid loan charges only waives the
* remaining amount.
*
* Consider removing this block of code or logically completing it
* for the future by getting the list of affected Transactions
***/
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges()); getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
@@ -1396,24 +1407,24 @@ public class Loan extends AbstractPersistable<Long> {
return waiveInterestTransaction; return waiveInterestTransaction;
} }
public LoanTransaction makeRepayment(final LocalDate transactionDate, final BigDecimal transactionAmount, public ChangedTransactionDetail makeRepayment(final LoanTransaction repaymentTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds, final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds) {
final Money repayment = Money.of(loanCurrency(), transactionAmount);
final LoanTransaction loanTransaction = LoanTransaction.repayment(repayment, transactionDate);
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
handleRepaymentOrWaiverTransaction(loanTransaction, loanLifecycleStateMachine, null); ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrWaiverTransaction(repaymentTransaction,
loanLifecycleStateMachine, null);
return loanTransaction; return changedTransactionDetail;
} }
private void handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction, private ChangedTransactionDetail handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) { final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) {
ChangedTransactionDetail changedTransactionDetail = null;
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
LoanStatus.fromInt(this.loanStatus)); LoanStatus.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue(); this.loanStatus = statusEnum.getValue();
@@ -1463,13 +1474,18 @@ public class Loan extends AbstractPersistable<Long> {
setOfLoanCharges()); setOfLoanCharges());
} else { } else {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges()); allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
for (LoanTransaction newLoanTransaction : changedTransactionDetail.getNewTransactions()) {
newLoanTransaction.updateLoan(this);
}
} }
updateLoanSummaryDerivedFields(); updateLoanSummaryDerivedFields();
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine); doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
return changedTransactionDetail;
} }
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() { private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
@@ -1614,19 +1630,15 @@ public class Loan extends AbstractPersistable<Long> {
return LoanTransaction.waiver(this, possibleInterestToWaive, transactionDate); return LoanTransaction.waiver(this, possibleInterestToWaive, transactionDate);
} }
public LoanTransaction adjustExistingTransaction(final LocalDate transactionDate, final BigDecimal transactionAmountValue, public ChangedTransactionDetail adjustExistingTransaction(final LoanTransaction newTransactionDetail,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment, final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) { final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
ChangedTransactionDetail changedTransactionDetail = null;
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final Money transactionAmount = Money.of(loanCurrency(), transactionAmountValue);
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmount, transactionDate);
if (transactionForAdjustment.isInterestWaiver()) {
newTransactionDetail = LoanTransaction.waiver(this, transactionAmount, transactionDate);
}
if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) { if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) {
final String errorMessage = "Only transactions of type repayment or waiver can be adjusted."; final String errorMessage = "Only transactions of type repayment or waiver can be adjusted.";
throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.only.allowed.to.repayment.or.waiver.transaction", throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.only.allowed.to.repayment.or.waiver.transaction",
@@ -1640,10 +1652,11 @@ public class Loan extends AbstractPersistable<Long> {
transactionForAdjustment.reverse(); transactionForAdjustment.reverse();
if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) { if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment); changedTransactionDetail = handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
transactionForAdjustment);
} }
return newTransactionDetail; return changedTransactionDetail;
} }
private boolean isOverPaid() { private boolean isOverPaid() {
@@ -16,7 +16,7 @@ public interface LoanRepaymentScheduleTransactionProcessor {
void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments, void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> charges); Set<LoanCharge> charges);
void handleTransaction(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers, MonetaryCurrency currency, ChangedTransactionDetail handleTransaction(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges); List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges);
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency, void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
@@ -86,14 +86,34 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate); return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate);
} }
public static LoanTransaction applyLoanCharge(final Loan loan, final Money amount, final LocalDate applyDate, public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) {
final Money feeCharges, final Money penaltyCharges) { return new LoanTransaction(loanTransaction.loan, loanTransaction.typeOf, loanTransaction.dateOf, loanTransaction.amount,
loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.feeChargesPortion,
loanTransaction.penaltyChargesPortion, loanTransaction.reversed);
}
public static LoanTransaction applyLoanCharge(final Loan loan, final Money amount, final LocalDate applyDate, final Money feeCharges,
final Money penaltyCharges) {
LoanTransaction applyCharge = new LoanTransaction(loan, LoanTransactionType.APPLY_CHARGES, amount.getAmount(), applyDate); LoanTransaction applyCharge = new LoanTransaction(loan, LoanTransactionType.APPLY_CHARGES, amount.getAmount(), applyDate);
applyCharge.updateChargesComponents(feeCharges, penaltyCharges); applyCharge.updateChargesComponents(feeCharges, penaltyCharges);
return applyCharge; return applyCharge;
} }
private LoanTransaction(Loan loan, Integer typeOf, Date dateOf, BigDecimal amount, BigDecimal principalPortion,
BigDecimal interestPortion, BigDecimal feeChargesPortion, BigDecimal penaltyChargesPortion, boolean reversed) {
super();
this.loan = loan;
this.typeOf = typeOf;
this.dateOf = dateOf;
this.amount = amount;
this.principalPortion = principalPortion;
this.interestPortion = interestPortion;
this.feeChargesPortion = feeChargesPortion;
this.penaltyChargesPortion = penaltyChargesPortion;
this.reversed = reversed;
}
public static LoanTransaction waiveLoanCharge(final Loan loan, final Money waived, final LocalDate waiveDate, public static LoanTransaction waiveLoanCharge(final Loan loan, final Money waived, final LocalDate waiveDate,
final Money feeChargesWaived, final Money penaltyChargesWaived) { final Money feeChargesWaived, final Money penaltyChargesWaived) {
LoanTransaction waiver = new LoanTransaction(loan, LoanTransactionType.WAIVE_CHARGES, waived.getAmount(), waiveDate); LoanTransaction waiver = new LoanTransaction(loan, LoanTransactionType.WAIVE_CHARGES, waived.getAmount(), waiveDate);
@@ -305,7 +325,6 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
return thisTransactionData; return thisTransactionData;
} }
public Loan getLoan() { public Loan getLoan() {
return this.loan; return this.loan;
} }
@@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepository; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepository;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
@@ -32,6 +33,7 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedExce
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON; import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException; import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand; import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
@@ -207,15 +209,31 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingTransactionIds = new ArrayList<Long>(); final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final LoanTransaction loanRepayment = loan.makeRepayment(transactionDate, transactionAmount, defaultLoanLifecycleStateMachine(), final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount);
existingTransactionIds, existingReversedTransactionIds); final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, transactionDate);
this.loanTransactionRepository.save(loanRepayment);
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds);
this.loanTransactionRepository.save(newRepaymentTransaction);
/***
* TODO Vishwas Batch save is giving me a
* HibernateOptimisticLockingFailureException, looping and saving for
* the time being, not a major issue for now as this loop is entered
* only in edge cases (when a payment is made before the latest payment
* recorded against the loan)
***/
if (changedTransactionDetail != null) {
for (LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
this.loanTransactionRepository.save(loanTransaction);
}
}
this.loanRepository.save(loan); this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText); changes.put("note", noteText);
Note note = Note.loanTransactionNote(loan, loanRepayment, noteText); Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
@@ -223,7 +241,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withEntityId(loanRepayment.getId()) // .withEntityId(newRepaymentTransaction.getId()) //
.withOfficeId(loan.getOfficeId()) // .withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) // .withClientId(loan.getClientId()) //
.withGroupId(loan.getGroupId()) // .withGroupId(loan.getGroupId()) //
@@ -257,13 +275,32 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingTransactionIds = new ArrayList<Long>(); final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount, final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, transactionDate);
if (transactionToAdjust.isInterestWaiver()) {
newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate);
}
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds); defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds);
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
this.loanTransactionRepository.save(newTransactionDetail); this.loanTransactionRepository.save(newTransactionDetail);
} }
/***
* TODO Vishwas Batch save is giving me a
* HibernateOptimisticLockingFailureException, looping and saving for
* the time being, not a major issue for now as this loop is entered
* only in edge cases (when a payment is made before the latest payment
* recorded against the loan)
***/
if (changedTransactionDetail != null) {
for (LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
this.loanTransactionRepository.save(loanTransaction);
}
}
this.loanRepository.save(loan); this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
@@ -495,12 +532,26 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
this.loanChargeRepository.save(loanCharge); this.loanChargeRepository.save(loanCharge);
LoanTransaction applyChargeTransaction = loan.addLoanCharge(loanCharge, existingTransactionIds, existingReversedTransactionIds); final LoanTransaction applyLoanChargeTransaction = loan.getChargeAppliedTransaction(loanCharge, null);
final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds,
existingReversedTransactionIds);
// we want to apply charge transactions only for those loans charges // we want to apply charge transactions only for those loans charges
// that are applied when a loan is active // that are applied when a loan is active
if (loan.status().isActive()) { if (loan.status().isActive()) {
this.loanTransactionRepository.save(applyChargeTransaction); this.loanTransactionRepository.save(applyLoanChargeTransaction);
/***
* TODO Vishwas Batch save is giving me a
* HibernateOptimisticLockingFailureException, looping and saving
* for the time being, not a major issue for now as this loop is
* entered only in edge cases (when a payment is made before the
* latest payment recorded against the loan)
***/
if (changedTransactionDetail != null) {
for (LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
this.loanTransactionRepository.save(loanTransaction);
}
}
} }
this.loanRepository.save(loan); this.loanRepository.save(loan);