wip: repayment/disbursal apis support optional payment details
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
New table for storing transaction details (for both loan and savings)
|
||||
*/
|
||||
|
||||
CREATE TABLE `m_payment_detail` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`payment_type_enum` SMALLINT(5) NOT NULL,
|
||||
`account_number` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`check_number` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`receipt_number` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`bank_number` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`routing_code` VARCHAR(100) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
)
|
||||
COLLATE='utf8_general_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
/*
|
||||
Update loan transaction to add a link to transaction detail table
|
||||
*/
|
||||
|
||||
ALTER TABLE `m_loan_transaction`
|
||||
ADD COLUMN `payment_detail_id` BIGINT(20) NULL AFTER `loan_id`,
|
||||
ADD CONSTRAINT `FK_m_loan_transaction_m_payment_detail` FOREIGN KEY (`payment_detail_id`) REFERENCES `m_payment_detail` (`id`);
|
||||
|
||||
|
||||
|
||||
+6
-3
@@ -24,6 +24,8 @@ public class LoanTransactionData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final CurrencyData currency;
|
||||
@SuppressWarnings("unused")
|
||||
private final PaymentDetailData paymentDetailData;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amount;
|
||||
@@ -36,11 +38,12 @@ public class LoanTransactionData {
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal penaltyChargesPortion;
|
||||
|
||||
public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final CurrencyData currency,
|
||||
final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion) {
|
||||
public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData,
|
||||
final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion,
|
||||
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion) {
|
||||
this.id = id;
|
||||
this.type = transactionType;
|
||||
this.paymentDetailData = paymentDetailData;
|
||||
this.currency = currency;
|
||||
this.date = date;
|
||||
this.amount = amount;
|
||||
|
||||
+11
@@ -46,6 +46,17 @@ public class LoanTransactionEnumData {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the transaction involves either a payment (disbursement)
|
||||
* or a receipt (repayments, repayments during disbursement etc)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPaymentOrReceipt() {
|
||||
if (isDisbursement() || isRepayment() || isRepaymentAtDisbursement() || isRecoveryRepayment()) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDisbursement() {
|
||||
return this.disbursement;
|
||||
}
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.data;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a payment.
|
||||
*/
|
||||
public class PaymentDetailData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData paymentType;
|
||||
@SuppressWarnings("unused")
|
||||
private final String accountNumber;
|
||||
@SuppressWarnings("unused")
|
||||
private final String checkNumber;
|
||||
@SuppressWarnings("unused")
|
||||
private final String routingCode;
|
||||
@SuppressWarnings("unused")
|
||||
private final String receiptNumber;
|
||||
@SuppressWarnings("unused")
|
||||
private final String bankNumber;
|
||||
|
||||
public PaymentDetailData(Long id, EnumOptionData paymentType, String accountNumber, String checkNumber, String routingCode,
|
||||
String receiptNumber, String bankNumber) {
|
||||
this.id = id;
|
||||
this.paymentType = paymentType;
|
||||
this.accountNumber = accountNumber;
|
||||
this.checkNumber = checkNumber;
|
||||
this.routingCode = routingCode;
|
||||
this.receiptNumber = receiptNumber;
|
||||
this.bankNumber = bankNumber;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-10
@@ -810,7 +810,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
final String clientIdParamName = "clientId";
|
||||
//FIXME AA : Client is null for group loans. Group loan modifications require group validation.
|
||||
// FIXME AA : Client is null for group loans. Group loan modifications
|
||||
// require group validation.
|
||||
if (this.client != null) {
|
||||
if (command.isChangeInLongParameterNamed(clientIdParamName, this.client.getId())) {
|
||||
final Long newValue = command.longValueOfParameterNamed(clientIdParamName);
|
||||
@@ -1227,11 +1228,12 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.actualDisbursementDate = expectedDisbursedOnLocalDate.toDate();
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
/****
|
||||
* Vishwas TODO: Refactor to skip unnecessary creation of Disbursement
|
||||
* Vishwas TODO: Re-factor to skip unnecessary creation of Disbursement
|
||||
* and fees applied transactions (though they are not persisted) on
|
||||
* modifications to loan application modification
|
||||
*****/
|
||||
handleDisbursementTransaction(expectedDisbursedOnLocalDate);
|
||||
PaymentDetail paymentDetail = null;
|
||||
handleDisbursementTransaction(paymentDetail, expectedDisbursedOnLocalDate);
|
||||
}
|
||||
|
||||
private Collection<Long> findExistingTransactionIds() {
|
||||
@@ -1259,9 +1261,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command, final ApplicationCurrency currency,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final Map<String, Object> actualChanges, final PaymentDetail paymentDetail) {
|
||||
|
||||
updateLoanToPreDisbursalState();
|
||||
|
||||
@@ -1284,7 +1285,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("actualDisbursementDate", command.stringValueOfParameterNamed("actualDisbursementDate"));
|
||||
|
||||
handleDisbursementTransaction(actualDisbursementDate);
|
||||
handleDisbursementTransaction(paymentDetail, actualDisbursementDate);
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
|
||||
regenerateRepaymentSchedule(currency);
|
||||
@@ -1349,19 +1350,24 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
updateLoanSchedule(generatedData);
|
||||
}
|
||||
|
||||
private LoanTransaction handleDisbursementTransaction(final LocalDate disbursedOn) {
|
||||
private LoanTransaction handleDisbursementTransaction(final PaymentDetail paymentDetail, final LocalDate disbursedOn) {
|
||||
// track disbursement transaction
|
||||
final LoanTransaction disbursementTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(),
|
||||
disbursedOn);
|
||||
paymentDetail, disbursedOn);
|
||||
disbursementTransaction.updateLoan(this);
|
||||
this.loanTransactions.add(disbursementTransaction);
|
||||
|
||||
// add repayment transaction to track incoming money from client to mfi
|
||||
// for (charges due at time of disbursement)
|
||||
|
||||
/***
|
||||
* TODO Vishwas: do we need to be able to pass in payment type details
|
||||
* for repayments at disbursements too?
|
||||
***/
|
||||
final Money totalFeeChargesDueAtDisbursement = this.summary.getTotalFeeChargesDueAtDisbursement(loanCurrency());
|
||||
if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()) {
|
||||
|
||||
LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(totalFeeChargesDueAtDisbursement, disbursedOn);
|
||||
LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(totalFeeChargesDueAtDisbursement, null, disbursedOn);
|
||||
Money zero = Money.zero(getCurrency());
|
||||
chargesPayment.updateComponents(zero, zero, totalFeeChargesDueAtDisbursement, zero);
|
||||
chargesPayment.updateLoan(this);
|
||||
|
||||
+25
-7
@@ -24,6 +24,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@@ -39,6 +40,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "payment_detail_id", nullable = true)
|
||||
private PaymentDetail paymentDetail;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private final Integer typeOf;
|
||||
|
||||
@@ -70,16 +75,16 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
this.typeOf = null;
|
||||
}
|
||||
|
||||
public static LoanTransaction disbursement(final Money amount, final LocalDate disbursementDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.DISBURSEMENT, amount.getAmount(), disbursementDate);
|
||||
public static LoanTransaction disbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate disbursementDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate);
|
||||
}
|
||||
|
||||
public static LoanTransaction repayment(final Money amount, final LocalDate paymentDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.REPAYMENT, amount.getAmount(), paymentDate);
|
||||
public static LoanTransaction repayment(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate);
|
||||
}
|
||||
|
||||
public static LoanTransaction repaymentAtDisbursement(final Money amount, final LocalDate paymentDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, amount.getAmount(), paymentDate);
|
||||
public static LoanTransaction repaymentAtDisbursement(final Money amount, final PaymentDetail paymentDetail, final LocalDate paymentDate) {
|
||||
return new LoanTransaction(null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(), paymentDate);
|
||||
}
|
||||
|
||||
public static LoanTransaction waiver(final Loan loan, final Money waived, final LocalDate waiveDate) {
|
||||
@@ -146,6 +151,15 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
this.dateOf = date.toDateMidnight().toDate();
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final LoanTransactionType type, final PaymentDetail paymentDetail, final BigDecimal amount,
|
||||
final LocalDate date) {
|
||||
this.loan = loan;
|
||||
this.typeOf = type.getValue();
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.amount = amount;
|
||||
this.dateOf = date.toDateMidnight().toDate();
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
this.reversed = true;
|
||||
}
|
||||
@@ -315,7 +329,11 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
public LoanTransactionData toData(final CurrencyData currencyData) {
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf);
|
||||
return new LoanTransactionData(this.getId(), transactionType, currencyData, getTransactionDate(), this.amount,
|
||||
PaymentDetailData paymentDetailData = null;
|
||||
if (this.paymentDetail != null) {
|
||||
paymentDetailData = paymentDetail.toData();
|
||||
}
|
||||
return new LoanTransactionData(this.getId(), transactionType, paymentDetailData, currencyData, getTransactionDate(), this.amount,
|
||||
this.principalPortion, this.interestPortion, this.feeChargesPortion, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
|
||||
Executable
+128
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_payment_detail")
|
||||
public final class PaymentDetail extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "payment_type_enum", nullable = false)
|
||||
private Integer paymentType;
|
||||
|
||||
@Column(name = "account_number", length = 50)
|
||||
private String accountNumber;
|
||||
|
||||
@Column(name = "check_number", length = 50)
|
||||
private String checkNumber;
|
||||
|
||||
@Column(name = "routing_code", length = 50)
|
||||
private String routingCode;
|
||||
|
||||
@Column(name = "receipt_number", length = 50)
|
||||
private String receiptNumber;
|
||||
|
||||
@Column(name = "bank_number", length = 50)
|
||||
private String bankNumber;
|
||||
|
||||
protected PaymentDetail() {
|
||||
|
||||
}
|
||||
|
||||
public static PaymentDetail generatePaymentDetail(final JsonCommand command, final Map<String, Object> changes) {
|
||||
// create a payment detail
|
||||
final Integer paymentTypeId = command.integerValueSansLocaleOfParameterNamed("paymentTypeId");
|
||||
|
||||
if (paymentTypeId == null) { return null; }
|
||||
|
||||
changes.put("paymentTypeId", paymentTypeId);
|
||||
|
||||
final String accountNumber = command.stringValueOfParameterNamed("accountNumber");
|
||||
final String checkNumber = command.stringValueOfParameterNamed("checkNumber");
|
||||
final String routingCode = command.stringValueOfParameterNamed("routingCode");
|
||||
final String receiptNumber = command.stringValueOfParameterNamed("receiptNumber");
|
||||
final String bankNumber = command.stringValueOfParameterNamed("bankNumber");
|
||||
final PaymentType paymentType = PaymentType.fromInt(paymentTypeId);
|
||||
|
||||
PaymentDetail paymentDetail = null;
|
||||
if (paymentType.isCheckPayment()) {
|
||||
paymentDetail = PaymentDetail.checkPaymentDetail(accountNumber, checkNumber, routingCode);
|
||||
if (StringUtils.isNotBlank(accountNumber)) {
|
||||
changes.put("accountNumber", accountNumber);
|
||||
}
|
||||
if (StringUtils.isNotBlank(checkNumber)) {
|
||||
changes.put("checkNumber", checkNumber);
|
||||
}
|
||||
if (StringUtils.isNotBlank(routingCode)) {
|
||||
changes.put("routingCode", routingCode);
|
||||
}
|
||||
} else if (paymentType.isEFTPayment()) {
|
||||
paymentDetail = PaymentDetail.eftPaymentDetail(accountNumber, routingCode);
|
||||
if (StringUtils.isNotBlank(accountNumber)) {
|
||||
changes.put("accountNumber", accountNumber);
|
||||
}
|
||||
if (StringUtils.isNotBlank(routingCode)) {
|
||||
changes.put("routingCode", routingCode);
|
||||
}
|
||||
} else if (paymentType.isReceiptPayment()) {
|
||||
paymentDetail = PaymentDetail.receiptPaymentDetail(receiptNumber, bankNumber);
|
||||
if (StringUtils.isNotBlank(receiptNumber)) {
|
||||
changes.put("receiptNumber", receiptNumber);
|
||||
}
|
||||
if (StringUtils.isNotBlank(bankNumber)) {
|
||||
changes.put("bankNumber", bankNumber);
|
||||
}
|
||||
} else {
|
||||
paymentDetail = PaymentDetail.cashPaymentDetail();
|
||||
}
|
||||
return paymentDetail;
|
||||
}
|
||||
|
||||
public static PaymentDetail cashPaymentDetail() {
|
||||
return new PaymentDetail(PaymentType.CASH, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public static PaymentDetail checkPaymentDetail(final String accountNumber, final String checkNumber, final String routingCode) {
|
||||
return new PaymentDetail(PaymentType.CHECK, accountNumber, checkNumber, routingCode, null, null);
|
||||
}
|
||||
|
||||
public static PaymentDetail receiptPaymentDetail(final String receiptNumber, final String bankNumber) {
|
||||
return new PaymentDetail(PaymentType.RECEIPT, null, null, null, receiptNumber, bankNumber);
|
||||
}
|
||||
|
||||
public static PaymentDetail eftPaymentDetail(final String accountNumber, final String routingCode) {
|
||||
return new PaymentDetail(PaymentType.ELECTRONIC_FUND_TRANSFER, accountNumber, null, routingCode, null, null);
|
||||
}
|
||||
|
||||
private PaymentDetail(final PaymentType paymentType, final String accountNumber, final String checkNumber, final String routingCode,
|
||||
final String receiptNumber, final String bankNumber) {
|
||||
this.paymentType = paymentType.getValue();
|
||||
this.accountNumber = accountNumber;
|
||||
this.checkNumber = checkNumber;
|
||||
this.routingCode = routingCode;
|
||||
this.receiptNumber = receiptNumber;
|
||||
this.bankNumber = bankNumber;
|
||||
}
|
||||
|
||||
public PaymentDetailData toData() {
|
||||
final EnumOptionData paymentTypeData = LoanEnumerations.paymentType(this.paymentType);
|
||||
final PaymentDetailData paymentDetailData = new PaymentDetailData(getId(), paymentTypeData, this.accountNumber, this.checkNumber,
|
||||
this.routingCode, this.receiptNumber, this.bankNumber);
|
||||
return paymentDetailData;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface PaymentDetailRepository extends JpaRepository<PaymentDetail, Long>, JpaSpecificationExecutor<Loan> {
|
||||
// no added behaviour
|
||||
}
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PaymentType {
|
||||
|
||||
CASH(1, "paymentType.cash"), CHECK(2, "paymentType.check"), RECEIPT(3, "paymentType.receipt"), //
|
||||
ELECTRONIC_FUND_TRANSFER(4, "paymentType.eft");// Electronic Funds Transfer
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private PaymentType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
private static final Map<Integer, PaymentType> intToEnumMap = new HashMap<Integer, PaymentType>();
|
||||
private static int minValue;
|
||||
private static int maxValue;
|
||||
static {
|
||||
int i = 0;
|
||||
for (final PaymentType type : PaymentType.values()) {
|
||||
if (i == 0) {
|
||||
minValue = type.value;
|
||||
}
|
||||
intToEnumMap.put(type.value, type);
|
||||
if (minValue >= type.value) {
|
||||
minValue = type.value;
|
||||
}
|
||||
if (maxValue < type.value) {
|
||||
maxValue = type.value;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static PaymentType fromInt(final int i) {
|
||||
final PaymentType type = intToEnumMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
|
||||
public static int getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public static int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public boolean isCashPayment() {
|
||||
return this.value.equals(PaymentType.CASH.value);
|
||||
}
|
||||
|
||||
public boolean isCheckPayment() {
|
||||
return this.value.equals(PaymentType.CHECK.value);
|
||||
}
|
||||
|
||||
public boolean isReceiptPayment() {
|
||||
return this.value.equals(PaymentType.RECEIPT.value);
|
||||
}
|
||||
|
||||
public boolean isEFTPayment() {
|
||||
return this.value.equals(PaymentType.ELECTRONIC_FUND_TRANSFER.value);
|
||||
}
|
||||
|
||||
}
|
||||
+26
-4
@@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -47,7 +48,7 @@ public final class LoanEventApiJsonValidator {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "note", "locale",
|
||||
"dateFormat"));
|
||||
"dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
@@ -62,6 +63,8 @@ public final class LoanEventApiJsonValidator {
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
validatePaymentDetails(baseDataValidator, element);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -69,11 +72,11 @@ public final class LoanEventApiJsonValidator {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "note",
|
||||
"locale", "dateFormat"));
|
||||
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "note",
|
||||
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||
@@ -88,9 +91,28 @@ public final class LoanEventApiJsonValidator {
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
validatePaymentDetails(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param baseDataValidator
|
||||
* @param element
|
||||
*/
|
||||
private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
// Validate all string payment detail fields for max length
|
||||
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element);
|
||||
baseDataValidator.reset().parameter("paymentTypeId").value(paymentTypeId)
|
||||
.inMinMaxRange(PaymentType.getMinValue(), PaymentType.getMaxValue());
|
||||
final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList("accountNumber", "checkNumber", "routingCode",
|
||||
"receiptNumber", "bankNumber"));
|
||||
for (String paymentDetailParameterName : paymentDetailParameters) {
|
||||
final String paymentDetailParameterValue = fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element);
|
||||
baseDataValidator.reset().parameter(paymentDetailParameterName).value(paymentDetailParameterValue).ignoreIfNull()
|
||||
.notExceedingLengthOf(50);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateTransactionWithNoAmount(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
|
||||
+46
-26
@@ -35,6 +35,7 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanSummaryData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
@@ -126,6 +127,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
// retrieve all loan transactions that are not invalid and have not
|
||||
// been 'contra'ed by another transaction
|
||||
// repayments at time of disbursement (e.g. charges)
|
||||
|
||||
/*** TODO Vishwas: Remove references to "Contra" from the codebase ***/
|
||||
String sql = "select "
|
||||
+ rm.LoanPaymentsSchema()
|
||||
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.is_reversed=0 order by tr.transaction_date ASC";
|
||||
@@ -158,7 +161,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
final GroupData groupAccount = this.groupReadPlatformService.retrieveGroupDetails(groupId , false);
|
||||
final GroupData groupAccount = this.groupReadPlatformService.retrieveGroupDetails(groupId, false);
|
||||
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
|
||||
LoanAccountData loanDetails = LoanAccountData.groupDefaults(groupAccount, expectedDisbursementDate);
|
||||
|
||||
@@ -169,10 +172,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
return loanDetails;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LoanAccountData retrieveTemplateWithCompleteGroupAndProductDetails(Long groupId, Long productId){
|
||||
|
||||
public LoanAccountData retrieveTemplateWithCompleteGroupAndProductDetails(Long groupId, Long productId) {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
final GroupData groupAccount = this.groupReadPlatformService.retrieveGroup(groupId);
|
||||
@@ -186,8 +189,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
return loanDetails;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId) {
|
||||
|
||||
@@ -209,7 +211,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount();
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
||||
return new LoanTransactionData(null, transactionType, currencyData, earliestUnpaidInstallmentDate,
|
||||
return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
||||
possibleNextRepaymentAmount.getAmount(), null, null, null, null);
|
||||
}
|
||||
|
||||
@@ -237,8 +239,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final MonetaryCurrency monetaryCurrency = new MonetaryCurrency(currency.getCode(), currency.getDecimalPlaces());
|
||||
final BigDecimal amount = waiveOfInterest.getAmount(monetaryCurrency).getAmount();
|
||||
return new LoanTransactionData(null, transactionType, currencyData, waiveOfInterest.getTransactionDate(), amount, null, null, null,
|
||||
null);
|
||||
return new LoanTransactionData(null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount, null, null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,7 +249,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
context.authenticatedUser();
|
||||
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF);
|
||||
return new LoanTransactionData(null, transactionType, null, DateUtils.getLocalDateOfTenant(), null, null, null, null, null);
|
||||
return new LoanTransactionData(null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -516,19 +518,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
GroupData groupData = null;
|
||||
|
||||
if(groupId != null){
|
||||
|
||||
|
||||
if (groupId != null) {
|
||||
|
||||
groupData = new GroupData(groupId, groupName, groupExternalId, groupOfficeId, groupStaffId, groupParentId, groupHierarchy);
|
||||
}
|
||||
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
|
||||
loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId,
|
||||
loanPurposeName, loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency,
|
||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId,
|
||||
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, loanSummary,
|
||||
feeChargesDueAtDisbursementCharged);
|
||||
loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
|
||||
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId, amortizationType,
|
||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
||||
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,12 +690,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
public String LoanPaymentsSchema() {
|
||||
|
||||
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, "
|
||||
+ "tr.principal_portion_derived as principal, " + "tr.interest_portion_derived as interest, "
|
||||
+ "tr.fee_charges_portion_derived as fees, " + "tr.penalty_charges_portion_derived as penalties, "
|
||||
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
|
||||
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
|
||||
+ " pd.payment_type_enum as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, "
|
||||
+ " 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, "
|
||||
+ " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode "
|
||||
+ " 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 ";
|
||||
+ " 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 "
|
||||
+ " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -711,6 +715,22 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final Long id = rs.getLong("id");
|
||||
final int transactionTypeInt = JdbcSupport.getInteger(rs, "transactionType");
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(transactionTypeInt);
|
||||
|
||||
PaymentDetailData paymentDetailData = null;
|
||||
|
||||
if (transactionType.isPaymentOrReceipt()) {
|
||||
final Integer paymentTypeId = JdbcSupport.getInteger(rs, "paymentType");
|
||||
if (paymentTypeId != null) {
|
||||
EnumOptionData paymentType = LoanEnumerations.paymentType(paymentTypeId);
|
||||
final String accountNumber = rs.getString("accountNumber");
|
||||
final String checkNumber = rs.getString("checkNumber");
|
||||
final String routingCode = rs.getString("routingCode");
|
||||
final String receiptNumber = rs.getString("receiptNumber");
|
||||
final String bankNumber = rs.getString("bankNumber");
|
||||
paymentDetailData = new PaymentDetailData(id, paymentType, accountNumber, checkNumber, routingCode, receiptNumber,
|
||||
bankNumber);
|
||||
}
|
||||
}
|
||||
final LocalDate date = JdbcSupport.getLocalDate(rs, "date");
|
||||
final BigDecimal totalAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "total");
|
||||
final BigDecimal principalPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principal");
|
||||
@@ -718,8 +738,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final BigDecimal feeChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "fees");
|
||||
final BigDecimal penaltyChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penalties");
|
||||
|
||||
return new LoanTransactionData(id, transactionType, currencyData, date, totalAmount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion);
|
||||
return new LoanTransactionData(id, transactionType, paymentDetailData, currencyData, date, totalAmount, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-18
@@ -49,6 +49,8 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetailRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
|
||||
@@ -79,6 +81,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final LoanSummaryWrapper loanSummaryWrapper;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
private final PaymentDetailRepository paymentDetailRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -88,7 +91,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final NoteRepository noteRepository, final ChargeRepositoryWrapper chargeRepository,
|
||||
final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepository applicationCurrencyRepository,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||
final PaymentDetailRepository paymentDetailRepository) {
|
||||
this.context = context;
|
||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||
this.loanAssembler = loanAssembler;
|
||||
@@ -102,6 +106,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer;
|
||||
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
this.paymentDetailRepository = paymentDetailRepository;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
@@ -123,8 +128,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = loan.disburse(currentUser, command, currency, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes);
|
||||
if (paymentDetail != null) {
|
||||
paymentDetailRepository.save(paymentDetail);
|
||||
}
|
||||
|
||||
loan.disburse(currentUser, command, currency, existingTransactionIds, existingReversedTransactionIds, changes, paymentDetail);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
@@ -153,6 +165,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
public Map<String, Object> bulkLoanDisbursal(JsonCommand command, CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) {
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
/****
|
||||
* TODO Vishwas: Pair with Ashok and re-factor collection sheet
|
||||
* code-base
|
||||
*****/
|
||||
|
||||
SingleDisbursalCommand[] disbursalCommand = bulkDisbursalCommand.getDisburseTransactions();
|
||||
Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
if (disbursalCommand == null) { return changes; }
|
||||
@@ -167,7 +184,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
changes.putAll(loan.disburse(currentUser, command, currency, existingTransactionIds, existingReversedTransactionIds));
|
||||
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes);
|
||||
if (paymentDetail != null) {
|
||||
paymentDetailRepository.save(paymentDetail);
|
||||
}
|
||||
|
||||
loan.disburse(currentUser, command, currency, existingTransactionIds, existingReversedTransactionIds, changes, paymentDetail);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
@@ -190,8 +212,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
context.authenticatedUser();
|
||||
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
final BigDecimal totalInterestCharged = loan.getSummary().getTotalInterestCharged();
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = loan.undoDisbursal(existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -207,11 +227,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
// add the previously calculated net charged interest back to
|
||||
// accountingBridgedate, this would not work if interest
|
||||
// recalculation in introduced
|
||||
accountingBridgeData.put("calculatedInterest", totalInterestCharged);
|
||||
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
}
|
||||
|
||||
@@ -248,8 +263,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("note", noteText);
|
||||
}
|
||||
|
||||
CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, transactionAmount, transactionDate,
|
||||
noteText);
|
||||
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes);
|
||||
if (paymentDetail != null) {
|
||||
paymentDetailRepository.save(paymentDetail);
|
||||
}
|
||||
CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount,
|
||||
transactionDate, noteText);
|
||||
|
||||
return commandProcessingResultBuilder.withCommandId(command.commandId()) //
|
||||
.withLoanId(loanId) //
|
||||
@@ -257,15 +276,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.build();
|
||||
}
|
||||
|
||||
private CommandProcessingResultBuilder saveLoanRepayment(final Long loanId, final BigDecimal transactionAmount,
|
||||
final LocalDate transactionDate, final String noteText) {
|
||||
private CommandProcessingResultBuilder saveLoanRepayment(final Long loanId, final PaymentDetail paymentDetail,
|
||||
final BigDecimal transactionAmount, final LocalDate transactionDate, final String noteText) {
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount);
|
||||
final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, transactionDate);
|
||||
final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, paymentDetail, transactionDate);
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
|
||||
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -310,7 +329,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (repaymentCommand == null) return changes;
|
||||
|
||||
for (SingleRepaymentCommand singleLoanRepaymentCommand : repaymentCommand) {
|
||||
saveLoanRepayment(singleLoanRepaymentCommand.getLoanId(), singleLoanRepaymentCommand.getTransactionAmount(),
|
||||
/****
|
||||
* TODO Vishwas, have a re-look at this implementation, defaulting
|
||||
* it to null for now
|
||||
***/
|
||||
PaymentDetail paymentDetail = null;
|
||||
saveLoanRepayment(singleLoanRepaymentCommand.getLoanId(), paymentDetail, singleLoanRepaymentCommand.getTransactionAmount(),
|
||||
bulkRepaymentCommand.getTransactionDate(), bulkRepaymentCommand.getNote());
|
||||
changes.put("bulkTransations", singleLoanRepaymentCommand);
|
||||
}
|
||||
@@ -343,7 +367,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
|
||||
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, transactionDate);
|
||||
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes);
|
||||
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, paymentDetail, transactionDate);
|
||||
if (transactionToAdjust.isInterestWaiver()) {
|
||||
newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate);
|
||||
}
|
||||
@@ -352,6 +377,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
|
||||
if (paymentDetail != null) {
|
||||
paymentDetailRepository.save(paymentDetail);
|
||||
}
|
||||
this.loanTransactionRepository.save(newTransactionDetail);
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -10,6 +10,7 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
@@ -197,6 +198,13 @@ public class LoanEnumerations {
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData paymentType(final Integer id) {
|
||||
PaymentType paymentType = PaymentType.fromInt(id);
|
||||
EnumOptionData enumOptionData = new EnumOptionData(paymentType.getValue().longValue(), paymentType.getCode(), paymentType
|
||||
.getValue().toString());
|
||||
return enumOptionData;
|
||||
}
|
||||
|
||||
public static LoanTransactionEnumData transactionType(final Integer id) {
|
||||
return transactionType(LoanTransactionType.fromInt(id));
|
||||
}
|
||||
|
||||
+29
-27
@@ -2,37 +2,39 @@ package org.mifosplatform.portfolio.loanaccount;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public class LoanTransactionBuilder {
|
||||
|
||||
private Money transactionAmount = new MoneyBuilder().build();
|
||||
private LocalDate transactionDate = LocalDate.now();
|
||||
private boolean repayment = false;
|
||||
@SuppressWarnings("unused")
|
||||
private Money transactionAmount = new MoneyBuilder().build();
|
||||
@SuppressWarnings("unused")
|
||||
private LocalDate transactionDate = LocalDate.now();
|
||||
@SuppressWarnings("unused")
|
||||
private boolean repayment = false;
|
||||
|
||||
public LoanTransaction build() {
|
||||
|
||||
LoanTransaction transaction = null;
|
||||
|
||||
if (repayment) {
|
||||
transaction = LoanTransaction.repayment(transactionAmount, transactionDate);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
/** public LoanTransaction build() {
|
||||
|
||||
public LoanTransactionBuilder with(final Money newAmount) {
|
||||
this.transactionAmount = newAmount;
|
||||
return this;
|
||||
}
|
||||
LoanTransaction transaction = null;
|
||||
|
||||
public LoanTransactionBuilder with(final LocalDate withTransactionDate) {
|
||||
this.transactionDate = withTransactionDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanTransactionBuilder repayment() {
|
||||
this.repayment = true;
|
||||
return this;
|
||||
}
|
||||
if (repayment) {
|
||||
transaction = LoanTransaction.repayment(transactionAmount, transactionDate);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}**/
|
||||
|
||||
public LoanTransactionBuilder with(final Money newAmount) {
|
||||
this.transactionAmount = newAmount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanTransactionBuilder with(final LocalDate withTransactionDate) {
|
||||
this.transactionDate = withTransactionDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanTransactionBuilder repayment() {
|
||||
this.repayment = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user