Loan transaction reversal data extension
This commit is contained in:
committed by
Arnold Gálovics
parent
163b9b1b8a
commit
80401586e6
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.service;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public final class CommandParameterUtil {
|
||||
|
||||
private CommandParameterUtil() {}
|
||||
|
||||
public static boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -142,4 +142,8 @@ public interface LoanApiConstants {
|
||||
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||
|
||||
String LOAN_ASSOCIATIONS_ALL = "all";
|
||||
|
||||
// Reversal Transation Data
|
||||
String REVERSAL_EXTERNAL_ID_PARAMNAME = "reversalExternalId";
|
||||
String REVERSED_ON_DATE_PARAMNAME = "reversedOnDate";
|
||||
}
|
||||
|
||||
+52
-85
@@ -44,7 +44,7 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.fineract.accounting.journalentry.api.DateParam;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
@@ -54,6 +54,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.service.CommandParameterUtil;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
@@ -63,18 +64,18 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPla
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/loans/{loanId}/transactions")
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@Scope("singleton")
|
||||
@Tag(name = "Loan Transactions", description = "Capabilities include loan repayment's, interest waivers and the ability to 'adjust' an existing transaction. An 'adjustment' of a transaction is really a 'reversal' of existing transaction followed by creation of a new transaction with the provided details.")
|
||||
public class LoanTransactionsApiResource {
|
||||
|
||||
private final Set<String> responseDataParameters = new HashSet<>(
|
||||
Arrays.asList("id", "type", "date", "currency", "amount", "externalId"));
|
||||
private final Set<String> responseDataParameters = new HashSet<>(Arrays.asList("id", "type", "date", "currency", "amount", "externalId",
|
||||
LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME, LoanApiConstants.REVERSED_ON_DATE_PARAMNAME));
|
||||
|
||||
private final String resourceNameForPermissions = "LOAN";
|
||||
|
||||
@@ -86,26 +87,6 @@ public class LoanTransactionsApiResource {
|
||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||
private final LoanChargePaidByReadPlatformService loanChargePaidByReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public LoanTransactionsApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final DefaultToApiJsonSerializer<LoanTransactionData> toApiJsonSerializer,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||
LoanChargePaidByReadPlatformService loanChargePaidByReadPlatformService) {
|
||||
this.context = context;
|
||||
this.loanReadPlatformService = loanReadPlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
||||
this.loanChargePaidByReadPlatformService = loanChargePaidByReadPlatformService;
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@@ -132,39 +113,39 @@ public class LoanTransactionsApiResource {
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
LoanTransactionData transactionData = null;
|
||||
if (is(commandParam, "repayment")) {
|
||||
if (CommandParameterUtil.is(commandParam, "repayment")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(loanId);
|
||||
} else if (is(commandParam, "merchantIssuedRefund")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "merchantIssuedRefund")) {
|
||||
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.MERCHANT_ISSUED_REFUND,
|
||||
loanId, transactionDate);
|
||||
} else if (is(commandParam, "payoutRefund")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "payoutRefund")) {
|
||||
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.PAYOUT_REFUND, loanId,
|
||||
transactionDate);
|
||||
} else if (is(commandParam, "goodwillCredit")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "goodwillCredit")) {
|
||||
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.GOODWILL_CREDIT, loanId,
|
||||
transactionDate);
|
||||
} else if (is(commandParam, "waiveinterest")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "waiveinterest")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveWaiveInterestDetails(loanId);
|
||||
} else if (is(commandParam, "writeoff")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "writeoff")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanWriteoffTemplate(loanId);
|
||||
} else if (is(commandParam, "close-rescheduled")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "close-rescheduled")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveNewClosureDetails();
|
||||
} else if (is(commandParam, "close")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "close")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveNewClosureDetails();
|
||||
} else if (is(commandParam, "disburse")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "disburse")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveDisbursalTemplate(loanId, true);
|
||||
transactionData.setNumberOfRepayments(this.loanReadPlatformService.retrieveNumberOfRepayments(loanId));
|
||||
final List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallmentData = this.loanReadPlatformService
|
||||
.getRepaymentDataResponse(loanId);
|
||||
transactionData.setLoanRepaymentScheduleInstallments(loanRepaymentScheduleInstallmentData);
|
||||
} else if (is(commandParam, "disburseToSavings")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "disburseToSavings")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveDisbursalTemplate(loanId, false);
|
||||
} else if (is(commandParam, "recoverypayment")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "recoverypayment")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveRecoveryPaymentTemplate(loanId);
|
||||
} else if (is(commandParam, "prepayLoan")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "prepayLoan")) {
|
||||
LocalDate transactionDate = null;
|
||||
if (transactionDateParam == null) {
|
||||
transactionDate = DateUtils.getBusinessLocalDate();
|
||||
@@ -173,11 +154,11 @@ public class LoanTransactionsApiResource {
|
||||
}
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanId,
|
||||
transactionDate);
|
||||
} else if (is(commandParam, "refundbycash")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "refundbycash")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveRefundByCashTemplate(loanId);
|
||||
} else if (is(commandParam, "refundbytransfer")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "refundbytransfer")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveDisbursalTemplate(loanId, true);
|
||||
} else if (is(commandParam, "foreclosure")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "foreclosure")) {
|
||||
LocalDate transactionDate = null;
|
||||
if (transactionDateParam == null) {
|
||||
transactionDate = DateUtils.getBusinessLocalDate();
|
||||
@@ -185,7 +166,7 @@ public class LoanTransactionsApiResource {
|
||||
transactionDate = transactionDateParam.getDate("transactionDate", dateFormat, locale);
|
||||
}
|
||||
transactionData = this.loanReadPlatformService.retrieveLoanForeclosureTemplate(loanId, transactionDate);
|
||||
} else if (is(commandParam, "creditBalanceRefund")) {
|
||||
} else if (CommandParameterUtil.is(commandParam, "creditBalanceRefund")) {
|
||||
transactionData = this.loanReadPlatformService.retrieveCreditBalanceRefundTemplate(loanId);
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||
@@ -245,55 +226,41 @@ public class LoanTransactionsApiResource {
|
||||
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
|
||||
CommandProcessingResult result = null;
|
||||
if (is(commandParam, "repayment")) {
|
||||
final CommandWrapper commandRequest = builder.loanRepaymentTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "merchantIssuedRefund")) {
|
||||
final CommandWrapper commandRequest = builder.loanMerchantIssuedRefundTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "payoutRefund")) {
|
||||
final CommandWrapper commandRequest = builder.loanPayoutRefundTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "goodwillCredit")) {
|
||||
final CommandWrapper commandRequest = builder.loanGoodwillCreditTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "chargeRefund")) {
|
||||
final CommandWrapper commandRequest = builder.refundLoanCharge(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "waiveinterest")) {
|
||||
final CommandWrapper commandRequest = builder.waiveInterestPortionTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "writeoff")) {
|
||||
final CommandWrapper commandRequest = builder.writeOffLoanTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "close-rescheduled")) {
|
||||
final CommandWrapper commandRequest = builder.closeLoanAsRescheduledTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "close")) {
|
||||
final CommandWrapper commandRequest = builder.closeLoanTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "undowriteoff")) {
|
||||
final CommandWrapper commandRequest = builder.undoWriteOffLoanTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "recoverypayment")) {
|
||||
final CommandWrapper commandRequest = builder.loanRecoveryPaymentTransaction(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "refundByCash")) {
|
||||
final CommandWrapper commandRequest = builder.refundLoanTransactionByCash(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "foreclosure")) {
|
||||
final CommandWrapper commandRequest = builder.loanForeclosure(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "creditBalanceRefund")) {
|
||||
final CommandWrapper commandRequest = builder.creditBalanceRefund(loanId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
CommandWrapper commandRequest = null;
|
||||
if (CommandParameterUtil.is(commandParam, "repayment")) {
|
||||
commandRequest = builder.loanRepaymentTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "merchantIssuedRefund")) {
|
||||
commandRequest = builder.loanMerchantIssuedRefundTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "payoutRefund")) {
|
||||
commandRequest = builder.loanPayoutRefundTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "goodwillCredit")) {
|
||||
commandRequest = builder.loanGoodwillCreditTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "chargeRefund")) {
|
||||
commandRequest = builder.refundLoanCharge(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "waiveinterest")) {
|
||||
commandRequest = builder.waiveInterestPortionTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "writeoff")) {
|
||||
commandRequest = builder.writeOffLoanTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "close-rescheduled")) {
|
||||
commandRequest = builder.closeLoanAsRescheduledTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "close")) {
|
||||
commandRequest = builder.closeLoanTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "undowriteoff")) {
|
||||
commandRequest = builder.undoWriteOffLoanTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "recoverypayment")) {
|
||||
commandRequest = builder.loanRecoveryPaymentTransaction(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "refundByCash")) {
|
||||
commandRequest = builder.refundLoanTransactionByCash(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "foreclosure")) {
|
||||
commandRequest = builder.loanForeclosure(loanId).build();
|
||||
} else if (CommandParameterUtil.is(commandParam, "creditBalanceRefund")) {
|
||||
commandRequest = builder.creditBalanceRefund(loanId).build();
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
if (commandRequest == null) {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||
}
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -142,6 +142,10 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public Double amount;
|
||||
@Schema(example = "559.88")
|
||||
public Double interestPortion;
|
||||
@Schema(example = "20120514")
|
||||
public String reversalExternalId;
|
||||
@Schema(example = "[2012, 5, 18]")
|
||||
public LocalDate reversedOnDate;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoansLoanIdTransactionsRequest")
|
||||
|
||||
+13
-5
@@ -86,6 +86,10 @@ public class LoanTransactionData {
|
||||
private transient String transactionType;
|
||||
private List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallments;
|
||||
|
||||
// Reverse Data
|
||||
private String reversalExternalId;
|
||||
private LocalDate reversedOnDate;
|
||||
|
||||
public static LoanTransactionData importInstance(BigDecimal repaymentAmount, LocalDate lastRepaymentDate, Long repaymentTypeId,
|
||||
Integer rowIndex, String locale, String dateFormat) {
|
||||
return new LoanTransactionData(repaymentAmount, lastRepaymentDate, repaymentTypeId, rowIndex, locale, dateFormat);
|
||||
@@ -222,7 +226,7 @@ public class LoanTransactionData {
|
||||
boolean manuallyReversed) {
|
||||
this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, netDisbursalAmount, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion,
|
||||
paymentTypeOptions, externalId, transfer, fixedEmiAmount, outstandingLoanBalance, null, manuallyReversed);
|
||||
paymentTypeOptions, externalId, transfer, fixedEmiAmount, outstandingLoanBalance, null, manuallyReversed, null, null);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
@@ -230,10 +234,11 @@ public class LoanTransactionData {
|
||||
final BigDecimal netDisbursalAmount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
final BigDecimal unrecognizedIncomePortion, final String externalId, final AccountTransferData transfer,
|
||||
BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance, LocalDate submittedOnDate, final boolean manuallyReversed) {
|
||||
BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance, LocalDate submittedOnDate, final boolean manuallyReversed,
|
||||
final String reversalExternalId, final LocalDate reversedOnDate) {
|
||||
this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, netDisbursalAmount, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, null, externalId,
|
||||
transfer, fixedEmiAmount, outstandingLoanBalance, submittedOnDate, manuallyReversed);
|
||||
transfer, fixedEmiAmount, outstandingLoanBalance, submittedOnDate, manuallyReversed, reversalExternalId, reversedOnDate);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
@@ -242,7 +247,8 @@ public class LoanTransactionData {
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
final BigDecimal unrecognizedIncomePortion, final Collection<PaymentTypeData> paymentTypeOptions, final String externalId,
|
||||
final AccountTransferData transfer, final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance,
|
||||
final LocalDate submittedOnDate, final boolean manuallyReversed) {
|
||||
final LocalDate submittedOnDate, final boolean manuallyReversed, final String reversalExternalId,
|
||||
final LocalDate reversedOnDate) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
@@ -266,6 +272,8 @@ public class LoanTransactionData {
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.manuallyReversed = manuallyReversed;
|
||||
this.possibleNextRepaymentDate = null;
|
||||
this.reversalExternalId = reversalExternalId;
|
||||
this.reversedOnDate = reversedOnDate;
|
||||
}
|
||||
|
||||
public LoanTransactionData(Long id, LoanTransactionEnumData transactionType, LocalDate date, BigDecimal totalAmount,
|
||||
@@ -274,7 +282,7 @@ public class LoanTransactionData {
|
||||
BigDecimal outstandingLoanBalance, final boolean manuallyReversed) {
|
||||
this(id, null, null, transactionType, null, null, date, totalAmount, netDisbursalAmount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, null, null, null, null,
|
||||
outstandingLoanBalance, null, manuallyReversed);
|
||||
outstandingLoanBalance, null, manuallyReversed, null, null);
|
||||
}
|
||||
|
||||
public static LoanTransactionData loanTransactionDataForDisbursalTemplate(final LoanTransactionEnumData transactionType,
|
||||
|
||||
+2
-2
@@ -3606,7 +3606,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public ChangedTransactionDetail adjustExistingTransaction(final LoanTransaction newTransactionDetail,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final String reversalExternalId) {
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
||||
validateActivityNotBeforeLastTransactionDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, transactionForAdjustment.getTransactionDate());
|
||||
@@ -3630,7 +3630,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.or.creditbalancerefund.transactions", errorMessage);
|
||||
}
|
||||
|
||||
transactionForAdjustment.reverse();
|
||||
transactionForAdjustment.reverse(reversalExternalId);
|
||||
transactionForAdjustment.manuallyAdjustedOrReversed();
|
||||
|
||||
if (isClosedWrittenOff()) {
|
||||
|
||||
+12
@@ -106,6 +106,12 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
@Column(name = "external_id", length = 100, nullable = true, unique = true)
|
||||
private String externalId;
|
||||
|
||||
@Column(name = "reversal_external_id", length = 100, nullable = true, unique = true)
|
||||
private String reversalExternalId;
|
||||
|
||||
@Column(name = "reversed_on_date", nullable = true)
|
||||
private LocalDate reversedOnDate;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<LoanChargePaidBy> loanChargesPaid = new HashSet<>();
|
||||
|
||||
@@ -364,9 +370,15 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public void reverse() {
|
||||
this.loan.validateRepaymentTypeTransactionNotBeforeAChargeRefund(this, "reversed");
|
||||
this.reversed = true;
|
||||
this.reversedOnDate = DateUtils.getBusinessLocalDate();
|
||||
this.loanTransactionToRepaymentScheduleMappings.clear();
|
||||
}
|
||||
|
||||
public void reverse(final String reversalExternalId) {
|
||||
this.reverse();
|
||||
this.reversalExternalId = reversalExternalId;
|
||||
}
|
||||
|
||||
public void resetDerivedComponents() {
|
||||
this.principalPortion = null;
|
||||
this.interestPortion = null;
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(
|
||||
newLoanTransaction.getLoanTransactionToRepaymentScheduleMappings());
|
||||
} else {
|
||||
loanTransaction.reverse();
|
||||
loanTransaction.reverse(loanTransaction.getExternalId());
|
||||
loanTransaction.updateExternalId(null);
|
||||
changedTransactionDetail.getNewTransactionMappings().put(loanTransaction.getId(), newLoanTransaction);
|
||||
}
|
||||
|
||||
+9
-10
@@ -33,6 +33,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
@@ -51,24 +52,16 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanRepaymentScheduleNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public final class LoanEventApiJsonValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer;
|
||||
private final LoanRepository loanRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanEventApiJsonValidator(final FromJsonHelper fromApiJsonHelper,
|
||||
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer, final LoanRepository loanRepository) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanRepository = loanRepository;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
@@ -195,7 +188,8 @@ public final class LoanEventApiJsonValidator {
|
||||
}
|
||||
|
||||
final Set<String> transactionParameters = new HashSet<>(Arrays.asList("transactionDate", "transactionAmount", "externalId", "note",
|
||||
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
||||
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber",
|
||||
LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
||||
@@ -213,6 +207,11 @@ public final class LoanEventApiJsonValidator {
|
||||
final String note = this.fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
final String reversalExternalId = this.fromApiJsonHelper.extractStringNamed(LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME).ignoreIfNull().value(reversalExternalId)
|
||||
.notExceedingLengthOf(100);
|
||||
|
||||
validatePaymentDetails(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
+5
-2
@@ -1300,7 +1300,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
|
||||
+ " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, "
|
||||
+ " tr.unrecognized_income_portion as unrecognizedIncome," + " tr.submitted_on_date as submittedOnDate, "
|
||||
+ " tr.manually_adjusted_or_reversed as manuallyReversed, "
|
||||
+ " tr.manually_adjusted_or_reversed as manuallyReversed, tr.reversal_external_id as reversalExternalId, tr.reversed_on_date as reversedOnDate, "
|
||||
+ " pd.payment_type_id 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.net_disbursal_amount as netDisbursalAmount,"
|
||||
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc."
|
||||
@@ -1366,6 +1366,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final BigDecimal unrecognizedIncomePortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "unrecognizedIncome");
|
||||
final BigDecimal outstandingLoanBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "outstandingLoanBalance");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final String reversalExternalId = rs.getString("reversalExternalId");
|
||||
final LocalDate reversedOnDate = JdbcSupport.getLocalDate(rs, "reversedOnDate");
|
||||
|
||||
final BigDecimal netDisbursalAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "netDisbursalAmount");
|
||||
|
||||
@@ -1391,7 +1393,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
return new LoanTransactionData(id, officeId, officeName, transactionType, paymentDetailData, currencyData, date, totalAmount,
|
||||
netDisbursalAmount, principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overPaymentPortion,
|
||||
unrecognizedIncomePortion, externalId, transfer, null, outstandingLoanBalance, submittedOnDate, manuallyReversed);
|
||||
unrecognizedIncomePortion, externalId, transfer, null, outstandingLoanBalance, submittedOnDate, manuallyReversed,
|
||||
reversalExternalId, reversedOnDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -800,7 +800,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
@Override
|
||||
public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = getAppUserIfPresent();
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
checkClientOrGroupActive(loan);
|
||||
businessEventNotifierService.notifyPreBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
|
||||
@@ -1009,8 +1008,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
@Override
|
||||
public CommandProcessingResult adjustLoanTransaction(final Long loanId, final Long transactionId, final JsonCommand command) {
|
||||
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
|
||||
this.loanEventApiJsonValidator.validateTransaction(command.json());
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
@@ -1036,6 +1033,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
||||
final String reversalExternalId = command.stringValueOfParameterNamedAllowingNull(LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
|
||||
@@ -1076,7 +1074,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
||||
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
||||
scheduleGeneratorDTO);
|
||||
scheduleGeneratorDTO, reversalExternalId);
|
||||
|
||||
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
|
||||
if (paymentDetail != null) {
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<include file="parts/0035_add_audit_entries_to_calendar.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0036_add_audit_entries_and_rework_command_source_datetime_fields.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0037_add_loan_cob_job_data.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0038_add_reversal_data_to_loan_transaction.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<addColumn tableName="m_loan_transaction">
|
||||
<column defaultValueComputed="NULL" name="reversal_external_id" type="VARCHAR(100)" />
|
||||
</addColumn>
|
||||
<addColumn tableName="m_loan_transaction">
|
||||
<column defaultValueComputed="NULL" name="reversed_on_date" type="date"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user