FINERACT-2210: Incorrect accounting of reversed charge-off transaction.
This commit is contained in:
committed by
Adam Saghy
parent
b7ba9bd570
commit
957666df18
+3
-7
@@ -27,6 +27,7 @@ import jakarta.persistence.Table;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
@@ -54,6 +55,7 @@ public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@Column(name = "currency_code", length = 3, nullable = false)
|
@Column(name = "currency_code", length = 3, nullable = false)
|
||||||
private String currencyCode;
|
private String currencyCode;
|
||||||
|
|
||||||
|
@Setter
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "reversal_id")
|
@JoinColumn(name = "reversal_id")
|
||||||
private JournalEntry reversalJournalEntry;
|
private JournalEntry reversalJournalEntry;
|
||||||
@@ -73,6 +75,7 @@ public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@Column(name = "share_transaction_id")
|
@Column(name = "share_transaction_id")
|
||||||
private Long shareTransactionId;
|
private Long shareTransactionId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
@Column(name = "reversed", nullable = false)
|
@Column(name = "reversed", nullable = false)
|
||||||
private boolean reversed = false;
|
private boolean reversed = false;
|
||||||
|
|
||||||
@@ -151,11 +154,4 @@ public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return JournalEntryType.CREDIT.getValue().equals(this.type);
|
return JournalEntryType.CREDIT.getValue().equals(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReversalJournalEntry(final JournalEntry reversalJournalEntry) {
|
|
||||||
this.reversalJournalEntry = reversalJournalEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReversed(final boolean reversed) {
|
|
||||||
this.reversed = reversed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -105,6 +105,7 @@ public enum DefaultLoanProduct implements LoanProduct {
|
|||||||
LP2_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR_LAST_INSTALLMENT_STRATEGY, //
|
LP2_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR_LAST_INSTALLMENT_STRATEGY, //
|
||||||
LP2_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR_LAST_INSTALLMENT_STRATEGY, //
|
LP2_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR_LAST_INSTALLMENT_STRATEGY, //
|
||||||
LP2_ADV_PYMNT_INTEREST_DAILY_INT_RECALCULATION_ZERO_INT_CHARGE_OFF_INT_RECOGNITION_FROM_DISB_DATE, //
|
LP2_ADV_PYMNT_INTEREST_DAILY_INT_RECALCULATION_ZERO_INT_CHARGE_OFF_INT_RECOGNITION_FROM_DISB_DATE, //
|
||||||
|
LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON, //
|
||||||
;
|
;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+122
@@ -1250,4 +1250,126 @@ public class LoanProductsRequestFactory {
|
|||||||
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))//
|
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))//
|
||||||
.incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));//
|
.incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PostLoanProductsRequest defaultLoanProductsRequestLP2ChargeOffReasonToExpenseAccountMappings() {
|
||||||
|
final String name = Utils.randomNameGenerator(NAME_PREFIX_LP2, 4);
|
||||||
|
final String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX, 3);
|
||||||
|
|
||||||
|
final List<Integer> principalVariationsForBorrowerCycle = new ArrayList<>();
|
||||||
|
final List<Integer> numberOfRepaymentVariationsForBorrowerCycle = new ArrayList<>();
|
||||||
|
final List<Integer> interestRateVariationsForBorrowerCycle = new ArrayList<>();
|
||||||
|
final List<LoanProductChargeData> charges = new ArrayList<>();
|
||||||
|
final List<LoanProductChargeToGLAccountMapper> penaltyToIncomeAccountMappings = new ArrayList<>();
|
||||||
|
final List<LoanProductChargeToGLAccountMapper> feeToIncomeAccountMappings = new ArrayList<>();
|
||||||
|
|
||||||
|
final List<GetLoanPaymentChannelToFundSourceMappings> paymentChannelToFundSourceMappings = new ArrayList<>();
|
||||||
|
final GetLoanPaymentChannelToFundSourceMappings loanPaymentChannelToFundSourceMappings = new GetLoanPaymentChannelToFundSourceMappings();
|
||||||
|
loanPaymentChannelToFundSourceMappings.fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.FUND_RECEIVABLES));
|
||||||
|
loanPaymentChannelToFundSourceMappings.paymentTypeId(paymentTypeResolver.resolve(DefaultPaymentType.MONEY_TRANSFER));
|
||||||
|
paymentChannelToFundSourceMappings.add(loanPaymentChannelToFundSourceMappings);
|
||||||
|
|
||||||
|
final Long chargeOffReasonId = codeHelper.retrieveCodeByName(CHARGE_OFF_REASONS).getId();
|
||||||
|
|
||||||
|
final List<PostChargeOffReasonToExpenseAccountMappings> chargeOffReasonToExpenseAccountMappings = new ArrayList<>();
|
||||||
|
final PostChargeOffReasonToExpenseAccountMappings chargeOffDelinquentReason = new PostChargeOffReasonToExpenseAccountMappings();
|
||||||
|
chargeOffDelinquentReason.chargeOffReasonCodeValueId(codeValueResolver.resolve(chargeOffReasonId, DefaultCodeValue.DELINQUENT));
|
||||||
|
chargeOffDelinquentReason.expenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD));
|
||||||
|
chargeOffReasonToExpenseAccountMappings.add(chargeOffDelinquentReason);
|
||||||
|
|
||||||
|
return new PostLoanProductsRequest()//
|
||||||
|
.name(name)//
|
||||||
|
.shortName(shortName)//
|
||||||
|
.description(DESCRIPTION_LP2)//
|
||||||
|
.enableDownPayment(true)//
|
||||||
|
.enableAutoRepaymentForDownPayment(true)//
|
||||||
|
.disbursedAmountPercentageForDownPayment(new BigDecimal(25))//
|
||||||
|
.fundId(FUND_ID)//
|
||||||
|
.startDate(null)//
|
||||||
|
.closeDate(null)//
|
||||||
|
.includeInBorrowerCycle(false)//
|
||||||
|
.currencyCode(CURRENCY_CODE)//
|
||||||
|
.digitsAfterDecimal(2)//
|
||||||
|
.inMultiplesOf(0)//
|
||||||
|
.installmentAmountInMultiplesOf(1)//
|
||||||
|
.useBorrowerCycle(false)//
|
||||||
|
.minPrincipal(100.0)//
|
||||||
|
.principal(1000.0)//
|
||||||
|
.maxPrincipal(10000.0)//
|
||||||
|
.minNumberOfRepayments(1)//
|
||||||
|
.numberOfRepayments(3)//
|
||||||
|
.maxNumberOfRepayments(30)//
|
||||||
|
.isLinkedToFloatingInterestRates(false)//
|
||||||
|
.minInterestRatePerPeriod((double) 0)//
|
||||||
|
.interestRatePerPeriod((double) 0)//
|
||||||
|
.maxInterestRatePerPeriod((double) 0)//
|
||||||
|
.interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_MONTH)//
|
||||||
|
.repaymentEvery(15)//
|
||||||
|
.repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_DAYS)//
|
||||||
|
.principalVariationsForBorrowerCycle(principalVariationsForBorrowerCycle)//
|
||||||
|
.numberOfRepaymentVariationsForBorrowerCycle(numberOfRepaymentVariationsForBorrowerCycle)//
|
||||||
|
.interestRateVariationsForBorrowerCycle(interestRateVariationsForBorrowerCycle)//
|
||||||
|
.amortizationType(AMORTIZATION_TYPE)//
|
||||||
|
.interestType(INTEREST_TYPE_DECLINING_BALANCE)//
|
||||||
|
.isEqualAmortization(false)//
|
||||||
|
.interestCalculationPeriodType(INTEREST_CALCULATION_PERIOD_TYPE_SAME_AS_REPAYMENT)//
|
||||||
|
.transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE)//
|
||||||
|
.daysInYearType(DAYS_IN_YEAR_TYPE)//
|
||||||
|
.daysInMonthType(DAYS_IN_MONTH_TYPE)//
|
||||||
|
.canDefineInstallmentAmount(true)//
|
||||||
|
.graceOnArrearsAgeing(3)//
|
||||||
|
.overdueDaysForNPA(179)//
|
||||||
|
.accountMovesOutOfNPAOnlyOnArrearsCompletion(false)//
|
||||||
|
.principalThresholdForLastInstallment(50)//
|
||||||
|
.allowVariableInstallments(false)//
|
||||||
|
.canUseForTopup(false)//
|
||||||
|
.isInterestRecalculationEnabled(false)//
|
||||||
|
.holdGuaranteeFunds(false)//
|
||||||
|
.multiDisburseLoan(true)//
|
||||||
|
.allowAttributeOverrides(new AllowAttributeOverrides()//
|
||||||
|
.amortizationType(true)//
|
||||||
|
.interestType(true)//
|
||||||
|
.transactionProcessingStrategyCode(true)//
|
||||||
|
.interestCalculationPeriodType(true)//
|
||||||
|
.inArrearsTolerance(true)//
|
||||||
|
.repaymentEvery(true)//
|
||||||
|
.graceOnPrincipalAndInterestPayment(true)//
|
||||||
|
.graceOnArrearsAgeing(true))//
|
||||||
|
.allowPartialPeriodInterestCalcualtion(true)//
|
||||||
|
.maxTrancheCount(10)//
|
||||||
|
.outstandingLoanBalance(10000.0)//
|
||||||
|
.charges(charges)//
|
||||||
|
.accountingRule(LOAN_ACCOUNTING_RULE)//
|
||||||
|
.fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.SUSPENSE_CLEARING_ACCOUNT))//
|
||||||
|
.loanPortfolioAccountId(accountTypeResolver.resolve(DefaultAccountType.LOANS_RECEIVABLE))//
|
||||||
|
.transfersInSuspenseAccountId(accountTypeResolver.resolve(DefaultAccountType.TRANSFER_IN_SUSPENSE_ACCOUNT))//
|
||||||
|
.interestOnLoanAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME))//
|
||||||
|
.incomeFromFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
|
||||||
|
.incomeFromPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
|
||||||
|
.incomeFromRecoveryAccountId(accountTypeResolver.resolve(DefaultAccountType.RECOVERIES))//
|
||||||
|
.writeOffAccountId(accountTypeResolver.resolve(DefaultAccountType.WRITTEN_OFF))//
|
||||||
|
.overpaymentLiabilityAccountId(accountTypeResolver.resolve(DefaultAccountType.OVERPAYMENT_ACCOUNT))//
|
||||||
|
.receivableInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
|
||||||
|
.receivableFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
|
||||||
|
.receivablePenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
|
||||||
|
.dateFormat(DATE_FORMAT)//
|
||||||
|
.locale(LOCALE_EN)//
|
||||||
|
.disallowExpectedDisbursements(true)//
|
||||||
|
.allowApprovedDisbursedAmountsOverApplied(true)//
|
||||||
|
.overAppliedCalculationType(OVER_APPLIED_CALCULATION_TYPE)//
|
||||||
|
.overAppliedNumber(OVER_APPLIED_NUMBER)//
|
||||||
|
.delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue())//
|
||||||
|
.goodwillCreditAccountId(accountTypeResolver.resolve(DefaultAccountType.GOODWILL_EXPENSE_ACCOUNT))//
|
||||||
|
.incomeFromGoodwillCreditInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME_CHARGE_OFF))//
|
||||||
|
.incomeFromGoodwillCreditFeesAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
|
||||||
|
.incomeFromGoodwillCreditPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
|
||||||
|
.paymentChannelToFundSourceMappings(paymentChannelToFundSourceMappings)//
|
||||||
|
.penaltyToIncomeAccountMappings(penaltyToIncomeAccountMappings)//
|
||||||
|
.feeToIncomeAccountMappings(feeToIncomeAccountMappings)//
|
||||||
|
.incomeFromChargeOffInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME_CHARGE_OFF))//
|
||||||
|
.incomeFromChargeOffFeesAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
|
||||||
|
.chargeOffExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT))//
|
||||||
|
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT))//
|
||||||
|
.chargeOffReasonToExpenseAccountMappings(chargeOffReasonToExpenseAccountMappings)//
|
||||||
|
.incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));//
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
@@ -1975,6 +1975,34 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
|
|||||||
.createLoanProduct(loanProductsRequestInterest36030DecliningPeriodDailyIntRecalc).execute();
|
.createLoanProduct(loanProductsRequestInterest36030DecliningPeriodDailyIntRecalc).execute();
|
||||||
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_360_30__DECLINING_PERIOD_DAILY_INT_RECALC,
|
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_360_30__DECLINING_PERIOD_DAILY_INT_RECALC,
|
||||||
responseInterest36030DecliningPeriodDailyIntRecalc);
|
responseInterest36030DecliningPeriodDailyIntRecalc);
|
||||||
|
|
||||||
|
// LP2 + zero-interest chargeOff behaviour + progressive loan schedule + horizontal + delinquent charge-off
|
||||||
|
// reason to GL account mapping
|
||||||
|
// (LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON)
|
||||||
|
final String name83 = DefaultLoanProduct.LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON.getName();
|
||||||
|
|
||||||
|
final PostLoanProductsRequest loanProductsRequestAdvZeroInterestChargeOffProgressiveDelinquentReason = loanProductsRequestFactory
|
||||||
|
.defaultLoanProductsRequestLP2ChargeOffReasonToExpenseAccountMappings()//
|
||||||
|
.name(name83)//
|
||||||
|
.enableDownPayment(false)//
|
||||||
|
.enableAutoRepaymentForDownPayment(null)//
|
||||||
|
.disbursedAmountPercentageForDownPayment(null)//
|
||||||
|
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())//
|
||||||
|
.loanScheduleType("PROGRESSIVE") //
|
||||||
|
.loanScheduleProcessingType("HORIZONTAL")//
|
||||||
|
.interestRateFrequencyType(3)//
|
||||||
|
.maxInterestRatePerPeriod(10.0)//
|
||||||
|
.paymentAllocation(List.of(//
|
||||||
|
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), //
|
||||||
|
createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), //
|
||||||
|
createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), //
|
||||||
|
createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")))//
|
||||||
|
.chargeOffBehaviour("ZERO_INTEREST");//
|
||||||
|
final Response<PostLoanProductsResponse> responseLoanProductsRequestAdvZeroInterestChargeOffProgressiveDelinquentReason = loanProductsApi
|
||||||
|
.createLoanProduct(loanProductsRequestAdvZeroInterestChargeOffProgressiveDelinquentReason).execute();
|
||||||
|
TestContext.INSTANCE.set(
|
||||||
|
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON,
|
||||||
|
responseLoanProductsRequestAdvZeroInterestChargeOffProgressiveDelinquentReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
|
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
|
||||||
|
|||||||
+1
@@ -116,6 +116,7 @@ public abstract class TestContextKey {
|
|||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationZeroInterestChargeOff";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationZeroInterestChargeOff";
|
||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviour";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviour";
|
||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOff";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOff";
|
||||||
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffDelinquentReason";
|
||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAllowPartialPeriod";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAllowPartialPeriod";
|
||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAccrualActivityPosting";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAccrualActivityPosting";
|
||||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030ChargebackInterestFeePrincipal";
|
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030ChargebackInterestFeePrincipal";
|
||||||
|
|||||||
@@ -7542,3 +7542,45 @@ Feature: Charge-off
|
|||||||
| 20 January 2024 | Charge-off | 790.71 | 757.67 | 33.04 | 0.0 | 0.0 | 0.0 | false | false |
|
| 20 January 2024 | Charge-off | 790.71 | 757.67 | 33.04 | 0.0 | 0.0 | 0.0 | false | false |
|
||||||
Then Loan marked as charged-off on "20 January 2024"
|
Then Loan marked as charged-off on "20 January 2024"
|
||||||
Then LoanAccrualAdjustmentTransactionBusinessEvent is raised on "20 January 2024"
|
Then LoanAccrualAdjustmentTransactionBusinessEvent is raised on "20 January 2024"
|
||||||
|
|
||||||
|
@TestRailId:C3567
|
||||||
|
Scenario: Charge-off reversal on a fraud loan respects GL mapping based on charge-off reason
|
||||||
|
When Admin sets the business date to "1 January 2024"
|
||||||
|
And Admin creates a client with random data
|
||||||
|
And Admin creates a fully customized loan with the following data:
|
||||||
|
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||||
|
| LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||||
|
Then Loan Repayment schedule has 6 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | | | | 0.0 |
|
||||||
|
| 1 | 31 | 01 February 2024 | | 83.59 | 16.41 | 0.59 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||||
|
| 2 | 29 | 01 March 2024 | | 67.05 | 16.54 | 0.46 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||||
|
| 3 | 31 | 01 April 2024 | | 50.45 | 16.6 | 0.4 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||||
|
| 4 | 30 | 01 May 2024 | | 33.74 | 16.71 | 0.29 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||||
|
| 5 | 31 | 01 June 2024 | | 16.94 | 16.8 | 0.2 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||||
|
| 6 | 30 | 01 July 2024 | | 0.0 | 16.94 | 0.1 | 0.0 | 0.0 | 17.04 | 0.0 | 0.0 | 0.0 | 17.04 |
|
||||||
|
Then Loan Repayment schedule has the following data in Total row:
|
||||||
|
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| 100 | 2.04 | 0 | 0 | 102.04 | 0 | 0 | 0 | 102.04 |
|
||||||
|
And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024"
|
||||||
|
And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount
|
||||||
|
Then Admin can successfully set Fraud flag to the loan
|
||||||
|
When Admin sets the business date to "03 February 2024"
|
||||||
|
And Admin does charge-off the loan with reason "DELINQUENT" on "03 February 2024"
|
||||||
|
Then Loan Transactions tab has a "CHARGE_OFF" transaction with date "03 February 2024" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | | 100.0 |
|
||||||
|
| ASSET | 112603 | Interest/Fee Receivable | | 0.62 |
|
||||||
|
| EXPENSE | 744037 | Credit Loss/Bad Debt-Fraud | 100.0 | |
|
||||||
|
| INCOME | 404001 | Interest Income Charge Off | 0.62 | |
|
||||||
|
Then Admin does a charge-off undo the loan
|
||||||
|
Then Loan Transactions tab has a "CHARGE_OFF" transaction with date "03 February 2024" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | | 100.0 |
|
||||||
|
| ASSET | 112601 | Loans Receivable | 100.0 | |
|
||||||
|
| ASSET | 112603 | Interest/Fee Receivable | | 0.62 |
|
||||||
|
| ASSET | 112603 | Interest/Fee Receivable | 0.62 | |
|
||||||
|
| EXPENSE | 744037 | Credit Loss/Bad Debt-Fraud | 100.0 | |
|
||||||
|
| EXPENSE | 744037 | Credit Loss/Bad Debt-Fraud | | 100.0 |
|
||||||
|
| INCOME | 404001 | Interest Income Charge Off | 0.62 | |
|
||||||
|
| INCOME | 404001 | Interest Income Charge Off | | 0.62 |
|
||||||
|
|||||||
+84
-164
@@ -68,14 +68,11 @@ import org.apache.fineract.portfolio.PortfolioProductType;
|
|||||||
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
||||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientTransaction;
|
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientTransactionRepository;
|
import org.apache.fineract.portfolio.client.domain.ClientTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
@@ -356,15 +353,12 @@ public class AccountingProcessorHelper {
|
|||||||
* transactionDate
|
* transactionDate
|
||||||
* @param totalAmount
|
* @param totalAmount
|
||||||
* totalAmount
|
* totalAmount
|
||||||
* @param isReversal
|
|
||||||
* isReversal
|
|
||||||
* @param chargePaymentDTOs
|
* @param chargePaymentDTOs
|
||||||
* chargePaymentDTOs
|
* chargePaymentDTOs
|
||||||
*/
|
*/
|
||||||
public void createJournalEntriesAndReversalsForLoanCharges(final Office office, final String currencyCode,
|
public void createJournalEntriesForLoanCharges(final Office office, final String currencyCode, final Integer accountTypeToBeDebited,
|
||||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long loanId,
|
final Integer accountTypeToBeCredited, final Long loanProductId, final Long loanId, final String transactionId,
|
||||||
final String transactionId, final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
final LocalDate transactionDate, final BigDecimal totalAmount, final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
|
||||||
|
|
||||||
GLAccount receivableAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountTypeToBeDebited, null);
|
GLAccount receivableAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountTypeToBeDebited, null);
|
||||||
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
||||||
@@ -387,13 +381,8 @@ public class AccountingProcessorHelper {
|
|||||||
final GLAccount account = entry.getKey();
|
final GLAccount account = entry.getKey();
|
||||||
final BigDecimal amount = entry.getValue();
|
final BigDecimal amount = entry.getValue();
|
||||||
totalCreditedAmount = totalCreditedAmount.add(amount);
|
totalCreditedAmount = totalCreditedAmount.add(amount);
|
||||||
if (isReversal) {
|
createDebitJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
|
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalAmount.compareTo(totalCreditedAmount) != 0) {
|
if (totalAmount.compareTo(totalCreditedAmount) != 0) {
|
||||||
@@ -453,61 +442,43 @@ public class AccountingProcessorHelper {
|
|||||||
* @param transactionId
|
* @param transactionId
|
||||||
* @param transactionDate
|
* @param transactionDate
|
||||||
* @param amount
|
* @param amount
|
||||||
* @param isReversal
|
|
||||||
*/
|
*/
|
||||||
public void createJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode,
|
public void createJournalEntriesForLoan(final Office office, final String currencyCode, final Integer accountTypeToBeDebited,
|
||||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId,
|
final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||||
final Long loanId, final String transactionId, final LocalDate transactionDate, final BigDecimal amount,
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
final Boolean isReversal) {
|
|
||||||
int accountTypeToDebitId = accountTypeToBeDebited;
|
int accountTypeToDebitId = accountTypeToBeDebited;
|
||||||
int accountTypeToCreditId = accountTypeToBeCredited;
|
int accountTypeToCreditId = accountTypeToBeCredited;
|
||||||
// reverse debits and credits for reversals
|
|
||||||
if (isReversal) {
|
|
||||||
accountTypeToDebitId = accountTypeToBeCredited;
|
|
||||||
accountTypeToCreditId = accountTypeToBeDebited;
|
|
||||||
}
|
|
||||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
|
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
|
||||||
transactionId, transactionDate, amount);
|
transactionId, transactionDate, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createSplitJournalEntriesAndReversalsForLoan(Office office, String currencyCode,
|
public void createSplitJournalEntriesForLoan(Office office, String currencyCode, List<JournalAmountHolder> splitAccountsHolder,
|
||||||
List<JournalAmountHolder> splitAccountsHolder, JournalAmountHolder totalAccountHolder, Long loanProductId, Long paymentTypeId,
|
JournalAmountHolder totalAccountHolder, Long loanProductId, Long paymentTypeId, Long loanId, String transactionId,
|
||||||
Long loanId, String transactionId, LocalDate transactionDate, Boolean isReversal) {
|
LocalDate transactionDate) {
|
||||||
splitAccountsHolder.forEach(journalItemHolder -> {
|
splitAccountsHolder.forEach(journalItemHolder -> {
|
||||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, journalItemHolder.getAccountType(), paymentTypeId);
|
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, journalItemHolder.getAccountType(), paymentTypeId);
|
||||||
if (isReversal) {
|
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
journalItemHolder.getAmount());
|
||||||
journalItemHolder.getAmount());
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
|
||||||
journalItemHolder.getAmount());
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
final GLAccount totalAccount = getLinkedGLAccountForLoanProduct(loanProductId, totalAccountHolder.getAccountType(), paymentTypeId);
|
final GLAccount totalAccount = getLinkedGLAccountForLoanProduct(loanProductId, totalAccountHolder.getAccountType(), paymentTypeId);
|
||||||
if (isReversal) {
|
createCreditJournalEntryForLoan(office, currencyCode, totalAccount, loanId, transactionId, transactionDate,
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, totalAccount, loanId, transactionId, transactionDate,
|
totalAccountHolder.getAmount());
|
||||||
totalAccountHolder.getAmount());
|
|
||||||
} else {
|
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, totalAccount, loanId, transactionId, transactionDate,
|
|
||||||
totalAccountHolder.getAmount());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode,
|
public void createCreditJournalEntryForLoan(final Office office, final String currencyCode,
|
||||||
final CashAccountsForLoan accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
final CashAccountsForLoan accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
final int accountMappingTypeId = accountMappingType.getValue();
|
final int accountMappingTypeId = accountMappingType.getValue();
|
||||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId,
|
createCreditJournalEntryForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
transactionId, transactionDate, amount, isReversal);
|
transactionDate, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode,
|
public void createCreditJournalEntryForLoan(final Office office, final String currencyCode,
|
||||||
final AccrualAccountsForLoan accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
final AccrualAccountsForLoan accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
final int accountMappingTypeId = accountMappingType.getValue();
|
final int accountMappingTypeId = accountMappingType.getValue();
|
||||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId,
|
createCreditJournalEntryForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
transactionId, transactionDate, amount, isReversal);
|
transactionDate, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -635,18 +606,6 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCashBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
|
||||||
final Long debitAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
|
||||||
final BigDecimal amount, final Boolean isReversal) {
|
|
||||||
// reverse debits and credits for reversals
|
|
||||||
final GLAccount debitAccount = getGLAccountById(debitAccountId);
|
|
||||||
if (isReversal) {
|
|
||||||
createCreditJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createCashBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
public void createCashBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||||
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||||
final BigDecimal amount, final Boolean isReversal) {
|
final BigDecimal amount, final Boolean isReversal) {
|
||||||
@@ -685,18 +644,6 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createAccrualBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
|
||||||
final Long debitAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
|
||||||
final BigDecimal amount, final Boolean isReversal) {
|
|
||||||
// reverse debits and credits for reversals
|
|
||||||
final GLAccount debitAccount = getGLAccountById(debitAccountId);
|
|
||||||
if (isReversal) {
|
|
||||||
createCreditJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
public void createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||||
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||||
final BigDecimal amount, final Boolean isReversal) {
|
final BigDecimal amount, final Boolean isReversal) {
|
||||||
@@ -723,80 +670,37 @@ public class AccountingProcessorHelper {
|
|||||||
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId,
|
public void createDebitJournalEntryForLoan(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
||||||
if (isReversal) {
|
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
|
public void createDebitJournalEntryForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal,
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final GLAccount account) {
|
||||||
final GLAccount account) {
|
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
if (isReversal) {
|
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createDebitJournalEntryOrReversalForLoanCharges(final Office office, final String currencyCode,
|
public void createDebitJournalEntryForLoanCharges(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
final int accountMappingTypeId, final Long loanProductId, final Long chargeId, final Long loanId, final String transactionId,
|
final Long loanProductId, final Long chargeId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
final BigDecimal amount) {
|
||||||
final GLAccount account = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
|
final GLAccount account = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
|
||||||
if (isReversal) {
|
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCreditJournalEntryOrReversalForLoanCharges(final Office office, final String currencyCode,
|
public void createCreditJournalEntryForLoanCharges(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
final int accountMappingTypeId, final Long loanProductId, final Long loanId, final String transactionId,
|
final Long loanProductId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||||
final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
final BigDecimal totalAmount, final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
createJournalEntriesForLoanChargesInternal(office, currencyCode, accountMappingTypeId, loanProductId, loanId, transactionId,
|
||||||
/***
|
transactionDate, totalAmount, chargePaymentDTOs, true);
|
||||||
* Map to track each account and the net credit to be made for a particular account
|
}
|
||||||
***/
|
|
||||||
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
|
||||||
for (final ChargePaymentDTO chargePaymentDTO : chargePaymentDTOs) {
|
|
||||||
final Long chargeId = chargePaymentDTO.getChargeId();
|
|
||||||
final GLAccount chargeSpecificAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
|
|
||||||
BigDecimal chargeSpecificAmount = chargePaymentDTO.getAmount();
|
|
||||||
|
|
||||||
// adjust net credit amount if the account is already present in the
|
public void createDebitJournalEntryForLoanCharges(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
// map
|
final Long loanProductId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||||
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
|
final BigDecimal totalAmount, final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||||
final BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
|
createJournalEntriesForLoanChargesInternal(office, currencyCode, accountMappingTypeId, loanProductId, loanId, transactionId,
|
||||||
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
|
transactionDate, totalAmount, chargePaymentDTOs, false);
|
||||||
}
|
|
||||||
creditDetailsMap.put(chargeSpecificAccount, chargeSpecificAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
|
|
||||||
for (final Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
|
|
||||||
final GLAccount account = entry.getKey();
|
|
||||||
final BigDecimal amount = entry.getValue();
|
|
||||||
totalCreditedAmount = totalCreditedAmount.add(amount);
|
|
||||||
if (isReversal) {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Vishwas Temporary validation to be removed before moving to
|
|
||||||
// release branch
|
|
||||||
if (totalAmount.compareTo(totalCreditedAmount) != 0) {
|
|
||||||
throw new PlatformDataIntegrityException(
|
|
||||||
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
|
|
||||||
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
|
|
||||||
totalCreditedAmount, totalAmount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -899,38 +803,20 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanTransaction getLoanTransactionById(final Long loanTransactionId) {
|
|
||||||
return this.loanTransactionRepository.getReferenceById(loanTransactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SavingsAccountTransaction getSavingsTransactionById(final Long savingsTransactionId) {
|
|
||||||
return this.savingsAccountTransactionRepository.getReferenceById(savingsTransactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientTransaction getClientTransactionById(final Long clientTransactionId) {
|
|
||||||
return this.clientTransactionRepository.getReferenceById(clientTransactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Office getOfficeById(final long officeId) {
|
public Office getOfficeById(final long officeId) {
|
||||||
return this.officeRepository.getReferenceById(officeId);
|
return this.officeRepository.getReferenceById(officeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId,
|
public void createCreditJournalEntryForLoan(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
||||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, isReversal,
|
createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, account);
|
||||||
account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
|
public void createCreditJournalEntryForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal,
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final GLAccount account) {
|
||||||
final GLAccount account) {
|
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
if (isReversal) {
|
|
||||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
} else {
|
|
||||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCreditJournalEntryForClientPayments(final Office office, final String currencyCode, final GLAccount account,
|
private void createCreditJournalEntryForClientPayments(final Office office, final String currencyCode, final GLAccount account,
|
||||||
@@ -1403,4 +1289,38 @@ public class AccountingProcessorHelper {
|
|||||||
return savedJournalEntry;
|
return savedJournalEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createJournalEntriesForLoanChargesInternal(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||||
|
final Long loanProductId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||||
|
final BigDecimal totalAmount, final List<ChargePaymentDTO> chargePaymentDTOs, final boolean isCredit) {
|
||||||
|
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (final ChargePaymentDTO chargePaymentDTO : chargePaymentDTOs) {
|
||||||
|
final Long chargeId = chargePaymentDTO.getChargeId();
|
||||||
|
final GLAccount account = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
|
||||||
|
BigDecimal amount = chargePaymentDTO.getAmount();
|
||||||
|
|
||||||
|
creditDetailsMap.merge(account, amount, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
|
||||||
|
GLAccount account = entry.getKey();
|
||||||
|
BigDecimal amount = entry.getValue();
|
||||||
|
totalCreditedAmount = totalCreditedAmount.add(amount);
|
||||||
|
|
||||||
|
if (isCredit) {
|
||||||
|
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
|
} else {
|
||||||
|
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalAmount.compareTo(totalCreditedAmount) != 0) {
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
|
||||||
|
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
|
||||||
|
totalCreditedAmount, totalAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+148
-157
@@ -46,16 +46,24 @@ import org.springframework.stereotype.Component;
|
|||||||
public class AccrualBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
public class AccrualBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
||||||
|
|
||||||
private final AccountingProcessorHelper helper;
|
private final AccountingProcessorHelper helper;
|
||||||
|
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
|
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
|
||||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
|
final Long officeId = loanDTO.getOfficeId();
|
||||||
final Office office = this.helper.getOfficeById(loanDTO.getOfficeId());
|
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(officeId);
|
||||||
|
final Office office = this.helper.getOfficeById(officeId);
|
||||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||||
final LoanTransactionEnumData transactionType = loanTransactionDTO.getTransactionType();
|
final LoanTransactionEnumData transactionType = loanTransactionDTO.getTransactionType();
|
||||||
|
|
||||||
|
if (loanTransactionDTO.isReversed()) {
|
||||||
|
journalEntryWritePlatformService.createJournalEntryForReversedLoanTransaction(transactionDate,
|
||||||
|
loanTransactionDTO.getTransactionId(), officeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Disbursements
|
// Handle Disbursements
|
||||||
if (transactionType.isDisbursement()) {
|
if (transactionType.isDisbursement()) {
|
||||||
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
||||||
@@ -67,8 +75,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle repayments, loan refunds, repayments at disbursement and reversal of Repayments and Repayments at
|
* Handle repayments, loan refunds, repayments at disbursement (except charge adjustment)
|
||||||
* disbursement (except charge adjustment)
|
|
||||||
*/
|
*/
|
||||||
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
||||||
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
||||||
@@ -91,7 +98,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
createJournalEntriesForCreditBalanceRefund(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForCreditBalanceRefund(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Write Offs, waivers and their reversals
|
// Handle Write Offs
|
||||||
else if ((transactionType.isWriteOff() || transactionType.isWaiveInterest() || transactionType.isWaiveCharges())) {
|
else if ((transactionType.isWriteOff() || transactionType.isWaiveInterest() || transactionType.isWaiveCharges())) {
|
||||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
|
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
|
||||||
}
|
}
|
||||||
@@ -135,7 +142,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPayment = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPayment = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
if (isMarkedAsChargeOff) {
|
if (isMarkedAsChargeOff) {
|
||||||
@@ -202,14 +208,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), isReversal, glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||||
debitEntry.getValue(), isReversal, glAccount);
|
glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +233,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
// need to fetch if there are account mappings (always one)
|
// need to fetch if there are account mappings (always one)
|
||||||
@@ -272,14 +277,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), isReversal, glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||||
debitEntry.getValue(), isReversal, glAccount);
|
glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +323,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
@@ -386,8 +390,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
entry.getValue(), isReversal, entry.getKey());
|
entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -398,8 +402,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
} else {
|
} else {
|
||||||
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||||
}
|
}
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,13 +422,12 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// handle principal payment (and reversals)
|
// handle principal payment
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -432,7 +435,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
accountMap.put(account, principalAmount);
|
accountMap.put(account, principalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle interest payment (and reversals)
|
// handle interest payment
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -445,7 +448,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle fees payment (and reversals)
|
// handle fees payment
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -458,7 +461,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle penalties payment (and reversals)
|
// handle penalties payment
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -485,8 +488,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
entry.getValue(), isReversal, entry.getKey());
|
entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -497,8 +500,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
} else {
|
} else {
|
||||||
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||||
}
|
}
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,7 +522,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final BigDecimal overpaidAmount = Objects.isNull(loanTransactionDTO.getOverPayment()) ? BigDecimal.ZERO
|
final BigDecimal overpaidAmount = Objects.isNull(loanTransactionDTO.getOverPayment()) ? BigDecimal.ZERO
|
||||||
: loanTransactionDTO.getOverPayment();
|
: loanTransactionDTO.getOverPayment();
|
||||||
@@ -536,36 +538,36 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltyPaid = Objects.isNull(loanTransactionDTO.getPenaltyPaid()) ? BigDecimal.ZERO
|
final BigDecimal penaltyPaid = Objects.isNull(loanTransactionDTO.getPenaltyPaid()) ? BigDecimal.ZERO
|
||||||
: loanTransactionDTO.getPenaltyPaid();
|
: loanTransactionDTO.getPenaltyPaid();
|
||||||
|
|
||||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId,
|
helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId, paymentTypeId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, amount, isReversal);
|
loanId, transactionId, transactionDate, amount);
|
||||||
|
|
||||||
if (overpaidAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (overpaidAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaidAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, overpaidAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (principalCredited.compareTo(principalPaid) > 0) {
|
if (principalCredited.compareTo(principalPaid) > 0) {
|
||||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId,
|
helper.createDebitJournalEntryForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, principalCredited.subtract(principalPaid), isReversal);
|
transactionId, transactionDate, principalCredited.subtract(principalPaid));
|
||||||
} else if (principalCredited.compareTo(principalPaid) < 0) {
|
} else if (principalCredited.compareTo(principalPaid) < 0) {
|
||||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId,
|
helper.createCreditJournalEntryForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, principalPaid.subtract(principalCredited), isReversal);
|
transactionId, transactionDate, principalPaid.subtract(principalCredited));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feeCredited.compareTo(feePaid) > 0) {
|
if (feeCredited.compareTo(feePaid) > 0) {
|
||||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId,
|
helper.createDebitJournalEntryForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
loanId, transactionId, transactionDate, feeCredited.subtract(feePaid), isReversal);
|
transactionId, transactionDate, feeCredited.subtract(feePaid));
|
||||||
} else if (feeCredited.compareTo(feePaid) < 0) {
|
} else if (feeCredited.compareTo(feePaid) < 0) {
|
||||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId,
|
helper.createCreditJournalEntryForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
loanId, transactionId, transactionDate, feePaid.subtract(feeCredited), isReversal);
|
transactionId, transactionDate, feePaid.subtract(feeCredited));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (penaltyCredited.compareTo(penaltyPaid) > 0) {
|
if (penaltyCredited.compareTo(penaltyPaid) > 0) {
|
||||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId,
|
helper.createDebitJournalEntryForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
loanId, transactionId, transactionDate, penaltyCredited.subtract(penaltyPaid), isReversal);
|
transactionId, transactionDate, penaltyCredited.subtract(penaltyPaid));
|
||||||
} else if (penaltyCredited.compareTo(penaltyPaid) < 0) {
|
} else if (penaltyCredited.compareTo(penaltyPaid) < 0) {
|
||||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId,
|
helper.createCreditJournalEntryForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||||
loanId, transactionId, transactionDate, penaltyPaid.subtract(penaltyCredited), isReversal);
|
transactionId, transactionDate, penaltyPaid.subtract(penaltyCredited));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,29 +618,27 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
||||||
: BigDecimal.ZERO;
|
: BigDecimal.ZERO;
|
||||||
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
||||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
// create journal entries for the disbursement (or disbursement
|
// create journal entries for the disbursement
|
||||||
// reversal)
|
|
||||||
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion, isReversed);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion, isReversed);
|
paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion);
|
||||||
}
|
}
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
} else {
|
} else {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,7 +667,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
* <b>Penalty Write off</b>: Debits "Losses Written off" and Credits "Receivable Penalties" <br/>
|
* <b>Penalty Write off</b>: Debits "Losses Written off" and Credits "Receivable Penalties" <br/>
|
||||||
* <br/>
|
* <br/>
|
||||||
* <br/>
|
* <br/>
|
||||||
* In case the loan transaction has been reversed, all debits are turned into credits and vice versa
|
|
||||||
*
|
*
|
||||||
* @param loanTransactionDTO
|
* @param loanTransactionDTO
|
||||||
* @param loanDTO
|
* @param loanDTO
|
||||||
@@ -701,7 +700,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
@@ -801,9 +799,9 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (isIncomeFromFee) {
|
if (isIncomeFromFee) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode,
|
||||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId);
|
||||||
glAccountBalanceHolder.addToDebit(debitAccount, feesAmount);
|
glAccountBalanceHolder.addToDebit(debitAccount, feesAmount);
|
||||||
@@ -879,44 +877,41 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), isReversal, glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
if (writeOff) {
|
if (writeOff) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||||
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
transactionDate, totalDebitAmount, isReversal);
|
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
transactionDate, totalDebitAmount, isReversal);
|
|
||||||
} else {
|
} else {
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
debitEntry.getValue(), isReversal, glAccount);
|
debitEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||||
* those related to the repayment above
|
* repayment above
|
||||||
***/
|
***/
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
totalDebitAmount, isReversal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,14 +933,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
Map<Integer, BigDecimal> debitAccountMapForGoodwillCredit = new LinkedHashMap<>();
|
Map<Integer, BigDecimal> debitAccountMapForGoodwillCredit = new LinkedHashMap<>();
|
||||||
|
|
||||||
// handle principal payment or writeOff (and reversals)
|
// handle principal payment or writeOff
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -957,7 +951,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle interest payment of writeOff (and reversals)
|
// handle interest payment of writeOff
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -975,15 +969,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle fees payment of writeOff (and reversals)
|
// handle fees payment of writeOff
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
|
|
||||||
if (isIncomeFromFee) {
|
if (isIncomeFromFee) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
|
||||||
} else {
|
} else {
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
@@ -1000,7 +993,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle penalties payment of writeOff (and reversals)
|
// handle penalties payment of writeOff
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
if (isIncomeFromFee) {
|
if (isIncomeFromFee) {
|
||||||
@@ -1047,53 +1040,48 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
entry.getValue(), isReversal, entry.getKey());
|
entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single DEBIT transaction for write-offs or Repayments (and their reversals)
|
* Single DEBIT transaction for write-offs or Repayments
|
||||||
***/
|
***/
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
if (writeOff) {
|
if (writeOff) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||||
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
transactionDate, totalDebitAmount, isReversal);
|
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
transactionDate, totalDebitAmount, isReversal);
|
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue());
|
||||||
isReversal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
transactionDate, totalDebitAmount, isReversal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||||
* those related to the repayment above
|
* repayment above
|
||||||
***/
|
***/
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
totalDebitAmount, isReversal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1120,8 +1108,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a single Debit to fund source and a single credit to "Income from Recovery"
|
* Create a single Debit to fund source and a single credit to "Income from Recovery"
|
||||||
*
|
|
||||||
* In case the loan transaction is a reversal, all debits are turned into credits and vice versa
|
|
||||||
*/
|
*/
|
||||||
private void createJournalEntriesForRecoveryRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForRecoveryRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
final Office office) {
|
final Office office) {
|
||||||
@@ -1134,12 +1120,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
transactionDate, amount, isReversal);
|
transactionDate, amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1151,8 +1136,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
*
|
*
|
||||||
* <b>Penalties:</b> Debit <i>Penalties Receivable</i> and credit <i>Income from Penalties</i>
|
* <b>Penalties:</b> Debit <i>Penalties Receivable</i> and credit <i>Income from Penalties</i>
|
||||||
*
|
*
|
||||||
* Also handles reversals for both fees and payment applications
|
|
||||||
*
|
|
||||||
* @param loanDTO
|
* @param loanDTO
|
||||||
* @param loanTransactionDTO
|
* @param loanTransactionDTO
|
||||||
* @param office
|
* @param office
|
||||||
@@ -1170,28 +1153,43 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final boolean isReversed = transactionType.isAccrualAdjustment() != loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
// create journal entries for recognizing interest (or reversal)
|
// create journal entries for recognizing interest
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(),
|
if (transactionType.isAccrualAdjustment()) {
|
||||||
AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||||
transactionDate, interestAmount, isReversed);
|
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
|
transactionDate, interestAmount);
|
||||||
|
} else {
|
||||||
|
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(),
|
||||||
|
AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
|
transactionDate, interestAmount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// create journal entries for the fees application (or reversal)
|
// create journal entries for the fees application
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
|
if (transactionType.isAccrualAdjustment()) {
|
||||||
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId,
|
this.helper.createJournalEntriesForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
loanId, transactionId, transactionDate, feesAmount, isReversed, loanTransactionDTO.getFeePayments());
|
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||||
|
feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
|
} else {
|
||||||
|
this.helper.createJournalEntriesForLoanCharges(office, currencyCode, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(),
|
||||||
|
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||||
|
feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// create journal entries for the penalties application (or reversal)
|
// create journal entries for the penalties application
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
if (transactionType.isAccrualAdjustment()) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
|
this.helper.createJournalEntriesForLoanCharges(office, currencyCode,
|
||||||
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(),
|
||||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed,
|
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, loanTransactionDTO.getPenaltyPayments());
|
||||||
loanTransactionDTO.getPenaltyPayments());
|
} else {
|
||||||
|
this.helper.createJournalEntriesForLoanCharges(office, currencyCode, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(),
|
||||||
|
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||||
|
penaltiesAmount, loanTransactionDTO.getPenaltyPayments());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1205,17 +1203,16 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
if (loanTransactionDTO.isAccountTransfer()) {
|
if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||||
refundAmount, isReversal);
|
refundAmount);
|
||||||
} else {
|
} else {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||||
refundAmount, isReversal);
|
refundAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,7 +1233,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
// transaction properties
|
// transaction properties
|
||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
@@ -1257,8 +1253,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(AccrualAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(AccrualAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
||||||
helper.createSplitJournalEntriesAndReversalsForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
|
helper.createSplitJournalEntriesForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId, paymentTypeId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, isReversal);
|
loanId, transactionId, transactionDate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1293,21 +1289,20 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount, !isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, !isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -1321,9 +1316,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
: chargePaymentDTO.getAmount(),
|
: chargePaymentDTO.getAmount(),
|
||||||
chargePaymentDTO.getLoanChargeId()));
|
chargePaymentDTO.getLoanChargeId()));
|
||||||
}
|
}
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
loanProductId, loanId, transactionId, transactionDate, feesAmount, chargePaymentDTOs);
|
||||||
!isReversal, chargePaymentDTOs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -1336,21 +1330,18 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
: chargePaymentDTO.getAmount(),
|
: chargePaymentDTO.getAmount(),
|
||||||
chargePaymentDTO.getLoanChargeId()));
|
chargePaymentDTO.getLoanChargeId()));
|
||||||
}
|
}
|
||||||
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, chargePaymentDTOs);
|
||||||
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
|
||||||
penaltiesAmount, !isReversal, chargePaymentDTOs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT, loanProductId,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, !isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+120
-147
@@ -35,6 +35,7 @@ import org.apache.fineract.accounting.journalentry.data.LoanDTO;
|
|||||||
import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO;
|
import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.office.domain.Office;
|
import org.apache.fineract.organisation.office.domain.Office;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -42,48 +43,53 @@ import org.springframework.stereotype.Component;
|
|||||||
public class CashBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
public class CashBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
||||||
|
|
||||||
private final AccountingProcessorHelper helper;
|
private final AccountingProcessorHelper helper;
|
||||||
|
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
|
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
|
||||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
|
final Long officeId = loanDTO.getOfficeId();
|
||||||
|
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(officeId);
|
||||||
final Long loanProductId = loanDTO.getLoanProductId();
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
final String currencyCode = loanDTO.getCurrencyCode();
|
final String currencyCode = loanDTO.getCurrencyCode();
|
||||||
|
final Office office = this.helper.getOfficeById(officeId);
|
||||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final Office office = this.helper.getOfficeById(loanTransactionDTO.getOfficeId());
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final Long loanId = loanDTO.getLoanId();
|
final Long loanId = loanDTO.getLoanId();
|
||||||
|
final LoanTransactionEnumData transactionType = loanTransactionDTO.getTransactionType();
|
||||||
|
|
||||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||||
|
|
||||||
/** Handle Disbursements and reversals of disbursements **/
|
if (loanTransactionDTO.isReversed()) {
|
||||||
if (loanTransactionDTO.getTransactionType().isDisbursement()) {
|
journalEntryWritePlatformService.createJournalEntryForReversedLoanTransaction(transactionDate, transactionId, officeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handle Disbursements **/
|
||||||
|
if (transactionType.isDisbursement()) {
|
||||||
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
* Logic for repayments, repayments at disbursement and reversal of Repayments and Repayments at
|
* Logic for repayments, repayments at disbursement (except charge adjustment)
|
||||||
* disbursement (except charge adjustment)
|
|
||||||
***/
|
***/
|
||||||
else if ((loanTransactionDTO.getTransactionType().isRepaymentType()
|
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
||||||
&& !loanTransactionDTO.getTransactionType().isChargeAdjustment())
|
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
||||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()
|
|
||||||
|| loanTransactionDTO.getTransactionType().isChargePayment()) {
|
|
||||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logic for handling recovery payments **/
|
/** Logic for handling recovery payments **/
|
||||||
else if (loanTransactionDTO.getTransactionType().isRecoveryRepayment()) {
|
else if (transactionType.isRecoveryRepayment()) {
|
||||||
createJournalEntriesForRecoveryRepayments(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForRecoveryRepayments(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logic for Refunds of Overpayments **/
|
/** Logic for Refunds of Overpayments **/
|
||||||
else if (loanTransactionDTO.getTransactionType().isRefund()) {
|
else if (transactionType.isRefund()) {
|
||||||
createJournalEntriesForRefund(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForRefund(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logic for Credit Balance Refunds **/
|
/** Logic for Credit Balance Refunds **/
|
||||||
else if (loanTransactionDTO.getTransactionType().isCreditBalanceRefund()) {
|
else if (transactionType.isCreditBalanceRefund()) {
|
||||||
createJournalEntriesForCreditBalanceRefund(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForCreditBalanceRefund(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,33 +97,32 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
* Only principal write off affects cash based accounting (interest and fee write off need not be
|
* Only principal write off affects cash based accounting (interest and fee write off need not be
|
||||||
* considered). Debit losses written off and credit Loan Portfolio
|
* considered). Debit losses written off and credit Loan Portfolio
|
||||||
**/
|
**/
|
||||||
else if (loanTransactionDTO.getTransactionType().isWriteOff()) {
|
else if (transactionType.isWriteOff()) {
|
||||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||||
CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, loanTransactionDTO.isReversed());
|
transactionDate, principalAmount);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (loanTransactionDTO.getTransactionType().isInitiateTransfer()
|
} else if (transactionType.isInitiateTransfer() || transactionType.isApproveTransfer()
|
||||||
|| loanTransactionDTO.getTransactionType().isApproveTransfer()
|
|| transactionType.isWithdrawTransfer()) {
|
||||||
|| loanTransactionDTO.getTransactionType().isWithdrawTransfer()) {
|
|
||||||
createJournalEntriesForTransfers(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForTransfers(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
/** Logic for Refunds of Active Loans **/
|
/** Logic for Refunds of Active Loans **/
|
||||||
else if (loanTransactionDTO.getTransactionType().isRefundForActiveLoans()) {
|
else if (transactionType.isRefundForActiveLoans()) {
|
||||||
createJournalEntriesForRefundForActiveLoan(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForRefundForActiveLoan(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
// Logic for Chargebacks
|
// Logic for Chargebacks
|
||||||
else if (loanTransactionDTO.getTransactionType().isChargeback()) {
|
else if (transactionType.isChargeback()) {
|
||||||
createJournalEntriesForChargeback(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForChargeback(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
// Logic for Charge Adjustment
|
// Logic for Charge Adjustment
|
||||||
else if (loanTransactionDTO.getTransactionType().isChargeAdjustment()) {
|
else if (transactionType.isChargeAdjustment()) {
|
||||||
createJournalEntriesForChargeAdjustment(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForChargeAdjustment(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
// Logic for Charge-Off
|
// Logic for Charge-Off
|
||||||
else if (loanTransactionDTO.getTransactionType().isChargeoff()) {
|
else if (transactionType.isChargeoff()) {
|
||||||
createJournalEntriesForChargeOff(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForChargeOff(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +143,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
@@ -174,14 +178,14 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), isReversal, glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||||
debitEntry.getValue(), isReversal, glAccount);
|
glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,13 +234,12 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// handle principal payment (and reversals)
|
// handle principal payment
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -244,7 +247,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
accountMap.put(account, principalAmount);
|
accountMap.put(account, principalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle interest payment (and reversals)
|
// handle interest payment
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -257,7 +260,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle fees payment (and reversals)
|
// handle fees payment
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -297,8 +300,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
entry.getValue(), isReversal, entry.getKey());
|
entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -309,8 +312,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
} else {
|
} else {
|
||||||
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||||
}
|
}
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,13 +332,12 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// handle principal payment (and reversals)
|
// handle principal payment
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
@@ -343,7 +345,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
accountMap.put(account, principalAmount);
|
accountMap.put(account, principalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle interest payment (and reversals)
|
// handle interest payment
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -356,7 +358,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle fees payment (and reversals)
|
// handle fees payment
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
@@ -369,7 +371,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle penalties payment (and reversals)
|
// handle penalties payment
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
@@ -396,8 +398,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
entry.getValue(), isReversal, entry.getKey());
|
entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -408,8 +410,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
} else {
|
} else {
|
||||||
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||||
}
|
}
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,20 +432,15 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount,
|
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount);
|
||||||
isReversal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
||||||
*
|
*
|
||||||
* All debits are turned into credits and vice versa in case of disbursement reversals
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param loanDTO
|
* @param loanDTO
|
||||||
* @param loanTransactionDTO
|
* @param loanTransactionDTO
|
||||||
* @param office
|
* @param office
|
||||||
@@ -461,36 +458,32 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
||||||
: BigDecimal.ZERO;
|
: BigDecimal.ZERO;
|
||||||
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, principalPortion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion);
|
||||||
}
|
}
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
} else {
|
} else {
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
||||||
*
|
*
|
||||||
* All debits are turned into credits and vice versa in case of disbursement reversals
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param loanDTO
|
* @param loanDTO
|
||||||
* @param loanTransactionDTO
|
* @param loanTransactionDTO
|
||||||
* @param office
|
* @param office
|
||||||
@@ -505,17 +498,16 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
if (loanTransactionDTO.isAccountTransfer()) {
|
if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
||||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||||
refundAmount, isReversal);
|
refundAmount);
|
||||||
} else {
|
} else {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
||||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||||
refundAmount, isReversal);
|
refundAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,8 +515,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
* Create a single Debit to fund source and multiple credits if applicable (loan portfolio for principal repayments,
|
* Create a single Debit to fund source and multiple credits if applicable (loan portfolio for principal repayments,
|
||||||
* Interest on loans for interest repayments, Income from fees for fees payment and Income from penalties for
|
* Interest on loans for interest repayments, Income from fees for fees payment and Income from penalties for
|
||||||
* penalty payment)
|
* penalty payment)
|
||||||
*
|
|
||||||
* In case the loan transaction is a reversal, all debits are turned into credits and vice versa
|
|
||||||
*/
|
*/
|
||||||
private void createJournalEntriesForRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
final Office office) {
|
final Office office) {
|
||||||
@@ -532,7 +522,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
||||||
if (isMarkedChargeOff) {
|
if (isMarkedChargeOff) {
|
||||||
createJournalEntriesForChargeOffLoanRepayments(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForChargeOffLoanRepayments(loanDTO, loanTransactionDTO, office);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
createJournalEntriesForLoanRepayments(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForLoanRepayments(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
@@ -555,7 +544,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
|
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
@@ -707,36 +695,35 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), isReversal, glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
/*** create a single debit entry for the entire amount **/
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else {
|
} else {
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
debitEntry.getValue(), isReversal, glAccount);
|
debitEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||||
* those related to the repayment above
|
* repayment above
|
||||||
***/
|
***/
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
totalDebitAmount, isReversal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -755,7 +742,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
@@ -763,8 +749,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateDebitAccountEntry(loanProductId, principalAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
populateDebitAccountEntry(loanProductId, principalAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
||||||
debitAccountMapForGoodwillCredit, paymentTypeId);
|
debitAccountMapForGoodwillCredit, paymentTypeId);
|
||||||
@@ -773,8 +759,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS, loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateDebitAccountEntry(loanProductId, interestAmount,
|
populateDebitAccountEntry(loanProductId, interestAmount,
|
||||||
CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue(), debitAccountMapForGoodwillCredit,
|
CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue(), debitAccountMapForGoodwillCredit,
|
||||||
@@ -784,9 +770,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
CashAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
isReversal, loanTransactionDTO.getFeePayments());
|
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateDebitAccountEntry(loanProductId, feesAmount, CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(),
|
populateDebitAccountEntry(loanProductId, feesAmount, CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(),
|
||||||
debitAccountMapForGoodwillCredit, paymentTypeId);
|
debitAccountMapForGoodwillCredit, paymentTypeId);
|
||||||
@@ -795,9 +780,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||||
CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, loanTransactionDTO.getPenaltyPayments());
|
||||||
penaltiesAmount, isReversal, loanTransactionDTO.getPenaltyPayments());
|
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateDebitAccountEntry(loanProductId, penaltiesAmount,
|
populateDebitAccountEntry(loanProductId, penaltiesAmount,
|
||||||
CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), debitAccountMapForGoodwillCredit,
|
CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), debitAccountMapForGoodwillCredit,
|
||||||
@@ -807,45 +791,44 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId, paymentTypeId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, isReversal);
|
loanId, transactionId, transactionDate, overPaymentAmount);
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateDebitAccountEntry(loanProductId, overPaymentAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
populateDebitAccountEntry(loanProductId, overPaymentAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
||||||
debitAccountMapForGoodwillCredit, paymentTypeId);
|
debitAccountMapForGoodwillCredit, paymentTypeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
/*** create a single debit entry for the entire amount **/
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
|
|
||||||
// create debit entries
|
// create debit entries
|
||||||
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey(), loanProductId, paymentTypeId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(), isReversal);
|
loanId, transactionId, transactionDate, debitEntry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||||
* those related to the repayment above
|
* repayment above
|
||||||
***/
|
***/
|
||||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
totalDebitAmount, isReversal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -863,8 +846,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a single Debit to fund source and a single credit to "Income from Recovery"
|
* Create a single Debit to fund source and a single credit to "Income from Recovery"
|
||||||
*
|
|
||||||
* In case the loan transaction is a reversal, all debits are turned into credits and vice versa
|
|
||||||
*/
|
*/
|
||||||
private void createJournalEntriesForRecoveryRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForRecoveryRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
final Office office) {
|
final Office office) {
|
||||||
@@ -877,12 +858,11 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
CashAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
CashAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||||
amount, isReversal);
|
amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,18 +887,16 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
// final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
|
||||||
|
|
||||||
if (loanTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
if (loanTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.TRANSFERS_SUSPENSE.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.TRANSFERS_SUSPENSE.getValue(),
|
||||||
CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId, null, loanId, transactionId, transactionDate,
|
CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId, null, loanId, transactionId, transactionDate,
|
||||||
principalAmount, isReversal);
|
principalAmount);
|
||||||
} else if (loanTransactionDTO.getTransactionType().isApproveTransfer()
|
} else if (loanTransactionDTO.getTransactionType().isApproveTransfer()
|
||||||
|| loanTransactionDTO.getTransactionType().isWithdrawTransfer()) {
|
|| loanTransactionDTO.getTransactionType().isWithdrawTransfer()) {
|
||||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
CashAccountsForLoan.TRANSFERS_SUSPENSE.getValue(), loanProductId, null, loanId, transactionId, transactionDate,
|
CashAccountsForLoan.TRANSFERS_SUSPENSE.getValue(), loanProductId, null, loanId, transactionId, transactionDate,
|
||||||
principalAmount, isReversal);
|
principalAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,7 +910,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
// transaction properties
|
// transaction properties
|
||||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
@@ -951,8 +928,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(CashAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(CashAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
||||||
helper.createSplitJournalEntriesAndReversalsForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
|
helper.createSplitJournalEntriesForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId, paymentTypeId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, isReversal);
|
loanId, transactionId, transactionDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
|
private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
|
||||||
@@ -969,21 +946,20 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, !isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, !isReversal);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -997,9 +973,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
: chargePaymentDTO.getAmount(),
|
: chargePaymentDTO.getAmount(),
|
||||||
chargePaymentDTO.getLoanChargeId()));
|
chargePaymentDTO.getLoanChargeId()));
|
||||||
}
|
}
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
CashAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
loanProductId, loanId, transactionId, transactionDate, feesAmount, chargePaymentDTOs);
|
||||||
!isReversal, chargePaymentDTOs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -1013,20 +988,18 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
chargePaymentDTO.getLoanChargeId()));
|
chargePaymentDTO.getLoanChargeId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||||
CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, chargePaymentDTOs);
|
||||||
penaltiesAmount, !isReversal, chargePaymentDTOs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, !isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -39,6 +39,8 @@ public interface JournalEntryWritePlatformService {
|
|||||||
|
|
||||||
CommandProcessingResult defineOpeningBalance(JsonCommand command);
|
CommandProcessingResult defineOpeningBalance(JsonCommand command);
|
||||||
|
|
||||||
|
void createJournalEntryForReversedLoanTransaction(LocalDate transactionDate, String loanTransactionId, Long officeId);
|
||||||
|
|
||||||
String revertProvisioningJournalEntries(LocalDate reversalTransactionDate, Long entityId, Integer entityType);
|
String revertProvisioningJournalEntries(LocalDate reversalTransactionDate, Long entityId, Integer entityType);
|
||||||
|
|
||||||
String createProvisioningJournalEntries(ProvisioningEntry entry);
|
String createProvisioningJournalEntries(ProvisioningEntry entry);
|
||||||
|
|||||||
+22
@@ -298,6 +298,28 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
|||||||
return new CommandProcessingResultBuilder().withTransactionId(reversalTransactionId).build();
|
return new CommandProcessingResultBuilder().withTransactionId(reversalTransactionId).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createJournalEntryForReversedLoanTransaction(final LocalDate transactionDate, final String loanTransactionId,
|
||||||
|
final Long officeId) {
|
||||||
|
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(officeId);
|
||||||
|
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||||
|
final String transactionId = AccountingProcessorHelper.LOAN_TRANSACTION_IDENTIFIER + loanTransactionId;
|
||||||
|
final List<JournalEntry> journalEntries = this.glJournalEntryRepository.findJournalEntries(transactionId,
|
||||||
|
PortfolioProductType.LOAN.getValue());
|
||||||
|
if (journalEntries == null || journalEntries.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final JournalEntry journalEntry : journalEntries) {
|
||||||
|
final JournalEntry reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetail(),
|
||||||
|
journalEntry.getGlAccount(), journalEntry.getCurrencyCode(), transactionId, Boolean.FALSE, transactionDate,
|
||||||
|
journalEntry.isDebitEntry() ? JournalEntryType.CREDIT : JournalEntryType.DEBIT, journalEntry.getAmount(),
|
||||||
|
journalEntry.getDescription(), journalEntry.getEntityType(), journalEntry.getEntityId(),
|
||||||
|
journalEntry.getReferenceNumber(), journalEntry.getLoanTransactionId(), journalEntry.getSavingsTransactionId(),
|
||||||
|
journalEntry.getClientTransactionId(), journalEntry.getShareTransactionId());
|
||||||
|
helper.persistJournalEntry(reversalJournalEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String revertJournalEntry(final List<JournalEntry> journalEntries, String reversalComment) {
|
public String revertJournalEntry(final List<JournalEntry> journalEntries, String reversalComment) {
|
||||||
final Long officeId = journalEntries.get(0).getOffice().getId();
|
final Long officeId = journalEntries.get(0).getOffice().getId();
|
||||||
final String reversalTransactionId = generateTransactionId(officeId);
|
final String reversalTransactionId = generateTransactionId(officeId);
|
||||||
|
|||||||
+4
-5
@@ -99,12 +99,11 @@ class CreateJournalEntriesForChargeOffLoanTest {
|
|||||||
|
|
||||||
verify(helper, times(1)).getChargeOffMappingByCodeValue(1L, PortfolioProductType.LOAN, chargeOffReasonId);
|
verify(helper, times(1)).getChargeOffMappingByCodeValue(1L, PortfolioProductType.LOAN, chargeOffReasonId);
|
||||||
verify(helper, times(1)).getLinkedGLAccountForLoanProduct(1L, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 1L);
|
verify(helper, times(1)).getLinkedGLAccountForLoanProduct(1L, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 1L);
|
||||||
verify(helper, times(1)).createCreditJournalEntryOrReversalForLoan(helper.getOfficeById(1L), "USD",
|
verify(helper, times(1)).createCreditJournalEntryForLoan(helper.getOfficeById(1L), "USD", AccrualAccountsForLoan.LOAN_PORTFOLIO, 1L,
|
||||||
AccrualAccountsForLoan.LOAN_PORTFOLIO, 1L, null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()),
|
null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()), new BigDecimal("500.00"));
|
||||||
new BigDecimal("500.00"), false);
|
verify(helper, times(1)).createDebitJournalEntryForLoan(helper.getOfficeById(1L), "USD",
|
||||||
verify(helper, times(1)).createDebitJournalEntryOrReversalForLoan(helper.getOfficeById(1L), "USD",
|
|
||||||
AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), 1L, null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()),
|
AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), 1L, null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()),
|
||||||
new BigDecimal("500.00"), false);
|
new BigDecimal("500.00"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user