FINERACT-2042 Credit Allocation for Principal and Interest components
This commit is contained in:
committed by
Peter Bagrij
parent
717eb69425
commit
c504996c1d
+3
-2
@@ -430,11 +430,12 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal overpaidAmount = Objects.isNull(loanTransactionDTO.getOverPayment()) ? BigDecimal.ZERO
|
||||
: loanTransactionDTO.getOverPayment();
|
||||
|
||||
if (BigDecimal.ZERO.compareTo(overpaidAmount) == 0) {
|
||||
if (BigDecimal.ZERO.compareTo(overpaidAmount) == 0) { // when no overpay
|
||||
helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
amount, isReversal);
|
||||
} else if (overpaidAmount.compareTo(amount) >= 0) {
|
||||
} else if (overpaidAmount.compareTo(amount) >= 0) { // when the overpay amount is matching with the normal
|
||||
// amount
|
||||
helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
amount, isReversal);
|
||||
|
||||
+7
@@ -66,6 +66,7 @@ import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanPaymentAllocationRule;
|
||||
@@ -390,6 +391,12 @@ public class LoanAssembler {
|
||||
r.getFutureInstallmentAllocationRule()))
|
||||
.toList();
|
||||
loanApplication.setPaymentAllocationRules(loanPaymentAllocationRules);
|
||||
|
||||
if (loanProduct.getCreditAllocationRules() != null && loanProduct.getCreditAllocationRules().size() > 0) {
|
||||
List<LoanCreditAllocationRule> loanCreditAllocationRules = loanProduct.getCreditAllocationRules().stream()
|
||||
.map(r -> new LoanCreditAllocationRule(loanApplication, r.getTransactionType(), r.getAllocationTypes())).toList();
|
||||
loanApplication.setCreditAllocationRules(loanCreditAllocationRules);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+235
-14
@@ -18,13 +18,25 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl;
|
||||
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CHARGEBACK;
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REPAYMENT;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.FEE;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.INTEREST;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PENALTY;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PRINCIPAL;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.refEq;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -39,21 +51,27 @@ import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanPaymentAllocationRule;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
@@ -95,13 +113,13 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
final BigDecimal chargeAmount = BigDecimal.valueOf(100);
|
||||
LocalDate disbursementDate = LocalDate.of(2023, 1, 1);
|
||||
LocalDate transactionDate = LocalDate.of(2023, 1, 5);
|
||||
LoanTransaction loanTransaction = Mockito.mock(LoanTransaction.class);
|
||||
LoanTransaction loanTransaction = mock(LoanTransaction.class);
|
||||
MonetaryCurrency currency = MONETARY_CURRENCY;
|
||||
LoanCharge charge = Mockito.mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = Mockito.mock(LoanChargePaidBy.class);
|
||||
LoanCharge charge = mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = mock(LoanChargePaidBy.class);
|
||||
Money overpaidAmount = Money.zero(currency);
|
||||
Money zero = Money.zero(currency);
|
||||
Loan loan = Mockito.mock(Loan.class);
|
||||
Loan loan = mock(Loan.class);
|
||||
Money chargeAmountMoney = Money.of(currency, chargeAmount);
|
||||
LoanRepaymentScheduleInstallment installment = Mockito
|
||||
.spy(new LoanRepaymentScheduleInstallment(loan, 1, disbursementDate, disbursementDate.plusMonths(1), BigDecimal.valueOf(0L),
|
||||
@@ -138,13 +156,13 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
BigDecimal chargeAmount = BigDecimal.valueOf(100.00);
|
||||
LocalDate disbursementDate = LocalDate.of(2023, 1, 1);
|
||||
LocalDate transactionDate = LocalDate.of(2023, 1, 5);
|
||||
LoanTransaction loanTransaction = Mockito.mock(LoanTransaction.class);
|
||||
LoanTransaction loanTransaction = mock(LoanTransaction.class);
|
||||
MonetaryCurrency currency = MONETARY_CURRENCY;
|
||||
LoanCharge charge = Mockito.mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = Mockito.mock(LoanChargePaidBy.class);
|
||||
LoanCharge charge = mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = mock(LoanChargePaidBy.class);
|
||||
Money overpaidAmount = Money.zero(currency);
|
||||
Money zero = Money.zero(currency);
|
||||
Loan loan = Mockito.mock(Loan.class);
|
||||
Loan loan = mock(Loan.class);
|
||||
Money chargeAmountMoney = Money.of(currency, chargeAmount);
|
||||
BigDecimal transactionAmount = BigDecimal.valueOf(20.00);
|
||||
Money transactionAmountMoney = Money.of(currency, transactionAmount);
|
||||
@@ -184,18 +202,18 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
BigDecimal chargeAmount = BigDecimal.valueOf(100.00);
|
||||
LocalDate disbursementDate = LocalDate.of(2023, 1, 1);
|
||||
LocalDate transactionDate = disbursementDate.plusMonths(1);
|
||||
LoanTransaction loanTransaction = Mockito.mock(LoanTransaction.class);
|
||||
LoanTransaction loanTransaction = mock(LoanTransaction.class);
|
||||
MonetaryCurrency currency = MONETARY_CURRENCY;
|
||||
LoanCharge charge = Mockito.mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = Mockito.mock(LoanChargePaidBy.class);
|
||||
LoanCharge charge = mock(LoanCharge.class);
|
||||
LoanChargePaidBy chargePaidBy = mock(LoanChargePaidBy.class);
|
||||
Money overpaidAmount = Money.zero(currency);
|
||||
Money zero = Money.zero(currency);
|
||||
Loan loan = Mockito.mock(Loan.class);
|
||||
LoanProductRelatedDetail loanProductRelatedDetail = Mockito.mock(LoanProductRelatedDetail.class);
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanProductRelatedDetail loanProductRelatedDetail = mock(LoanProductRelatedDetail.class);
|
||||
Money chargeAmountMoney = Money.of(currency, chargeAmount);
|
||||
BigDecimal transactionAmount = BigDecimal.valueOf(120.00);
|
||||
Money transactionAmountMoney = Money.of(currency, transactionAmount);
|
||||
LoanPaymentAllocationRule loanPaymentAllocationRule = Mockito.mock(LoanPaymentAllocationRule.class);
|
||||
LoanPaymentAllocationRule loanPaymentAllocationRule = mock(LoanPaymentAllocationRule.class);
|
||||
LoanRepaymentScheduleInstallment installment = Mockito
|
||||
.spy(new LoanRepaymentScheduleInstallment(loan, 1, disbursementDate, transactionDate, BigDecimal.valueOf(100L),
|
||||
BigDecimal.valueOf(0L), chargeAmount, BigDecimal.valueOf(0L), false, null, BigDecimal.ZERO));
|
||||
@@ -232,4 +250,207 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
assertEquals(0, BigDecimal.valueOf(80).compareTo(installment.getPrincipalOutstanding(currency).getAmount()));
|
||||
Mockito.verify(loan, Mockito.times(1)).getPaymentAllocationRules();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessCreditTransactionWithAllocationRuleInterestAndPrincipal() {
|
||||
// given
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanCreditAllocationRule mockCreditAllocationRule = createMockCreditAllocationRule(INTEREST, PRINCIPAL, PENALTY, FEE);
|
||||
Mockito.when(loan.getCreditAllocationRules()).thenReturn(List.of(mockCreditAllocationRule));
|
||||
LoanTransaction repayment = createRepayment(loan);
|
||||
lenient().when(loan.getLoanTransactions(any())).thenReturn(List.of(repayment));
|
||||
|
||||
LoanTransaction chargeBackTransaction = createChargebackTransaction(loan);
|
||||
MoneyHolder overpaymentHolder = new MoneyHolder(Money.zero(MONETARY_CURRENCY));
|
||||
List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LoanRepaymentScheduleInstallment installment = createMockInstallment(LocalDate.of(2023, 1, 31), false);
|
||||
installments.add(installment);
|
||||
|
||||
// when
|
||||
underTest.processCreditTransaction(chargeBackTransaction, overpaymentHolder, MONETARY_CURRENCY, installments);
|
||||
|
||||
// then
|
||||
Mockito.verify(installment, Mockito.times(1)).addToCredits(new BigDecimal("25.00"));
|
||||
Mockito.verify(installment, Mockito.times(1)).updateInterestCharged(new BigDecimal("20.00"));
|
||||
ArgumentCaptor<LocalDate> localDateArgumentCaptor = ArgumentCaptor.forClass(LocalDate.class);
|
||||
ArgumentCaptor<Money> moneyCaptor = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(installment, Mockito.times(1)).addToPrincipal(localDateArgumentCaptor.capture(), moneyCaptor.capture());
|
||||
Assertions.assertEquals(LocalDate.of(2023, 1, 1), localDateArgumentCaptor.getValue());
|
||||
assertEquals(0, moneyCaptor.getValue().getAmount().compareTo(BigDecimal.valueOf(5.0)));
|
||||
|
||||
ArgumentCaptor<Money> principal = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> interest = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> fee = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> penalty = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(chargeBackTransaction, times(1)).updateComponents(principal.capture(), interest.capture(), fee.capture(),
|
||||
penalty.capture());
|
||||
assertEquals(0, principal.getValue().getAmount().compareTo(BigDecimal.valueOf(5.0)));
|
||||
assertEquals(0, interest.getValue().getAmount().compareTo(BigDecimal.valueOf(20.0)));
|
||||
assertEquals(0, fee.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
assertEquals(0, penalty.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessCreditTransactionWithAllocationRulePrincipalAndInterest() {
|
||||
// given
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanCreditAllocationRule mockCreditAllocationRule = createMockCreditAllocationRule(PRINCIPAL, INTEREST, PENALTY, FEE);
|
||||
Mockito.when(loan.getCreditAllocationRules()).thenReturn(List.of(mockCreditAllocationRule));
|
||||
LoanTransaction repayment = createRepayment(loan);
|
||||
lenient().when(loan.getLoanTransactions(any())).thenReturn(List.of(repayment));
|
||||
|
||||
LoanTransaction chargeBackTransaction = createChargebackTransaction(loan);
|
||||
MoneyHolder overpaymentHolder = new MoneyHolder(Money.zero(MONETARY_CURRENCY));
|
||||
List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LoanRepaymentScheduleInstallment installment = createMockInstallment(LocalDate.of(2023, 1, 31), false);
|
||||
installments.add(installment);
|
||||
|
||||
// when
|
||||
underTest.processCreditTransaction(chargeBackTransaction, overpaymentHolder, MONETARY_CURRENCY, installments);
|
||||
|
||||
// then
|
||||
Mockito.verify(installment, Mockito.times(1)).addToCredits(new BigDecimal("25.00"));
|
||||
Mockito.verify(installment, Mockito.times(1)).updateInterestCharged(new BigDecimal("15.00"));
|
||||
ArgumentCaptor<LocalDate> localDateArgumentCaptor = ArgumentCaptor.forClass(LocalDate.class);
|
||||
ArgumentCaptor<Money> moneyCaptor = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(installment, Mockito.times(1)).addToPrincipal(localDateArgumentCaptor.capture(), moneyCaptor.capture());
|
||||
Assertions.assertEquals(LocalDate.of(2023, 1, 1), localDateArgumentCaptor.getValue());
|
||||
assertEquals(0, moneyCaptor.getValue().getAmount().compareTo(BigDecimal.valueOf(10.0)));
|
||||
|
||||
ArgumentCaptor<Money> principal = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> interest = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> fee = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> penalty = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(chargeBackTransaction, times(1)).updateComponents(principal.capture(), interest.capture(), fee.capture(),
|
||||
penalty.capture());
|
||||
assertEquals(0, principal.getValue().getAmount().compareTo(BigDecimal.valueOf(10.0)));
|
||||
assertEquals(0, interest.getValue().getAmount().compareTo(BigDecimal.valueOf(15.0)));
|
||||
assertEquals(0, fee.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
assertEquals(0, penalty.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessCreditTransactionWithAllocationRulePrincipalAndInterestWithAdditionalInstallment() {
|
||||
// given
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanCreditAllocationRule mockCreditAllocationRule = createMockCreditAllocationRule(PRINCIPAL, INTEREST, PENALTY, FEE);
|
||||
Mockito.when(loan.getCreditAllocationRules()).thenReturn(List.of(mockCreditAllocationRule));
|
||||
LoanTransaction repayment = createRepayment(loan);
|
||||
lenient().when(loan.getLoanTransactions(any())).thenReturn(List.of(repayment));
|
||||
|
||||
LoanTransaction chargeBackTransaction = createChargebackTransaction(loan);
|
||||
MoneyHolder overpaymentHolder = new MoneyHolder(Money.zero(MONETARY_CURRENCY));
|
||||
List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LoanRepaymentScheduleInstallment installment1 = createMockInstallment(LocalDate.of(2022, 12, 20), false);
|
||||
LoanRepaymentScheduleInstallment installment2 = createMockInstallment(LocalDate.of(2022, 12, 27), true);
|
||||
installments.add(installment1);
|
||||
installments.add(installment2);
|
||||
|
||||
// when
|
||||
underTest.processCreditTransaction(chargeBackTransaction, overpaymentHolder, MONETARY_CURRENCY, installments);
|
||||
|
||||
// then
|
||||
Mockito.verify(installment2, Mockito.times(1)).addToCredits(new BigDecimal("25.00"));
|
||||
Mockito.verify(installment2, Mockito.times(1)).updateInterestCharged(new BigDecimal("15.00"));
|
||||
ArgumentCaptor<LocalDate> localDateArgumentCaptor = ArgumentCaptor.forClass(LocalDate.class);
|
||||
ArgumentCaptor<Money> moneyCaptor = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(installment2, Mockito.times(1)).addToPrincipal(localDateArgumentCaptor.capture(), moneyCaptor.capture());
|
||||
Assertions.assertEquals(LocalDate.of(2023, 1, 1), localDateArgumentCaptor.getValue());
|
||||
assertEquals(0, moneyCaptor.getValue().getAmount().compareTo(BigDecimal.valueOf(10.0)));
|
||||
|
||||
ArgumentCaptor<Money> principal = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> interest = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> fee = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<Money> penalty = ArgumentCaptor.forClass(Money.class);
|
||||
Mockito.verify(chargeBackTransaction, times(1)).updateComponents(principal.capture(), interest.capture(), fee.capture(),
|
||||
penalty.capture());
|
||||
assertEquals(0, principal.getValue().getAmount().compareTo(BigDecimal.valueOf(10.0)));
|
||||
assertEquals(0, interest.getValue().getAmount().compareTo(BigDecimal.valueOf(15.0)));
|
||||
assertEquals(0, fee.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
assertEquals(0, penalty.getValue().getAmount().compareTo(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
private LoanRepaymentScheduleInstallment createMockInstallment(LocalDate localDate, boolean isAdditional) {
|
||||
LoanRepaymentScheduleInstallment installment = mock(LoanRepaymentScheduleInstallment.class);
|
||||
lenient().when(installment.isAdditional()).thenReturn(isAdditional);
|
||||
lenient().when(installment.getDueDate()).thenReturn(localDate);
|
||||
Money interestCharged = Money.of(MONETARY_CURRENCY, BigDecimal.ZERO);
|
||||
lenient().when(installment.getInterestCharged(MONETARY_CURRENCY)).thenReturn(interestCharged);
|
||||
return installment;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LoanCreditAllocationRule createMockCreditAllocationRule(AllocationType... allocationTypes) {
|
||||
LoanCreditAllocationRule mockCreditAllocationRule = mock(LoanCreditAllocationRule.class);
|
||||
lenient().when(mockCreditAllocationRule.getTransactionType()).thenReturn(CreditAllocationTransactionType.CHARGEBACK);
|
||||
lenient().when(mockCreditAllocationRule.getAllocationTypes()).thenReturn(Arrays.asList(allocationTypes));
|
||||
return mockCreditAllocationRule;
|
||||
}
|
||||
|
||||
private LoanTransaction createRepayment(Loan loan) {
|
||||
LoanTransaction repayment = mock(LoanTransaction.class);
|
||||
lenient().when(repayment.getLoan()).thenReturn(loan);
|
||||
lenient().when(repayment.isRepayment()).thenReturn(true);
|
||||
lenient().when(repayment.getTypeOf()).thenReturn(REPAYMENT);
|
||||
lenient().when(repayment.getPrincipalPortion()).thenReturn(BigDecimal.valueOf(10));
|
||||
lenient().when(repayment.getInterestPortion()).thenReturn(BigDecimal.valueOf(20));
|
||||
lenient().when(repayment.getFeeChargesPortion()).thenReturn(BigDecimal.ZERO);
|
||||
lenient().when(repayment.getPenaltyChargesPortion()).thenReturn(BigDecimal.ZERO);
|
||||
return repayment;
|
||||
}
|
||||
|
||||
private LoanTransaction createChargebackTransaction(Loan loan) {
|
||||
LoanTransaction chargeback = mock(LoanTransaction.class);
|
||||
lenient().when(chargeback.isChargeback()).thenReturn(true);
|
||||
lenient().when(chargeback.getTypeOf()).thenReturn(CHARGEBACK);
|
||||
lenient().when(chargeback.getLoan()).thenReturn(loan);
|
||||
lenient().when(chargeback.getAmount()).thenReturn(BigDecimal.valueOf(25));
|
||||
Money amount = Money.of(MONETARY_CURRENCY, BigDecimal.valueOf(25));
|
||||
lenient().when(chargeback.getAmount(MONETARY_CURRENCY)).thenReturn(amount);
|
||||
lenient().when(chargeback.getTransactionDate()).thenReturn(LocalDate.of(2023, 1, 1));
|
||||
return chargeback;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateChargebackAllocationMap() {
|
||||
Map<AllocationType, Money> result;
|
||||
MonetaryCurrency currency = mock(MonetaryCurrency.class);
|
||||
|
||||
result = underTest.calculateChargebackAllocationMap(allocationMap(50.0, 100.0, 200.0, 12.0), BigDecimal.valueOf(50.0),
|
||||
List.of(PRINCIPAL, INTEREST, FEE, PENALTY), currency);
|
||||
verify(allocationMap(50.0, 0, 0, 0), result);
|
||||
|
||||
result = underTest.calculateChargebackAllocationMap(allocationMap(40.0, 100.0, 200.0, 12.0), BigDecimal.valueOf(50.0),
|
||||
List.of(PRINCIPAL, INTEREST, FEE, PENALTY), currency);
|
||||
verify(allocationMap(40.0, 10, 0, 0), result);
|
||||
|
||||
result = underTest.calculateChargebackAllocationMap(allocationMap(40.0, 100.0, 200.0, 12.0), BigDecimal.valueOf(50.0),
|
||||
List.of(PRINCIPAL, FEE, PENALTY, INTEREST), currency);
|
||||
verify(allocationMap(40.0, 0, 10, 0), result);
|
||||
|
||||
result = underTest.calculateChargebackAllocationMap(allocationMap(40.0, 100.0, 200.0, 12.0), BigDecimal.valueOf(340.0),
|
||||
List.of(PRINCIPAL, FEE, PENALTY, INTEREST), currency);
|
||||
verify(allocationMap(40.0, 88.0, 200.0, 12.0), result);
|
||||
|
||||
result = underTest.calculateChargebackAllocationMap(allocationMap(40.0, 100.0, 200.0, 12.0), BigDecimal.valueOf(352.0),
|
||||
List.of(PRINCIPAL, FEE, PENALTY, INTEREST), currency);
|
||||
verify(allocationMap(40.0, 100.0, 200.0, 12.0), result);
|
||||
}
|
||||
|
||||
private void verify(Map<AllocationType, BigDecimal> expected, Map<AllocationType, Money> actual) {
|
||||
Assertions.assertEquals(expected.size(), actual.size());
|
||||
expected.forEach((k, v) -> {
|
||||
Assertions.assertEquals(0, v.compareTo(actual.get(k).getAmount()), "Not matching for " + k);
|
||||
});
|
||||
}
|
||||
|
||||
private Map<AllocationType, BigDecimal> allocationMap(double principal, double interest, double fee, double penalty) {
|
||||
Map<AllocationType, BigDecimal> allocationMap = new HashMap<>();
|
||||
allocationMap.put(AllocationType.PRINCIPAL, BigDecimal.valueOf(principal));
|
||||
allocationMap.put(AllocationType.INTEREST, BigDecimal.valueOf(interest));
|
||||
allocationMap.put(AllocationType.FEE, BigDecimal.valueOf(fee));
|
||||
allocationMap.put(AllocationType.PENALTY, BigDecimal.valueOf(penalty));
|
||||
return allocationMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user