Merge pull request #503 from johnw65/externalIds

mifosx-567 add support for externalId for loan transactions
This commit is contained in:
John Woodlock
2013-08-02 12:09:51 -07:00
8 changed files with 64 additions and 43 deletions
@@ -0,0 +1,3 @@
ALTER TABLE m_loan_transaction
ADD COLUMN `external_id` VARCHAR(100) NULL DEFAULT NULL AFTER `is_reversed` ,
ADD UNIQUE INDEX `external_id_UNIQUE` (`external_id` ASC) ;
@@ -45,7 +45,7 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class LoanTransactionsApiResource { public class LoanTransactionsApiResource {
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "type", "date", "currency", "amount")); private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "type", "date", "currency", "amount", "externalId"));
private final String resourceNameForPermissions = "LOAN"; private final String resourceNameForPermissions = "LOAN";
@@ -32,6 +32,7 @@ public class LoanTransactionData {
private final BigDecimal interestPortion; private final BigDecimal interestPortion;
private final BigDecimal feeChargesPortion; private final BigDecimal feeChargesPortion;
private final BigDecimal penaltyChargesPortion; private final BigDecimal penaltyChargesPortion;
private final String externalId;
// templates // templates
final Collection<CodeValueData> paymentTypeOptions; final Collection<CodeValueData> paymentTypeOptions;
@@ -40,20 +41,20 @@ public class LoanTransactionData {
return new LoanTransactionData(loanTransactionData.id, loanTransactionData.type, loanTransactionData.paymentDetailData, return new LoanTransactionData(loanTransactionData.id, loanTransactionData.type, loanTransactionData.paymentDetailData,
loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion, loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion,
loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion,
paymentTypeOptions); paymentTypeOptions, loanTransactionData.externalId);
} }
public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData,
final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion,
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion) { final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final String externalId) {
this(id, transactionType, paymentDetailData, currency, date, amount, principalPortion, interestPortion, feeChargesPortion, this(id, transactionType, paymentDetailData, currency, date, amount, principalPortion, interestPortion, feeChargesPortion,
penaltyChargesPortion, null); penaltyChargesPortion, null, externalId);
} }
public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData,
final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion,
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
final Collection<CodeValueData> paymentTypeOptions) { final Collection<CodeValueData> paymentTypeOptions, final String externalId) {
this.id = id; this.id = id;
this.type = transactionType; this.type = transactionType;
this.paymentDetailData = paymentDetailData; this.paymentDetailData = paymentDetailData;
@@ -65,6 +66,7 @@ public class LoanTransactionData {
this.feeChargesPortion = feeChargesPortion; this.feeChargesPortion = feeChargesPortion;
this.penaltyChargesPortion = penaltyChargesPortion; this.penaltyChargesPortion = penaltyChargesPortion;
this.paymentTypeOptions = paymentTypeOptions; this.paymentTypeOptions = paymentTypeOptions;
this.externalId = externalId;
} }
public LocalDate dateOf() { public LocalDate dateOf() {
@@ -1331,7 +1331,8 @@ public class Loan extends AbstractPersistable<Long> {
actualChanges.put("status", LoanEnumerations.status(this.loanStatus)); actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
final String txnExternalId = command.stringValueOfParameterNamed("externalId");
this.actualDisbursementDate = actualDisbursementDate.toDate(); this.actualDisbursementDate = actualDisbursementDate.toDate();
this.disbursedBy = currentUser; this.disbursedBy = currentUser;
updateLoanScheduleDependentDerivedFields(); updateLoanScheduleDependentDerivedFields();
@@ -1344,7 +1345,7 @@ public class Loan extends AbstractPersistable<Long> {
validateDisbursementDateIsOnNonWorkingDay(workingDays); validateDisbursementDateIsOnNonWorkingDay(workingDays);
validateDisbursementDateIsOnHoliday(isHolidayEnabled, holidays); validateDisbursementDateIsOnHoliday(isHolidayEnabled, holidays);
handleDisbursementTransaction(paymentDetail, actualDisbursementDate); handleDisbursementTransaction(paymentDetail, actualDisbursementDate, txnExternalId);
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) { if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays); regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
@@ -1394,10 +1395,10 @@ public class Loan extends AbstractPersistable<Long> {
updateLoanSchedule(loanSchedule); updateLoanSchedule(loanSchedule);
} }
private LoanTransaction handleDisbursementTransaction(final PaymentDetail paymentDetail, final LocalDate disbursedOn) { private LoanTransaction handleDisbursementTransaction(final PaymentDetail paymentDetail, final LocalDate disbursedOn, final String txnExternalId) {
// track disbursement transaction // track disbursement transaction
final LoanTransaction disbursementTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), final LoanTransaction disbursementTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(),
paymentDetail, disbursedOn); paymentDetail, disbursedOn, txnExternalId);
disbursementTransaction.updateLoan(this); disbursementTransaction.updateLoan(this);
this.loanTransactions.add(disbursementTransaction); this.loanTransactions.add(disbursementTransaction);
@@ -1411,7 +1412,7 @@ public class Loan extends AbstractPersistable<Long> {
final Money totalFeeChargesDueAtDisbursement = this.summary.getTotalFeeChargesDueAtDisbursement(loanCurrency()); final Money totalFeeChargesDueAtDisbursement = this.summary.getTotalFeeChargesDueAtDisbursement(loanCurrency());
if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()) { if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()) {
LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(totalFeeChargesDueAtDisbursement, null, disbursedOn); LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(totalFeeChargesDueAtDisbursement, null, disbursedOn, txnExternalId);
Money zero = Money.zero(getCurrency()); Money zero = Money.zero(getCurrency());
chargesPayment.updateComponents(zero, zero, totalFeeChargesDueAtDisbursement, zero); chargesPayment.updateComponents(zero, zero, totalFeeChargesDueAtDisbursement, zero);
chargesPayment.updateLoan(this); chargesPayment.updateLoan(this);
@@ -1830,6 +1831,7 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LocalDate writtenOffOnLocalDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate writtenOffOnLocalDate = command.localDateValueOfParameterNamed("transactionDate");
final String txnExternalId = command.stringValueOfParameterNamed("externalId");
this.closedOnDate = writtenOffOnLocalDate.toDate(); this.closedOnDate = writtenOffOnLocalDate.toDate();
this.writtenOffOnDate = writtenOffOnLocalDate.toDate(); this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
@@ -1849,7 +1851,7 @@ public class Loan extends AbstractPersistable<Long> {
throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate); throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate);
} }
loanTransaction = LoanTransaction.writeoff(this, writtenOffOnLocalDate); loanTransaction = LoanTransaction.writeoff(this, writtenOffOnLocalDate, txnExternalId);
final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions);
if (!isLastTransaction) { if (!isLastTransaction) {
final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions."; final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
@@ -1876,7 +1878,8 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LocalDate closureDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate closureDate = command.localDateValueOfParameterNamed("transactionDate");
final String txnExternalId = command.stringValueOfParameterNamed("externalId");
this.closedOnDate = closureDate.toDate(); this.closedOnDate = closureDate.toDate();
changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -1905,7 +1908,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
this.closedOnDate = closureDate.toDate(); this.closedOnDate = closureDate.toDate();
loanTransaction = LoanTransaction.writeoff(this, closureDate); loanTransaction = LoanTransaction.writeoff(this, closureDate, txnExternalId);
boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions);
if (!isLastTransaction) { if (!isLastTransaction) {
final String errorMessage = "The closing date of the loan must be on or after latest transaction date."; final String errorMessage = "The closing date of the loan must be on or after latest transaction date.";
@@ -23,6 +23,7 @@ import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
@@ -42,7 +43,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
* Disbursements, Repayments, Waivers, Write-off etc * Disbursements, Repayments, Waivers, Write-off etc
*/ */
@Entity @Entity
@Table(name = "m_loan_transaction") @Table(name = "m_loan_transaction", uniqueConstraints = {@UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE") })
public final class LoanTransaction extends AbstractPersistable<Long> { public final class LoanTransaction extends AbstractPersistable<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@@ -78,6 +79,9 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
@Column(name = "is_reversed", nullable = false) @Column(name = "is_reversed", nullable = false)
private boolean reversed; private boolean reversed;
@Column(name = "external_id", length = 100, nullable = true, unique = true)
private String externalId;
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true)
private Set<LoanChargePaidBy> loanChargesPaid = new HashSet<LoanChargePaidBy>(); private Set<LoanChargePaidBy> loanChargesPaid = new HashSet<LoanChargePaidBy>();
@@ -88,24 +92,24 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.typeOf = null; this.typeOf = null;
} }
public static LoanTransaction disbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate disbursementDate) { public static LoanTransaction disbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate disbursementDate, final String externalId) {
return new LoanTransaction(null, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate); return new LoanTransaction(null, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate, externalId);
} }
public static LoanTransaction repayment(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate) { public static LoanTransaction repayment(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate, final String externalId) {
return new LoanTransaction(null, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate); return new LoanTransaction(null, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
} }
public static LoanTransaction repaymentAtDisbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate) { public static LoanTransaction repaymentAtDisbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate, final String externalId) {
return new LoanTransaction(null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(), paymentDate); return new LoanTransaction(null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
} }
public static LoanTransaction waiver(final Loan loan, final Money waived, final LocalDate waiveDate) { public static LoanTransaction waiver(final Loan loan, final Money waived, final LocalDate waiveDate) {
return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate); return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate, null);
} }
public static LoanTransaction applyInterest(final Loan loan, final Money amount, final LocalDate interestAppliedDate) { public static LoanTransaction applyInterest(final Loan loan, final Money amount, final LocalDate interestAppliedDate) {
return new LoanTransaction(loan, LoanTransactionType.APPLY_INTEREST, amount.getAmount(), interestAppliedDate); return new LoanTransaction(loan, LoanTransactionType.APPLY_INTEREST, amount.getAmount(), interestAppliedDate, null);
} }
public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) { public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) {
@@ -116,7 +120,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
public static LoanTransaction applyLoanCharge(final Loan loan, final Money amount, final LocalDate applyDate, final Money feeCharges, public static LoanTransaction applyLoanCharge(final Loan loan, final Money amount, final LocalDate applyDate, final Money feeCharges,
final Money penaltyCharges) { 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, null);
applyCharge.updateChargesComponents(feeCharges, penaltyCharges); applyCharge.updateChargesComponents(feeCharges, penaltyCharges);
return applyCharge; return applyCharge;
} }
@@ -149,30 +153,32 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
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, null);
waiver.updateChargesComponents(feeChargesWaived, penaltyChargesWaived); waiver.updateChargesComponents(feeChargesWaived, penaltyChargesWaived);
return waiver; return waiver;
} }
public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate) { public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate, final String externalId) {
return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate); return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate, externalId);
} }
private LoanTransaction(final Loan loan, final LoanTransactionType type, final BigDecimal amount, final LocalDate date) { private LoanTransaction(final Loan loan, final LoanTransactionType type, final BigDecimal amount, final LocalDate date, final String externalId) {
this.loan = loan; this.loan = loan;
this.typeOf = type.getValue(); this.typeOf = type.getValue();
this.amount = amount; this.amount = amount;
this.dateOf = date.toDateMidnight().toDate(); this.dateOf = date.toDateMidnight().toDate();
this.externalId = externalId;
} }
private LoanTransaction(final Loan loan, final LoanTransactionType type, final PaymentDetail paymentDetail, final BigDecimal amount, private LoanTransaction(final Loan loan, final LoanTransactionType type, final PaymentDetail paymentDetail, final BigDecimal amount,
final LocalDate date) { final LocalDate date, final String externalId) {
this.loan = loan; this.loan = loan;
this.typeOf = type.getValue(); this.typeOf = type.getValue();
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
this.amount = amount; this.amount = amount;
this.dateOf = date.toDateMidnight().toDate(); this.dateOf = date.toDateMidnight().toDate();
this.externalId = externalId;
} }
public void reverse() { public void reverse() {
@@ -353,7 +359,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
paymentDetailData = paymentDetail.toData(); paymentDetailData = paymentDetail.toData();
} }
return new LoanTransactionData(this.getId(), transactionType, paymentDetailData, currencyData, getTransactionDate(), this.amount, return new LoanTransactionData(this.getId(), transactionType, paymentDetailData, currencyData, getTransactionDate(), this.amount,
this.principalPortion, this.interestPortion, this.feeChargesPortion, this.penaltyChargesPortion); this.principalPortion, this.interestPortion, this.feeChargesPortion, this.penaltyChargesPortion, this.externalId);
} }
public Map<String, Object> toMapData(final CurrencyData currencyData) { public Map<String, Object> toMapData(final CurrencyData currencyData) {
@@ -405,4 +411,8 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.loanChargesPaid = loanChargesPaid; this.loanChargesPaid = loanChargesPaid;
} }
public String getExternalId() {
return externalId;
}
} }
@@ -50,7 +50,7 @@ public final class LoanEventApiJsonValidator {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "note", "locale", final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "externalId", "note", "locale",
"dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber")); "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
@@ -92,7 +92,7 @@ public final class LoanEventApiJsonValidator {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "note", final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId", "note",
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber")); "locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
@@ -119,7 +119,7 @@ public final class LoanEventApiJsonValidator {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "note", final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId", "note",
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber")); "locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
@@ -315,7 +315,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions); possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions, null);
} }
@Override @Override
@@ -339,7 +339,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final BigDecimal amount = waiveOfInterest.getAmount(currency).getAmount(); final BigDecimal amount = waiveOfInterest.getAmount(currency).getAmount();
return new LoanTransactionData(null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount, null, null, return new LoanTransactionData(null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount, null, null,
null, null); null, null, null);
} }
@Override @Override
@@ -348,7 +348,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
context.authenticatedUser(); context.authenticatedUser();
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF);
return new LoanTransactionData(null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null, null, null); return new LoanTransactionData(null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null, null, null, null);
} }
@Override @Override
@@ -359,7 +359,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return new LoanTransactionData(null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null, null, null, return new LoanTransactionData(null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null, null, null,
null, paymentOptions); null, paymentOptions, null);
} }
@Override @Override
@@ -844,7 +844,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, " + " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, " + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, "
+ " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, " + " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " cv.code_value as paymentTypeName " + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id" + " cv.code_value as paymentTypeName, tr.external_id as externalId " + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id"
+ " join m_currency rc on rc.`code` = l.currency_code " + " join m_currency rc on rc.`code` = l.currency_code "
+ " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id" + " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id"
+ " left join m_code_value cv on pd.payment_type_cv_id = cv.id"; + " left join m_code_value cv on pd.payment_type_cv_id = cv.id";
@@ -887,9 +887,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final BigDecimal interestPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interest"); final BigDecimal interestPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interest");
final BigDecimal feeChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "fees"); final BigDecimal feeChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "fees");
final BigDecimal penaltyChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penalties"); final BigDecimal penaltyChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penalties");
final String externalId = rs.getString("externalId");
return new LoanTransactionData(id, transactionType, paymentDetailData, currencyData, date, totalAmount, principalPortion, return new LoanTransactionData(id, transactionType, paymentDetailData, currencyData, date, totalAmount, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion); interestPortion, feeChargesPortion, penaltyChargesPortion, externalId);
} }
} }
@@ -349,6 +349,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount"); final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final String txnExternalId = command.stringValueOfParameterNamed("externalId");
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -364,7 +365,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount, CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount,
transactionDate, noteText); transactionDate, noteText, txnExternalId);
return commandProcessingResultBuilder.withCommandId(command.commandId()) // return commandProcessingResultBuilder.withCommandId(command.commandId()) //
.withLoanId(loanId) // .withLoanId(loanId) //
@@ -373,7 +374,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
private CommandProcessingResultBuilder saveLoanRepayment(final Long loanId, final PaymentDetail paymentDetail, private CommandProcessingResultBuilder saveLoanRepayment(final Long loanId, final PaymentDetail paymentDetail,
final BigDecimal transactionAmount, final LocalDate transactionDate, final String noteText) { final BigDecimal transactionAmount, final LocalDate transactionDate, final String noteText, final String txnExternalId) {
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
// TODO: Is it required to validate transaction date with meeting dates // TODO: Is it required to validate transaction date with meeting dates
@@ -393,7 +394,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount); final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount);
final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, paymentDetail, transactionDate); final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, paymentDetail, transactionDate, txnExternalId);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate()); final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate());
final WorkingDays workingDays = this.workingDaysRepository.findOne(); final WorkingDays workingDays = this.workingDaysRepository.findOne();
@@ -448,7 +449,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
***/ ***/
PaymentDetail paymentDetail = null; PaymentDetail paymentDetail = null;
saveLoanRepayment(singleLoanRepaymentCommand.getLoanId(), paymentDetail, singleLoanRepaymentCommand.getTransactionAmount(), saveLoanRepayment(singleLoanRepaymentCommand.getLoanId(), paymentDetail, singleLoanRepaymentCommand.getTransactionAmount(),
bulkRepaymentCommand.getTransactionDate(), bulkRepaymentCommand.getNote()); bulkRepaymentCommand.getTransactionDate(), bulkRepaymentCommand.getNote(), null);
changes.put("bulkTransations", singleLoanRepaymentCommand); changes.put("bulkTransations", singleLoanRepaymentCommand);
} }
return changes; return changes;
@@ -469,6 +470,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount"); final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final String txnExternalId = command.stringValueOfParameterNamed("externalId");
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -481,7 +483,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount); final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createPaymentDetail(command, changes); PaymentDetail paymentDetail = paymentDetailWritePlatformService.createPaymentDetail(command, changes);
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, paymentDetail, transactionDate); LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, paymentDetail, transactionDate, txnExternalId);
if (transactionToAdjust.isInterestWaiver()) { if (transactionToAdjust.isInterestWaiver()) {
newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate); newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate);
} }