mifosx-172: wip - support adjust transaction for accounting.
This commit is contained in:
@@ -1087,10 +1087,6 @@ CREATE TABLE `m_loan_transaction` (
|
||||
`transaction_type_enum` smallint(5) NOT NULL,
|
||||
`transaction_date` date NOT NULL,
|
||||
`amount` decimal(19,6) NOT NULL,
|
||||
`createdby_id` bigint(20) DEFAULT NULL,
|
||||
`created_date` datetime DEFAULT NULL,
|
||||
`lastmodified_date` datetime DEFAULT NULL,
|
||||
`lastmodifiedby_id` bigint(20) DEFAULT NULL,
|
||||
`principal_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||
`interest_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||
`fee_charges_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||
@@ -1937,4 +1933,4 @@ UNLOCK TABLES;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2013-02-18 13:20:24
|
||||
-- Dump completed on 2013-02-19 0:44:13
|
||||
|
||||
@@ -8,4 +8,11 @@ UPDATE `m_loan_transaction` SET `is_reversed` = 1 WHERE contra_id is not null;
|
||||
ALTER TABLE `m_loan_transaction` DROP FOREIGN KEY `FKCFCEA426FC69F3F1`;
|
||||
ALTER TABLE `m_loan_transaction`
|
||||
DROP COLUMN `contra_id` ,
|
||||
DROP INDEX `FKCFCEA426FC69F3F1`;
|
||||
DROP INDEX `FKCFCEA426FC69F3F1`;
|
||||
|
||||
|
||||
ALTER TABLE `m_loan_transaction`
|
||||
DROP COLUMN `lastmodifiedby_id`,
|
||||
DROP COLUMN `lastmodified_date`,
|
||||
DROP COLUMN `created_date`,
|
||||
DROP COLUMN `createdby_id`;
|
||||
+46
-47
@@ -165,11 +165,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "expected_disbursedon_date")
|
||||
private Date expectedDisbursedOnDate;
|
||||
private Date expectedDisbursementDate;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "disbursedon_date")
|
||||
private Date disbursedOnDate;
|
||||
private Date actualDisbursementDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne(optional = true)
|
||||
@@ -199,7 +199,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "maturedon_date")
|
||||
private Date maturedOnDate;
|
||||
private Date actualMaturityDate;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "expected_firstrepaymenton_date")
|
||||
@@ -387,12 +387,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
|
||||
if (!loanCharge.isDueAtDisbursement()) { // TODO - only need to
|
||||
// reprocess transactions
|
||||
// against loan schedule if
|
||||
// loan charge is added with
|
||||
// due date before latest
|
||||
// transaction.
|
||||
// TODO - only need to reprocess transactions against loan schedule
|
||||
// if loan charge is added with due date before latest transaction.
|
||||
if (!loanCharge.isDueAtDisbursement()) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), this.repaymentScheduleInstallments, getNullPointerSafeLoanCharges());
|
||||
@@ -640,6 +637,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
public void updateLoanScheduleDependentDerivedFields() {
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
this.actualMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
}
|
||||
|
||||
public Map<String, Object> loanApplicationModification(final JsonCommand command, final Set<LoanCharge> possiblyModifedLoanCharges,
|
||||
@@ -737,7 +735,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
actualChanges.put("recalculateLoanSchedule", true);
|
||||
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(expectedDisbursementDateParamName);
|
||||
this.expectedDisbursedOnDate = newValue.toDate();
|
||||
this.expectedDisbursementDate = newValue.toDate();
|
||||
removeFirstDisbursementTransaction();
|
||||
disburse(getExpectedDisbursedOnLocalDate());
|
||||
}
|
||||
@@ -894,7 +892,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
// Have to set expectedDisbursementDate to avoid nullPointer so should
|
||||
// be passed down to updateLoanSchedule method
|
||||
if (loanSchedule.getDisbursementDate() != null) {
|
||||
this.expectedDisbursedOnDate = loanSchedule.getDisbursementDate().toDate();
|
||||
this.expectedDisbursementDate = loanSchedule.getDisbursementDate().toDate();
|
||||
}
|
||||
|
||||
updateLoanSchedule(loanScheduleData);
|
||||
@@ -914,7 +912,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
this.submittedOnDate = submittedOn.toDate();
|
||||
this.submittedBy = currentUser;
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
if (loanSchedule.getRepaymentStartFromDate() != null) {
|
||||
this.expectedFirstRepaymentOnDate = loanSchedule.getRepaymentStartFromDate().toDate();
|
||||
@@ -1101,8 +1099,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
private void disburse(final LocalDate expectedDisbursedOnLocalDate) {
|
||||
this.disbursedOnDate = expectedDisbursedOnLocalDate.toDate();
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
this.actualDisbursementDate = expectedDisbursedOnLocalDate.toDate();
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
handleDisbursementTransaction(expectedDisbursedOnLocalDate);
|
||||
}
|
||||
|
||||
@@ -1147,26 +1145,19 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
|
||||
LocalDate disbursedOn = command.localDateValueOfParameterNamed("disbursedOnDate");
|
||||
if (disbursedOn == null) {
|
||||
disbursedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
this.disbursedOnDate = disbursedOn.toDate();
|
||||
this.actualDisbursementDate = actualDisbursementDate.toDate();
|
||||
this.disbursedBy = currentUser;
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("disbursedOnDate", disbursedOn.toString(fmt));
|
||||
actualChanges.put("expectedMaturityDate", LocalDate.fromDateFields(this.expectedDisbursedOnDate).toString(fmt));
|
||||
actualChanges.put("actualDisbursementDate", command.stringValueOfParameterNamed("actualDisbursementDate"));
|
||||
|
||||
handleDisbursementTransaction(disbursedOn);
|
||||
handleDisbursementTransaction(actualDisbursementDate);
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
|
||||
regenerateRepaymentSchedule(currency);
|
||||
}
|
||||
}
|
||||
@@ -1267,9 +1258,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
|
||||
this.disbursedOnDate = null;
|
||||
this.actualDisbursementDate = null;
|
||||
this.disbursedBy = null;
|
||||
actualChanges.put("disbursedOnDate", "");
|
||||
actualChanges.put("actualDisbursementDate", "");
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
@@ -1290,7 +1281,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
private void updateLoanToPreDisbursalState() {
|
||||
this.disbursedOnDate = null;
|
||||
this.actualDisbursementDate = null;
|
||||
|
||||
for (LoanCharge charge : getNullPointerSafeLoanCharges()) {
|
||||
charge.resetToOriginal(loanCurrency());
|
||||
@@ -1318,11 +1309,15 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public LoanTransaction makeRepayment(final LocalDate transactionDate, final BigDecimal transactionAmount,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Money repayment = Money.of(loanCurrency(), transactionAmount);
|
||||
final LoanTransaction loanTransaction = LoanTransaction.repayment(repayment, transactionDate);
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
handleRepaymentOrWaiverTransaction(loanTransaction, loanLifecycleStateMachine, null);
|
||||
|
||||
return loanTransaction;
|
||||
@@ -1418,7 +1413,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.closedOnDate = transactionDate.toDate();
|
||||
this.maturedOnDate = transactionDate.toDate();
|
||||
this.actualMaturityDate = transactionDate.toDate();
|
||||
}
|
||||
|
||||
private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
@@ -1427,7 +1422,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.closedOnDate = null;
|
||||
this.maturedOnDate = null;
|
||||
this.actualMaturityDate = null;
|
||||
}
|
||||
|
||||
private boolean isChronologicallyLatestRepaymentOrWaiver(final LoanTransaction loanTransaction,
|
||||
@@ -1530,7 +1525,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public LoanTransaction adjustExistingTransaction(final LocalDate transactionDate, final BigDecimal transactionAmountValue,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment) {
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money transactionAmount = Money.of(loanCurrency(), transactionAmountValue);
|
||||
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmount, transactionDate);
|
||||
@@ -1914,8 +1913,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
public LocalDate getDisbursedOnDate() {
|
||||
LocalDate date = null;
|
||||
if (this.disbursedOnDate != null) {
|
||||
date = new LocalDate(this.disbursedOnDate);
|
||||
if (this.actualDisbursementDate != null) {
|
||||
date = new LocalDate(this.actualDisbursementDate);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
@@ -1937,13 +1936,13 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public Date getExpectedDisbursedOnDate() {
|
||||
return this.expectedDisbursedOnDate;
|
||||
return this.expectedDisbursementDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedDisbursedOnLocalDate() {
|
||||
LocalDate expectedDisbursementDate = null;
|
||||
if (this.expectedDisbursedOnDate != null) {
|
||||
expectedDisbursementDate = new LocalDate(this.expectedDisbursedOnDate);
|
||||
if (this.expectedDisbursementDate != null) {
|
||||
expectedDisbursementDate = new LocalDate(this.expectedDisbursementDate);
|
||||
}
|
||||
return expectedDisbursementDate;
|
||||
}
|
||||
@@ -1958,8 +1957,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
public LocalDate getDisbursementDate() {
|
||||
LocalDate disbursementDate = getExpectedDisbursedOnLocalDate();
|
||||
if (this.disbursedOnDate != null) {
|
||||
disbursementDate = new LocalDate(this.disbursedOnDate);
|
||||
if (this.actualDisbursementDate != null) {
|
||||
disbursementDate = new LocalDate(this.actualDisbursementDate);
|
||||
}
|
||||
return disbursementDate;
|
||||
}
|
||||
@@ -1974,8 +1973,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
public LocalDate getActualMaturityDate() {
|
||||
LocalDate possibleMaturityDate = null;
|
||||
if (this.maturedOnDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.maturedOnDate);
|
||||
if (this.actualMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.actualMaturityDate);
|
||||
}
|
||||
return possibleMaturityDate;
|
||||
}
|
||||
@@ -1986,8 +1985,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (this.expectedMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.expectedMaturityDate);
|
||||
}
|
||||
if (this.maturedOnDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.maturedOnDate);
|
||||
if (this.actualMaturityDate != null) {
|
||||
possibleMaturityDate = new LocalDate(this.actualMaturityDate);
|
||||
}
|
||||
return possibleMaturityDate;
|
||||
}
|
||||
@@ -2006,7 +2005,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) {
|
||||
return !new LocalDate(this.expectedDisbursedOnDate).isEqual(actualDisbursedOnDate);
|
||||
return !new LocalDate(this.expectedDisbursementDate).isEqual(actualDisbursedOnDate);
|
||||
}
|
||||
|
||||
public boolean isRepaymentScheduleRegenerationRequiredForDisbursement(final LocalDate actualDisbursementDate) {
|
||||
@@ -2090,7 +2089,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
if (isDisbursed()) {
|
||||
statusSinceDate = new LocalDate(this.disbursedOnDate);
|
||||
statusSinceDate = new LocalDate(this.actualDisbursementDate);
|
||||
}
|
||||
|
||||
if (isClosed()) {
|
||||
|
||||
+13
-14
@@ -19,14 +19,13 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
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.loanproduct.service.LoanEnumerations;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
/**
|
||||
* All monetary transactions against a loan are modelled through this entity.
|
||||
@@ -34,12 +33,19 @@ import org.mifosplatform.useradministration.domain.AppUser;
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction")
|
||||
public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private final Integer typeOf;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
private final Date dateOf;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@@ -55,13 +61,6 @@ public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long
|
||||
@Column(name = "penalty_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPortion = BigDecimal.ZERO;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
private final Date dateOf;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private final Integer typeOf;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
@@ -152,7 +151,7 @@ public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalPortion);
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getPrincipalPortion() {
|
||||
return this.principalPortion;
|
||||
}
|
||||
@@ -160,7 +159,7 @@ public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long
|
||||
public Money getInterestPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPortion);
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getInterestPortion() {
|
||||
return this.interestPortion;
|
||||
}
|
||||
@@ -168,11 +167,11 @@ public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long
|
||||
public Money getFeeChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPortion);
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getFeePortion() {
|
||||
return this.feeChargesPortion;
|
||||
}
|
||||
|
||||
|
||||
public Money getPenaltyChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.serialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
public final class LoanEventApiJsonValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public LoanEventApiJsonValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateDisbursement(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "note", "locale",
|
||||
"dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.disbursement");
|
||||
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
final LocalDate actualDisbursementDate = fromApiJsonHelper.extractLocalDateNamed("actualDisbursementDate", element);
|
||||
baseDataValidator.reset().parameter("actualDisbursementDate").value(actualDisbursementDate).notNull();
|
||||
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||
"Validation errors exist.", dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
+29
-38
@@ -34,7 +34,6 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||
import org.mifosplatform.portfolio.client.domain.Note;
|
||||
import org.mifosplatform.portfolio.client.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanTransactionCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
||||
@@ -51,7 +50,7 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentEx
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanChargeCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanTransactionCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||
@@ -64,7 +63,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
|
||||
private final LoanEventApiJsonValidator loanEventApiJsonValidator;
|
||||
private final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer;
|
||||
private final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer;
|
||||
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
|
||||
@@ -79,7 +78,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
@Autowired
|
||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
|
||||
final LoanEventApiJsonValidator loanEventApiJsonValidator,
|
||||
final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer,
|
||||
final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer,
|
||||
final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer, final LoanAssembler loanAssembler,
|
||||
@@ -88,7 +87,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrencyRepository applicationCurrencyRepository,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.context = context;
|
||||
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
|
||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||
this.loanTransactionCommandFromApiJsonDeserializer = loanTransactionCommandFromApiJsonDeserializer;
|
||||
this.loanChargeCommandFromApiJsonDeserializer = loanChargeCommandFromApiJsonDeserializer;
|
||||
this.loanAssembler = loanAssembler;
|
||||
@@ -117,18 +116,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
final LoanStateTransitionCommand disburseLoan = this.loanStateTransitionCommandFromApiJsonDeserializer.commandFromApiJson(command
|
||||
.json());
|
||||
disburseLoan.validate();
|
||||
this.loanEventApiJsonValidator.validateDisbursement(command.json());
|
||||
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
final LocalDate actualDisbursementDate = disburseLoan.getDisbursedOnDate();
|
||||
if (this.isBeforeToday(actualDisbursementDate) && currentUser.canNotDisburseLoanInPast()) { throw new NoAuthorizationException(
|
||||
"User has no authority to disburse loan with a date in the past."); }
|
||||
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
@@ -137,6 +129,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
@@ -171,7 +164,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Map<String, Object> changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -218,7 +211,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (this.isBeforeToday(transactionDate) && currentUser.canNotMakeRepaymentOnLoanInPast()) { throw new NoAuthorizationException(
|
||||
"error.msg.no.permission.to.make.repayment.on.loan.in.past"); }
|
||||
|
||||
final LoanTransaction loanRepayment = loan.makeRepayment(transactionDate, transactionAmount, defaultLoanLifecycleStateMachine());
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final LoanTransaction loanRepayment = loan.makeRepayment(transactionDate, transactionAmount, defaultLoanLifecycleStateMachine(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
this.loanTransactionRepository.save(loanRepayment);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
@@ -232,11 +229,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("locale", command.locale());
|
||||
changes.put("dateFormat", command.dateFormat());
|
||||
|
||||
// make a call to accounting
|
||||
if (loan.isAccountingEnabledOnLoanProduct()) {
|
||||
LoanDTO loanDTO = populateLoanData(loan, loanRepayment);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(loanDTO);
|
||||
}
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -271,15 +267,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
|
||||
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
|
||||
|
||||
boolean transactionIsRepayment = transactionToAdjust.isRepayment();
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount,
|
||||
defaultLoanLifecycleStateMachine(), transactionToAdjust);
|
||||
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
|
||||
this.loanTransactionRepository.saveAndFlush(newTransactionDetail);
|
||||
this.loanTransactionRepository.save(newTransactionDetail);
|
||||
}
|
||||
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -291,17 +289,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("locale", command.locale());
|
||||
changes.put("dateFormat", command.dateFormat());
|
||||
|
||||
// make a call to accounting only if transaction being adjusted is a
|
||||
// repayment (not waiver)
|
||||
if (loan.isAccountingEnabledOnLoanProduct() && transactionIsRepayment) {
|
||||
List<LoanTransaction> newLoanTransactions = new ArrayList<LoanTransaction>();
|
||||
if (newTransactionDetail.getId() != null) {
|
||||
newLoanTransactions.add(newTransactionDetail);
|
||||
}
|
||||
newLoanTransactions.add(transactionToAdjust);
|
||||
LoanDTO loanDTO = populateLoanDTO(loan, newLoanTransactions);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(loanDTO);
|
||||
}
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -655,7 +646,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
loan.reassignLoanOfficer(toLoanOfficer, dateOfLoanOfficerAssignment);
|
||||
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -717,7 +708,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
loan.removeLoanOfficer(dateOfLoanOfficerunAssigned);
|
||||
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
|
||||
Reference in New Issue
Block a user