Merge pull request #627 from pramodn02/MIFOSX-639

handled external id for loan transaction
This commit is contained in:
Vishwas Babu A J
2013-10-08 22:51:22 -07:00
5 changed files with 84 additions and 28 deletions
@@ -444,10 +444,10 @@ public class Loan extends AbstractPersistable<Long> {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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<Long> {
**/
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<Long> {
return disbursementTransaction;
}
public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment,
final List<Long> existingTransactionIds,final List<Long> existingReversedTransactionIds) {
public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
LoanCharge charge = null;
@@ -1713,10 +1713,15 @@ public class Loan extends AbstractPersistable<Long> {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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();
@@ -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<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
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<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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);
}
@@ -136,21 +136,21 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
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<Long> {
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<Long> {
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<Long> {
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<Long> {
return LoanTransactionType.REFUND.equals(getTypeOf()) && isNotReversed();
}
public void updateExternalId(String externalId) {
this.externalId = externalId;
}
}
@@ -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);
}
}
@@ -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<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
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<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
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<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
for (Map.Entry<Long, LoanTransaction> 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);
}