FINERACT-1694: Fix missing payment details data for events

This commit is contained in:
Adam Saghy
2023-02-07 18:07:34 +01:00
parent 3f2feceea1
commit 51203b173f
14 changed files with 102 additions and 63 deletions
@@ -261,6 +261,20 @@ final class LoanChargesApiResourceSwagger {
public Double amount; public Double amount;
@Schema(example = "786444UUUYYH7") @Schema(example = "786444UUUYYH7")
public String externalId; public String externalId;
@Schema(example = "An optional note")
public String note;
@Schema(example = "3")
public Long paymentTypeId;
@Schema(example = "acc123")
public String accountNumber;
@Schema(example = "che123")
public String checkNumber;
@Schema(example = "rou123")
public String routingCode;
@Schema(example = "rec123")
public String receiptNumber;
@Schema(example = "ban123")
public String bankNumber;
} }
@Schema(description = "PostLoansLoanIdChargesChargeIdResponse") @Schema(description = "PostLoansLoanIdChargesChargeIdResponse")
@@ -83,19 +83,6 @@ public class LoanTransactionEnumData {
this.chargeAdjustment = Long.valueOf(26).equals(this.id); this.chargeAdjustment = Long.valueOf(26).equals(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() || isRepaymentType() || isRepaymentAtDisbursement() || isRecoveryRepayment()) {
return true;
}
return false;
}
public boolean isRepaymentType() { public boolean isRepaymentType() {
if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund() if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund()
|| isChargeAdjustment()) { || isChargeAdjustment()) {
@@ -6272,8 +6272,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
public void handleChargebackTransaction(final LoanTransaction chargebackTransaction, public void handleChargebackTransaction(final LoanTransaction chargebackTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine) { final LoanLifecycleStateMachine loanLifecycleStateMachine) {
chargebackTransaction.updateLoan(this);
if (!chargebackTransaction.isChargeback()) { if (!chargebackTransaction.isChargeback()) {
final String errorMessage = "A transaction of type chargeback was expected but not received."; final String errorMessage = "A transaction of type chargeback was expected but not received.";
throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.chargeback.transaction", errorMessage); throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.chargeback.transaction", errorMessage);
@@ -97,5 +97,5 @@ public interface LoanAccountDomainService {
void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened); void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened);
LoanTransaction creditBalanceRefund(Loan loan, LocalDate transactionDate, BigDecimal transactionAmount, String noteText, LoanTransaction creditBalanceRefund(Loan loan, LocalDate transactionDate, BigDecimal transactionAmount, String noteText,
ExternalId externalId); ExternalId externalId, PaymentDetail paymentDetail);
} }
@@ -632,19 +632,19 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override @Override
public LoanTransaction creditBalanceRefund(final Loan loan, final LocalDate transactionDate, final BigDecimal transactionAmount, public LoanTransaction creditBalanceRefund(final Loan loan, final LocalDate transactionDate, final BigDecimal transactionAmount,
final String noteText, final ExternalId externalId) { final String noteText, final ExternalId externalId, PaymentDetail paymentDetail) {
businessEventNotifierService.notifyPreBusinessEvent(new LoanCreditBalanceRefundPreBusinessEvent(loan)); businessEventNotifierService.notifyPreBusinessEvent(new LoanCreditBalanceRefundPreBusinessEvent(loan));
final List<Long> existingTransactionIds = new ArrayList<>(); final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>(); final List<Long> existingReversedTransactionIds = new ArrayList<>();
final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount); final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount);
final LoanTransaction newCreditBalanceRefundTransaction = LoanTransaction.creditBalanceRefund(loan, loan.getOffice(), refundAmount, LoanTransaction newCreditBalanceRefundTransaction = LoanTransaction.creditBalanceRefund(loan, loan.getOffice(), refundAmount,
transactionDate, externalId); transactionDate, externalId, paymentDetail);
loan.creditBalanceRefund(newCreditBalanceRefundTransaction, defaultLoanLifecycleStateMachine, existingTransactionIds, loan.creditBalanceRefund(newCreditBalanceRefundTransaction, defaultLoanLifecycleStateMachine, existingTransactionIds,
existingReversedTransactionIds); existingReversedTransactionIds);
this.loanTransactionRepository.saveAndFlush(newCreditBalanceRefundTransaction); newCreditBalanceRefundTransaction = this.loanTransactionRepository.saveAndFlush(newCreditBalanceRefundTransaction);
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanTransactionNote(loan, newCreditBalanceRefundTransaction, noteText); final Note note = Note.loanTransactionNote(loan, newCreditBalanceRefundTransaction, noteText);
@@ -159,9 +159,9 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId); return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
} }
public static LoanTransaction chargeback(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction chargeback(final Loan loan, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final ExternalId externalId) { final LocalDate paymentDate, final ExternalId externalId) {
LoanTransaction loanTransaction = new LoanTransaction(null, office, LoanTransactionType.CHARGEBACK, paymentDetail, LoanTransaction loanTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGEBACK, paymentDetail,
amount.getAmount(), paymentDate, externalId); amount.getAmount(), paymentDate, externalId);
loanTransaction.principalPortion = amount.getAmount(); loanTransaction.principalPortion = amount.getAmount();
return loanTransaction; return loanTransaction;
@@ -175,8 +175,9 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
} }
public static LoanTransaction chargeAdjustment(final Loan loan, final BigDecimal amount, final LocalDate transactionDate, public static LoanTransaction chargeAdjustment(final Loan loan, final BigDecimal amount, final LocalDate transactionDate,
final ExternalId externalId) { final ExternalId externalId, PaymentDetail paymentDetail) {
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGE_ADJUSTMENT, amount, transactionDate, externalId); return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGE_ADJUSTMENT, paymentDetail, amount, transactionDate,
externalId);
} }
public void setLoanTransactionToRepaymentScheduleMappings(final Integer installmentId, final BigDecimal chargePerInstallment) { public void setLoanTransactionToRepaymentScheduleMappings(final Integer installmentId, final BigDecimal chargePerInstallment) {
@@ -290,9 +291,9 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
} }
public static LoanTransaction creditBalanceRefund(final Loan loan, final Office office, final Money amount, final LocalDate paymentDate, public static LoanTransaction creditBalanceRefund(final Loan loan, final Office office, final Money amount, final LocalDate paymentDate,
final ExternalId externalId) { final ExternalId externalId, PaymentDetail paymentDetail) {
return new LoanTransaction(loan, office, LoanTransactionType.CREDIT_BALANCE_REFUND.getValue(), paymentDate, amount.getAmount(), return new LoanTransaction(loan, office, LoanTransactionType.CREDIT_BALANCE_REFUND.getValue(), paymentDate, amount.getAmount(),
null, null, null, null, amount.getAmount(), false, null, externalId); null, null, null, null, amount.getAmount(), false, paymentDetail, externalId);
} }
public static LoanTransaction refundForActiveLoan(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction refundForActiveLoan(final Office office, final Money amount, final PaymentDetail paymentDetail,
@@ -184,13 +184,14 @@ public final class LoanChargeApiJsonValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateLoanAdjustmentRequest(final Long loanId, final Long loanChargeId, final String json) { public void validateLoanChargeAdjustmentRequest(final Long loanId, final Long loanChargeId, final String json) {
if (StringUtils.isBlank(json)) { if (StringUtils.isBlank(json)) {
throw new InvalidJsonException(); throw new InvalidJsonException();
} }
Set<String> transactionParameters = new HashSet<>(List.of("amount", "externalId", "locale")); Set<String> transactionParameters = new HashSet<>(List.of("amount", "externalId", "locale", "paymentTypeId", "accountNumber",
"checkNumber", "routingCode", "receiptNumber", "bankNumber", "note"));
final Type typeOfMap = new TypeToken<Map<String, Object>>() { final Type typeOfMap = new TypeToken<Map<String, Object>>() {
@@ -208,6 +209,9 @@ public final class LoanChargeApiJsonValidator {
baseDataValidator.reset().parameter("loanId").value(loanId).notNull().positiveAmount(); baseDataValidator.reset().parameter("loanId").value(loanId).notNull().positiveAmount();
baseDataValidator.reset().parameter("loanChargeId").value(loanChargeId).notNull().positiveAmount(); baseDataValidator.reset().parameter("loanChargeId").value(loanChargeId).notNull().positiveAmount();
final String note = this.fromApiJsonHelper.extractStringNamed("note", element);
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -123,6 +123,10 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJson
import org.apache.fineract.portfolio.loanproduct.data.LoanOverdueDTO; import org.apache.fineract.portfolio.loanproduct.data.LoanOverdueDTO;
import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException; import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException;
import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException;
import org.apache.fineract.portfolio.note.domain.Note;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -154,6 +158,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
private final AccountTransferDetailRepository accountTransferDetailRepository; private final AccountTransferDetailRepository accountTransferDetailRepository;
private final LoanChargeAssembler loanChargeAssembler; private final LoanChargeAssembler loanChargeAssembler;
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService; private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
private final NoteRepository noteRepository;
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) { private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
return e.getFromDate().isBefore(loanCharge.getDueDate()) && !loanCharge.getDueDate().isAfter(e.getDueDate()); return e.getFromDate().isBefore(loanCharge.getDueDate()) && !loanCharge.getDueDate().isAfter(e.getDueDate());
@@ -640,7 +646,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
@Transactional @Transactional
@Override @Override
public CommandProcessingResult adjustmentForLoanCharge(Long loanId, Long loanChargeId, JsonCommand command) { public CommandProcessingResult adjustmentForLoanCharge(Long loanId, Long loanChargeId, JsonCommand command) {
this.loanChargeApiJsonValidator.validateLoanAdjustmentRequest(loanId, loanChargeId, command.json()); this.loanChargeApiJsonValidator.validateLoanChargeAdjustmentRequest(loanId, loanChargeId, command.json());
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId); final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
final LocalDate transactionDate = DateUtils.getBusinessLocalDate(); final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
@@ -648,12 +654,22 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
final ExternalId externalId = externalIdFactory.createFromCommand(command, "externalId"); final ExternalId externalId = externalIdFactory.createFromCommand(command, "externalId");
final String locale = command.locale(); final String locale = command.locale();
Map<String, Object> changes = new HashMap<>();
changes.put("externalId", externalId);
changes.put("amount", transactionAmount);
changes.put("transactionDate", transactionDate);
changes.put("locale", locale);
loanChargeAdjustmentEntranceValidation(loanCharge, transactionAmount); loanChargeAdjustmentEntranceValidation(loanCharge, transactionAmount);
final Loan loan = loanAssembler.assembleFrom(loanId); final Loan loan = loanAssembler.assembleFrom(loanId);
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder(); final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes);
LoanTransaction loanTransaction = applyChargeAdjustment(loan, loanCharge, transactionAmount, transactionDate, externalId); if (paymentDetail != null) {
paymentDetail = this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
LoanTransaction loanTransaction = applyChargeAdjustment(loan, loanCharge, transactionAmount, transactionDate, externalId,
paymentDetail);
// Update loan transaction on repayment. // Update loan transaction on repayment.
if (AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) { if (AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) {
@@ -671,13 +687,17 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
} }
this.loanAccountDomainService.updateLoanCollateralTransaction(loanCollateralManagements); this.loanAccountDomainService.updateLoanCollateralTransaction(loanCollateralManagements);
} }
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanNote(loan, noteText);
changes.put("note", noteText);
this.noteRepository.save(note);
}
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan)); businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
businessEventNotifierService.notifyPostBusinessEvent(new LoanChargeAdjustmentPostBusinessEvent(loanTransaction)); businessEventNotifierService.notifyPostBusinessEvent(new LoanChargeAdjustmentPostBusinessEvent(loanTransaction));
Map<String, Object> changes = new HashMap<>();
changes.put("externalId", externalId);
changes.put("amount", transactionAmount);
changes.put("transactionDate", transactionDate);
changes.put("locale", locale);
return commandProcessingResultBuilder.withCommandId(command.commandId()) // return commandProcessingResultBuilder.withCommandId(command.commandId()) //
.withLoanId(loanId) // .withLoanId(loanId) //
.withEntityId(loanChargeId) // .withEntityId(loanChargeId) //
@@ -753,13 +773,13 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
} }
private LoanTransaction applyChargeAdjustment(final Loan loan, final LoanCharge loanCharge, final BigDecimal transactionAmount, private LoanTransaction applyChargeAdjustment(final Loan loan, final LoanCharge loanCharge, final BigDecimal transactionAmount,
final LocalDate transactionDate, final ExternalId txnExternalId) { final LocalDate transactionDate, final ExternalId txnExternalId, PaymentDetail paymentDetail) {
businessEventNotifierService.notifyPreBusinessEvent(new LoanChargeAdjustmentPreBusinessEvent(loan)); businessEventNotifierService.notifyPreBusinessEvent(new LoanChargeAdjustmentPreBusinessEvent(loan));
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
LoanTransaction loanChargeAdjustmentTransaction = LoanTransaction.chargeAdjustment(loan, transactionAmount, transactionDate, LoanTransaction loanChargeAdjustmentTransaction = LoanTransaction.chargeAdjustment(loan, transactionAmount, transactionDate,
txnExternalId); txnExternalId, paymentDetail);
LoanTransactionRelation loanTransactionRelation = LoanTransactionRelation.linkToCharge(loanChargeAdjustmentTransaction, loanCharge, LoanTransactionRelation loanTransactionRelation = LoanTransactionRelation.linkToCharge(loanChargeAdjustmentTransaction, loanCharge,
LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT); LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT);
loanChargeAdjustmentTransaction.getLoanTransactionRelations().add(loanTransactionRelation); loanChargeAdjustmentTransaction.getLoanTransactionRelations().add(loanTransactionRelation);
@@ -1386,20 +1386,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
PaymentDetailData paymentDetailData = null; PaymentDetailData paymentDetailData = null;
if (transactionType.isPaymentOrReceipt()) { final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType");
final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType"); if (paymentTypeId != null) {
if (paymentTypeId != null) { final String typeName = rs.getString("paymentTypeName");
final String typeName = rs.getString("paymentTypeName"); final PaymentTypeData paymentType = PaymentTypeData.instance(paymentTypeId, typeName);
final PaymentTypeData paymentType = PaymentTypeData.instance(paymentTypeId, typeName); final String accountNumber = rs.getString("accountNumber");
final String accountNumber = rs.getString("accountNumber"); final String checkNumber = rs.getString("checkNumber");
final String checkNumber = rs.getString("checkNumber"); final String routingCode = rs.getString("routingCode");
final String routingCode = rs.getString("routingCode"); final String receiptNumber = rs.getString("receiptNumber");
final String receiptNumber = rs.getString("receiptNumber"); final String bankNumber = rs.getString("bankNumber");
final String bankNumber = rs.getString("bankNumber"); paymentDetailData = new PaymentDetailData(id, paymentType, accountNumber, checkNumber, routingCode, receiptNumber,
paymentDetailData = new PaymentDetailData(id, paymentType, accountNumber, checkNumber, routingCode, receiptNumber, bankNumber);
bankNumber);
}
} }
final LocalDate date = JdbcSupport.getLocalDate(rs, "date"); final LocalDate date = JdbcSupport.getLocalDate(rs, "date");
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final BigDecimal totalAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "total"); final BigDecimal totalAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "total");
@@ -1256,20 +1256,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("paymentTypeId", command.longValueOfParameterNamed(LoanApiConstants.PAYMENT_TYPE_PARAMNAME)); changes.put("paymentTypeId", command.longValueOfParameterNamed(LoanApiConstants.PAYMENT_TYPE_PARAMNAME));
final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount); final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes); PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes);
LoanTransaction newTransaction = LoanTransaction.chargeback(loan.getOffice(), transactionAmountAsMoney, paymentDetail, if (paymentDetail != null) {
transactionDate, txnExternalId); paymentDetail = this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
LoanTransaction newTransaction = LoanTransaction.chargeback(loan, transactionAmountAsMoney, paymentDetail, transactionDate,
txnExternalId);
validateLoanTransactionAmountChargeBack(loanTransaction, newTransaction); validateLoanTransactionAmountChargeBack(loanTransaction, newTransaction);
this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
// Store the Loan Transaction Relation // Store the Loan Transaction Relation
LoanTransactionRelation loanTransactionRelation = LoanTransactionRelation.linkToTransaction(loanTransaction, newTransaction, LoanTransactionRelation loanTransactionRelation = LoanTransactionRelation.linkToTransaction(loanTransaction, newTransaction,
LoanTransactionRelationTypeEnum.CHARGEBACK); LoanTransactionRelationTypeEnum.CHARGEBACK);
this.loanTransactionRelationRepository.save(loanTransactionRelation); this.loanTransactionRelationRepository.save(loanTransactionRelation);
this.loanTransactionRepository.save(newTransaction); newTransaction = this.loanTransactionRepository.saveAndFlush(newTransaction);
loan.handleChargebackTransaction(newTransaction, defaultLoanLifecycleStateMachine); loan.handleChargebackTransaction(newTransaction, defaultLoanLifecycleStateMachine);
@@ -2439,9 +2440,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (!externalId.isEmpty()) { if (!externalId.isEmpty()) {
changes.put(LoanApiConstants.externalIdParameterName, externalId); changes.put(LoanApiConstants.externalIdParameterName, externalId);
} }
changes.put("paymentTypeId", command.longValueOfParameterNamed(LoanApiConstants.PAYMENT_TYPE_PARAMNAME));
PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes);
if (paymentDetail != null) {
paymentDetail = this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
final LoanTransaction loanTransaction = this.loanAccountDomainService.creditBalanceRefund(loan, transactionDate, transactionAmount, final LoanTransaction loanTransaction = this.loanAccountDomainService.creditBalanceRefund(loan, transactionDate, transactionAmount,
noteText, externalId); noteText, externalId, paymentDetail);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(loanTransaction.getId()) // .withEntityId(loanTransaction.getId()) //
@@ -82,6 +82,7 @@ public final class PaymentDetail extends AbstractPersistableCustom {
if (StringUtils.isNotBlank(bankNumber)) { if (StringUtils.isNotBlank(bankNumber)) {
changes.put(PaymentDetailConstants.bankNumberParamName, bankNumber); changes.put(PaymentDetailConstants.bankNumberParamName, bankNumber);
} }
changes.put("paymentTypeId", paymentType.getId());
final PaymentDetail paymentDetail = new PaymentDetail(paymentType, accountNumber, checkNumber, routingCode, receiptNumber, final PaymentDetail paymentDetail = new PaymentDetail(paymentType, accountNumber, checkNumber, routingCode, receiptNumber,
bankNumber); bankNumber);
return paymentDetail; return paymentDetail;
@@ -163,7 +163,7 @@ public class LoanDelinquencyDomainServiceTest {
final Money zeroMoney = Money.zero(currency); final Money zeroMoney = Money.zero(currency);
LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(loan, 1, fromDate, dueDate, principal, LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(loan, 1, fromDate, dueDate, principal,
zeroAmount, zeroAmount, zeroAmount, false, new HashSet<>(), zeroAmount); zeroAmount, zeroAmount, zeroAmount, false, new HashSet<>(), zeroAmount);
LoanTransaction loanTransaction = LoanTransaction.chargeback(null, Money.of(currency, principal), paymentDetail, transactionDate, LoanTransaction loanTransaction = LoanTransaction.chargeback(loan, Money.of(currency, principal), paymentDetail, transactionDate,
null); null);
installment.getLoanTransactionToRepaymentScheduleMappings().add(LoanTransactionToRepaymentScheduleMapping installment.getLoanTransactionToRepaymentScheduleMappings().add(LoanTransactionToRepaymentScheduleMapping
.createFrom(loanTransaction, installment, zeroMoney, zeroMoney, zeroMoney, zeroMoney)); .createFrom(loanTransaction, installment, zeroMoney, zeroMoney, zeroMoney, zeroMoney));
@@ -6169,7 +6169,8 @@ public class ClientLoanIntegrationTest {
String externalId = UUID.randomUUID().toString(); String externalId = UUID.randomUUID().toString();
PostLoansLoanIdChargesChargeIdResponse chargeAdjustmentResponse = this.loanTransactionHelper.chargeAdjustment((long) loanID, PostLoansLoanIdChargesChargeIdResponse chargeAdjustmentResponse = this.loanTransactionHelper.chargeAdjustment((long) loanID,
(long) penalty1LoanChargeId, new PostLoansLoanIdChargesChargeIdRequest().amount(10.0).externalId(externalId)); (long) penalty1LoanChargeId,
new PostLoansLoanIdChargesChargeIdRequest().amount(10.0).externalId(externalId).paymentTypeId(1L));
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID); loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
assertEquals(2, loanSchedule.size()); assertEquals(2, loanSchedule.size());
@@ -6196,6 +6197,7 @@ public class ClientLoanIntegrationTest {
assertEquals(chargeAdjustmentResponse.getSubResourceId(), transactionRelation.getFromLoanTransaction()); assertEquals(chargeAdjustmentResponse.getSubResourceId(), transactionRelation.getFromLoanTransaction());
assertEquals((long) penalty1LoanChargeId, transactionRelation.getToLoanCharge()); assertEquals((long) penalty1LoanChargeId, transactionRelation.getToLoanCharge());
assertEquals("CHARGE_ADJUSTMENT", transactionRelation.getRelationType()); assertEquals("CHARGE_ADJUSTMENT", transactionRelation.getRelationType());
assertEquals(1L, chargeAdjustmentTransaction.getPaymentDetailData().getPaymentType().getId());
PostLoansLoanIdTransactionsResponse repaymentResult = loanTransactionHelper.makeLoanRepayment((long) loanID, PostLoansLoanIdTransactionsResponse repaymentResult = loanTransactionHelper.makeLoanRepayment((long) loanID,
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("06 September 2022").locale("en") new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("06 September 2022").locale("en")
@@ -7177,7 +7179,7 @@ public class ClientLoanIntegrationTest {
assertTrue(loanDetails.getStatus().getOverpaid()); assertTrue(loanDetails.getStatus().getOverpaid());
this.loanTransactionHelper.makeCreditBalanceRefund((long) loanID, new PostLoansLoanIdTransactionsRequest() this.loanTransactionHelper.makeCreditBalanceRefund((long) loanID, new PostLoansLoanIdTransactionsRequest()
.transactionAmount(200.0).transactionDate("10 October 2022").dateFormat("dd MMMM yyyy").locale("en")); .transactionAmount(200.0).transactionDate("10 October 2022").dateFormat("dd MMMM yyyy").locale("en").paymentTypeId(1L));
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID); loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
assertTrue(loanDetails.getStatus().getClosedObligationsMet()); assertTrue(loanDetails.getStatus().getClosedObligationsMet());
@@ -7198,7 +7200,7 @@ public class ClientLoanIntegrationTest {
assertEquals(200.0, loanDetails.getTransactions().get(3).getOverpaymentPortion()); assertEquals(200.0, loanDetails.getTransactions().get(3).getOverpaymentPortion());
assertEquals(LocalDate.of(2022, 10, 10), loanDetails.getTransactions().get(3).getDate()); assertEquals(LocalDate.of(2022, 10, 10), loanDetails.getTransactions().get(3).getDate());
assertEquals(0.0, loanDetails.getTransactions().get(3).getOutstandingLoanBalance()); assertEquals(0.0, loanDetails.getTransactions().get(3).getOutstandingLoanBalance());
assertEquals(1L, loanDetails.getTransactions().get(3).getPaymentDetailData().getPaymentType().getId());
GetJournalEntriesTransactionIdResponse journalEntriesForTransaction = journalEntryHelper GetJournalEntriesTransactionIdResponse journalEntriesForTransaction = journalEntryHelper
.getJournalEntries("L" + loanDetails.getTransactions().get(3).getId()); .getJournalEntries("L" + loanDetails.getTransactions().get(3).getId());
List<JournalEntryTransactionItem> journalItems = journalEntriesForTransaction.getPageItems(); List<JournalEntryTransactionItem> journalItems = journalEntriesForTransaction.getPageItems();
@@ -32,6 +32,7 @@ import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse; import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
@@ -91,9 +92,14 @@ public class LoanAccountCreditRefundPayoutWithChargebackTest {
.transactionAmount(1000.0)); .transactionAmount(1000.0));
// Chargeback full repayment amount to add to principal balance // Chargeback full repayment amount to add to principal balance
loanTransactionHelper.chargebackLoanTransaction(loanExternalIdStr, repaymentTransaction_1.getResourceId(), PostLoansLoanIdTransactionsResponse chargebackResponse = loanTransactionHelper.chargebackLoanTransaction(loanExternalIdStr,
repaymentTransaction_1.getResourceId(),
new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(1000.0).paymentTypeId(1L)); new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(1000.0).paymentTypeId(1L));
GetLoansLoanIdTransactionsTransactionIdResponse chargebackTransactionResponse = loanTransactionHelper
.getLoanTransactionDetails(chargebackResponse.getLoanId(), chargebackResponse.getResourceId());
assertEquals(1L, chargebackTransactionResponse.getPaymentDetailData().getPaymentType().getId());
// Verify Goodwill Credit can be created with full amount // Verify Goodwill Credit can be created with full amount
final PostLoansLoanIdTransactionsResponse goodwillCredit_1 = loanTransactionHelper.makeGoodwillCredit((long) loanId, final PostLoansLoanIdTransactionsResponse goodwillCredit_1 = loanTransactionHelper.makeGoodwillCredit((long) loanId,
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("8 September 2022").locale("en") new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("8 September 2022").locale("en")