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.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
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)
|
||||
private String currencyCode;
|
||||
|
||||
@Setter
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "reversal_id")
|
||||
private JournalEntry reversalJournalEntry;
|
||||
@@ -73,6 +75,7 @@ public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
@Column(name = "share_transaction_id")
|
||||
private Long shareTransactionId;
|
||||
|
||||
@Setter
|
||||
@Column(name = "reversed", nullable = false)
|
||||
private boolean reversed = false;
|
||||
|
||||
@@ -151,11 +154,4 @@ public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
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_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_ZERO_INTEREST_CHARGE_OFF_DELINQUENT_REASON, //
|
||||
;
|
||||
|
||||
@Override
|
||||
|
||||
+122
@@ -1250,4 +1250,126 @@ public class LoanProductsRequestFactory {
|
||||
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))//
|
||||
.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();
|
||||
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_360_30__DECLINING_PERIOD_DAILY_INT_RECALC,
|
||||
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,
|
||||
|
||||
+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_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_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_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";
|
||||
|
||||
@@ -7541,4 +7541,46 @@ Feature: Charge-off
|
||||
| 20 January 2024 | Accrual Adjustment | 12.58 | 0.0 | 12.58 | 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 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.service.AccountTransfersReadPlatformService;
|
||||
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.loanaccount.data.LoanChargeData;
|
||||
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.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -356,15 +353,12 @@ public class AccountingProcessorHelper {
|
||||
* transactionDate
|
||||
* @param totalAmount
|
||||
* totalAmount
|
||||
* @param isReversal
|
||||
* isReversal
|
||||
* @param chargePaymentDTOs
|
||||
* chargePaymentDTOs
|
||||
*/
|
||||
public void createJournalEntriesAndReversalsForLoanCharges(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
public void createJournalEntriesForLoanCharges(final Office office, final String currencyCode, final Integer accountTypeToBeDebited,
|
||||
final Integer accountTypeToBeCredited, final Long loanProductId, final Long loanId, final String transactionId,
|
||||
final LocalDate transactionDate, final BigDecimal totalAmount, final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
|
||||
GLAccount receivableAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountTypeToBeDebited, null);
|
||||
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
||||
@@ -387,13 +381,8 @@ public class AccountingProcessorHelper {
|
||||
final GLAccount account = entry.getKey();
|
||||
final BigDecimal amount = entry.getValue();
|
||||
totalCreditedAmount = totalCreditedAmount.add(amount);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForLoan(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);
|
||||
}
|
||||
createDebitJournalEntryForLoan(office, currencyCode, receivableAccount, loanId, transactionId, transactionDate, amount);
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
if (totalAmount.compareTo(totalCreditedAmount) != 0) {
|
||||
@@ -453,61 +442,43 @@ public class AccountingProcessorHelper {
|
||||
* @param transactionId
|
||||
* @param transactionDate
|
||||
* @param amount
|
||||
* @param isReversal
|
||||
*/
|
||||
public void createJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId,
|
||||
final Long loanId, final String transactionId, final LocalDate transactionDate, final BigDecimal amount,
|
||||
final Boolean isReversal) {
|
||||
public void createJournalEntriesForLoan(final Office office, final String currencyCode, final Integer accountTypeToBeDebited,
|
||||
final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||
int accountTypeToDebitId = accountTypeToBeDebited;
|
||||
int accountTypeToCreditId = accountTypeToBeCredited;
|
||||
// reverse debits and credits for reversals
|
||||
if (isReversal) {
|
||||
accountTypeToDebitId = accountTypeToBeCredited;
|
||||
accountTypeToCreditId = accountTypeToBeDebited;
|
||||
}
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createSplitJournalEntriesAndReversalsForLoan(Office office, String currencyCode,
|
||||
List<JournalAmountHolder> splitAccountsHolder, JournalAmountHolder totalAccountHolder, Long loanProductId, Long paymentTypeId,
|
||||
Long loanId, String transactionId, LocalDate transactionDate, Boolean isReversal) {
|
||||
public void createSplitJournalEntriesForLoan(Office office, String currencyCode, List<JournalAmountHolder> splitAccountsHolder,
|
||||
JournalAmountHolder totalAccountHolder, Long loanProductId, Long paymentTypeId, Long loanId, String transactionId,
|
||||
LocalDate transactionDate) {
|
||||
splitAccountsHolder.forEach(journalItemHolder -> {
|
||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, journalItemHolder.getAccountType(), paymentTypeId);
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
||||
journalItemHolder.getAmount());
|
||||
} else {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
||||
journalItemHolder.getAmount());
|
||||
}
|
||||
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate,
|
||||
journalItemHolder.getAmount());
|
||||
});
|
||||
final GLAccount totalAccount = getLinkedGLAccountForLoanProduct(loanProductId, totalAccountHolder.getAccountType(), paymentTypeId);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, totalAccount, loanId, transactionId, transactionDate,
|
||||
totalAccountHolder.getAmount());
|
||||
} else {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, totalAccount, loanId, transactionId, transactionDate,
|
||||
totalAccountHolder.getAmount());
|
||||
}
|
||||
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 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();
|
||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
createCreditJournalEntryForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
|
||||
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 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();
|
||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
createCreditJournalEntryForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
|
||||
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,
|
||||
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||
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,
|
||||
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||
final BigDecimal amount, final Boolean isReversal) {
|
||||
@@ -723,80 +670,37 @@ public class AccountingProcessorHelper {
|
||||
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 LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
final LocalDate transactionDate, final BigDecimal amount) {
|
||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal,
|
||||
final GLAccount account) {
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
public void createDebitJournalEntryForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final GLAccount account) {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createDebitJournalEntryOrReversalForLoanCharges(final Office office, final String currencyCode,
|
||||
final int accountMappingTypeId, final Long loanProductId, final Long chargeId, final Long loanId, final String transactionId,
|
||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
public void createDebitJournalEntryForLoanCharges(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||
final Long loanProductId, final Long chargeId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||
final BigDecimal amount) {
|
||||
final GLAccount account = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createCreditJournalEntryOrReversalForLoanCharges(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 Boolean isReversal,
|
||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
/***
|
||||
* 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();
|
||||
public void createCreditJournalEntryForLoanCharges(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) {
|
||||
createJournalEntriesForLoanChargesInternal(office, currencyCode, accountMappingTypeId, loanProductId, loanId, transactionId,
|
||||
transactionDate, totalAmount, chargePaymentDTOs, true);
|
||||
}
|
||||
|
||||
// adjust net credit amount if the account is already present in the
|
||||
// map
|
||||
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
|
||||
final BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
|
||||
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
|
||||
}
|
||||
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);
|
||||
}
|
||||
public void createDebitJournalEntryForLoanCharges(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) {
|
||||
createJournalEntriesForLoanChargesInternal(office, currencyCode, accountMappingTypeId, loanProductId, loanId, transactionId,
|
||||
transactionDate, totalAmount, chargePaymentDTOs, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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) {
|
||||
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 LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
final LocalDate transactionDate, final BigDecimal amount) {
|
||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, isReversal,
|
||||
account);
|
||||
createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, account);
|
||||
}
|
||||
|
||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal,
|
||||
final GLAccount account) {
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
public void createCreditJournalEntryForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final GLAccount account) {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForClientPayments(final Office office, final String currencyCode, final GLAccount account,
|
||||
@@ -1403,4 +1289,38 @@ public class AccountingProcessorHelper {
|
||||
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 {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
|
||||
final Office office = this.helper.getOfficeById(loanDTO.getOfficeId());
|
||||
final Long officeId = loanDTO.getOfficeId();
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(officeId);
|
||||
final Office office = this.helper.getOfficeById(officeId);
|
||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
final LoanTransactionEnumData transactionType = loanTransactionDTO.getTransactionType();
|
||||
|
||||
if (loanTransactionDTO.isReversed()) {
|
||||
journalEntryWritePlatformService.createJournalEntryForReversedLoanTransaction(transactionDate,
|
||||
loanTransactionDTO.getTransactionId(), officeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle Disbursements
|
||||
if (transactionType.isDisbursement()) {
|
||||
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
|
||||
* disbursement (except charge adjustment)
|
||||
* Handle repayments, loan refunds, repayments at disbursement (except charge adjustment)
|
||||
*/
|
||||
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
||||
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
||||
@@ -91,7 +98,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
createJournalEntriesForCreditBalanceRefund(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
// Handle Write Offs, waivers and their reversals
|
||||
// Handle Write Offs
|
||||
else if ((transactionType.isWriteOff() || transactionType.isWaiveInterest() || transactionType.isWaiveCharges())) {
|
||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
|
||||
}
|
||||
@@ -135,7 +142,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPayment = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
if (isMarkedAsChargeOff) {
|
||||
@@ -202,14 +208,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
// create credit entries
|
||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), glAccount);
|
||||
}
|
||||
// create debit entries
|
||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||
glAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +233,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
// need to fetch if there are account mappings (always one)
|
||||
@@ -272,14 +277,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
// create credit entries
|
||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), glAccount);
|
||||
}
|
||||
// create debit entries
|
||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||
glAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +323,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
@@ -386,8 +390,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
|
||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||
entry.getKey());
|
||||
}
|
||||
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -398,8 +402,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
} else {
|
||||
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||
}
|
||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||
transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,13 +422,12 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||
|
||||
// handle principal payment (and reversals)
|
||||
// handle principal payment
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
@@ -432,7 +435,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
accountMap.put(account, principalAmount);
|
||||
}
|
||||
|
||||
// handle interest payment (and reversals)
|
||||
// handle interest payment
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
@@ -485,8 +488,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
|
||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||
entry.getKey());
|
||||
}
|
||||
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -497,8 +500,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
} else {
|
||||
accountMappingTypeId = AccrualAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||
}
|
||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||
transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,7 +522,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final BigDecimal overpaidAmount = Objects.isNull(loanTransactionDTO.getOverPayment()) ? BigDecimal.ZERO
|
||||
: loanTransactionDTO.getOverPayment();
|
||||
@@ -536,36 +538,36 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltyPaid = Objects.isNull(loanTransactionDTO.getPenaltyPaid()) ? BigDecimal.ZERO
|
||||
: loanTransactionDTO.getPenaltyPaid();
|
||||
|
||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, amount, isReversal);
|
||||
helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, amount);
|
||||
|
||||
if (overpaidAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaidAmount, isReversal);
|
||||
helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overpaidAmount);
|
||||
}
|
||||
|
||||
if (principalCredited.compareTo(principalPaid) > 0) {
|
||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalCredited.subtract(principalPaid), isReversal);
|
||||
helper.createDebitJournalEntryForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, principalCredited.subtract(principalPaid));
|
||||
} else if (principalCredited.compareTo(principalPaid) < 0) {
|
||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalPaid.subtract(principalCredited), isReversal);
|
||||
helper.createCreditJournalEntryForLoan(office, currencyCode, getPrincipalAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, principalPaid.subtract(principalCredited));
|
||||
}
|
||||
|
||||
if (feeCredited.compareTo(feePaid) > 0) {
|
||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, feeCredited.subtract(feePaid), isReversal);
|
||||
helper.createDebitJournalEntryForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, feeCredited.subtract(feePaid));
|
||||
} else if (feeCredited.compareTo(feePaid) < 0) {
|
||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, feePaid.subtract(feeCredited), isReversal);
|
||||
helper.createCreditJournalEntryForLoan(office, currencyCode, getFeeAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, feePaid.subtract(feeCredited));
|
||||
}
|
||||
|
||||
if (penaltyCredited.compareTo(penaltyPaid) > 0) {
|
||||
helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, penaltyCredited.subtract(penaltyPaid), isReversal);
|
||||
helper.createDebitJournalEntryForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, penaltyCredited.subtract(penaltyPaid));
|
||||
} else if (penaltyCredited.compareTo(penaltyPaid) < 0) {
|
||||
helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, penaltyPaid.subtract(penaltyCredited), isReversal);
|
||||
helper.createCreditJournalEntryForLoan(office, currencyCode, getPenaltyAccount(loanDTO), loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, penaltyPaid.subtract(penaltyCredited));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,29 +618,27 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
||||
: BigDecimal.ZERO;
|
||||
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
// create journal entries for the disbursement (or disbursement
|
||||
// reversal)
|
||||
// create journal entries for the disbursement
|
||||
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion, isReversed);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion);
|
||||
|
||||
}
|
||||
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion, isReversed);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion);
|
||||
}
|
||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||
} else {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversed);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||
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/>
|
||||
* <br/>
|
||||
* <br/>
|
||||
* In case the loan transaction has been reversed, all debits are turned into credits and vice versa
|
||||
*
|
||||
* @param loanTransactionDTO
|
||||
* @param loanDTO
|
||||
@@ -701,7 +700,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
@@ -801,9 +799,9 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
} else {
|
||||
if (isIncomeFromFee) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
||||
feesAmount, loanTransactionDTO.getFeePayments());
|
||||
GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId);
|
||||
glAccountBalanceHolder.addToDebit(debitAccount, feesAmount);
|
||||
@@ -879,44 +877,41 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
// create credit entries
|
||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), glAccount);
|
||||
}
|
||||
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (writeOff) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
||||
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
// create debit entries
|
||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), glAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
||||
* those related to the repayment above
|
||||
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||
* repayment above
|
||||
***/
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount, isReversal);
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,14 +933,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
Map<GLAccount, BigDecimal> accountMap = 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) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
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) {
|
||||
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
if (isIncomeFromFee) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
||||
} else {
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
if (isIncomeFromFee) {
|
||||
@@ -1047,53 +1040,48 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
|
||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||
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 (writeOff) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
||||
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
// create debit entries
|
||||
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||
isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue());
|
||||
}
|
||||
|
||||
} else {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
||||
* those related to the repayment above
|
||||
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||
* repayment above
|
||||
***/
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount, isReversal);
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1120,8 +1108,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
/**
|
||||
* 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,
|
||||
final Office office) {
|
||||
@@ -1134,12 +1120,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
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,
|
||||
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>
|
||||
*
|
||||
* Also handles reversals for both fees and payment applications
|
||||
*
|
||||
* @param loanDTO
|
||||
* @param loanTransactionDTO
|
||||
* @param office
|
||||
@@ -1170,28 +1153,43 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final boolean isReversed = transactionType.isAccrualAdjustment() != loanTransactionDTO.isReversed();
|
||||
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) {
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, interestAmount, isReversed);
|
||||
if (transactionType.isAccrualAdjustment()) {
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||
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) {
|
||||
this.helper.createJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
loanId, transactionId, transactionDate, feesAmount, isReversed, loanTransactionDTO.getFeePayments());
|
||||
if (transactionType.isAccrualAdjustment()) {
|
||||
this.helper.createJournalEntriesForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||
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) {
|
||||
|
||||
this.helper.createJournalEntriesAndReversalsForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed,
|
||||
loanTransactionDTO.getPenaltyPayments());
|
||||
if (transactionType.isAccrualAdjustment()) {
|
||||
this.helper.createJournalEntriesForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, 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 LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
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,
|
||||
refundAmount, isReversal);
|
||||
refundAmount);
|
||||
} 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,
|
||||
refundAmount, isReversal);
|
||||
refundAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,7 +1233,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
@@ -1257,8 +1253,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
|
||||
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(AccrualAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
||||
helper.createSplitJournalEntriesAndReversalsForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, isReversal);
|
||||
helper.createSplitJournalEntriesForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -1293,21 +1289,20 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||
}
|
||||
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||
}
|
||||
|
||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1321,9 +1316,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
: chargePaymentDTO.getAmount(),
|
||||
chargePaymentDTO.getLoanChargeId()));
|
||||
}
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
||||
!isReversal, chargePaymentDTOs);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, feesAmount, chargePaymentDTOs);
|
||||
}
|
||||
|
||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1336,21 +1330,18 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
: chargePaymentDTO.getAmount(),
|
||||
chargePaymentDTO.getLoanChargeId()));
|
||||
}
|
||||
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount, !isReversal, chargePaymentDTOs);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, chargePaymentDTOs);
|
||||
}
|
||||
|
||||
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount);
|
||||
}
|
||||
|
||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
||||
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||
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.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@@ -42,48 +43,53 @@ import org.springframework.stereotype.Component;
|
||||
public class CashBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Override
|
||||
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 String currencyCode = loanDTO.getCurrencyCode();
|
||||
final Office office = this.helper.getOfficeById(officeId);
|
||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(loanTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
final LoanTransactionEnumData transactionType = loanTransactionDTO.getTransactionType();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
/** Handle Disbursements and reversals of disbursements **/
|
||||
if (loanTransactionDTO.getTransactionType().isDisbursement()) {
|
||||
if (loanTransactionDTO.isReversed()) {
|
||||
journalEntryWritePlatformService.createJournalEntryForReversedLoanTransaction(transactionDate, transactionId, officeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
/** Handle Disbursements **/
|
||||
if (transactionType.isDisbursement()) {
|
||||
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
/***
|
||||
* Logic for repayments, repayments at disbursement and reversal of Repayments and Repayments at
|
||||
* disbursement (except charge adjustment)
|
||||
* Logic for repayments, repayments at disbursement (except charge adjustment)
|
||||
***/
|
||||
else if ((loanTransactionDTO.getTransactionType().isRepaymentType()
|
||||
&& !loanTransactionDTO.getTransactionType().isChargeAdjustment())
|
||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()
|
||||
|| loanTransactionDTO.getTransactionType().isChargePayment()) {
|
||||
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
||||
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/** Logic for handling recovery payments **/
|
||||
else if (loanTransactionDTO.getTransactionType().isRecoveryRepayment()) {
|
||||
else if (transactionType.isRecoveryRepayment()) {
|
||||
createJournalEntriesForRecoveryRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/** Logic for Refunds of Overpayments **/
|
||||
else if (loanTransactionDTO.getTransactionType().isRefund()) {
|
||||
else if (transactionType.isRefund()) {
|
||||
createJournalEntriesForRefund(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/** Logic for Credit Balance Refunds **/
|
||||
else if (loanTransactionDTO.getTransactionType().isCreditBalanceRefund()) {
|
||||
else if (transactionType.isCreditBalanceRefund()) {
|
||||
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
|
||||
* considered). Debit losses written off and credit Loan Portfolio
|
||||
**/
|
||||
else if (loanTransactionDTO.getTransactionType().isWriteOff()) {
|
||||
else if (transactionType.isWriteOff()) {
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode,
|
||||
CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, loanTransactionDTO.isReversed());
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||
CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
|
||||
transactionDate, principalAmount);
|
||||
|
||||
}
|
||||
} else if (loanTransactionDTO.getTransactionType().isInitiateTransfer()
|
||||
|| loanTransactionDTO.getTransactionType().isApproveTransfer()
|
||||
|| loanTransactionDTO.getTransactionType().isWithdrawTransfer()) {
|
||||
} else if (transactionType.isInitiateTransfer() || transactionType.isApproveTransfer()
|
||||
|| transactionType.isWithdrawTransfer()) {
|
||||
createJournalEntriesForTransfers(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
/** Logic for Refunds of Active Loans **/
|
||||
else if (loanTransactionDTO.getTransactionType().isRefundForActiveLoans()) {
|
||||
else if (transactionType.isRefundForActiveLoans()) {
|
||||
createJournalEntriesForRefundForActiveLoan(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
// Logic for Chargebacks
|
||||
else if (loanTransactionDTO.getTransactionType().isChargeback()) {
|
||||
else if (transactionType.isChargeback()) {
|
||||
createJournalEntriesForChargeback(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
// Logic for Charge Adjustment
|
||||
else if (loanTransactionDTO.getTransactionType().isChargeAdjustment()) {
|
||||
else if (transactionType.isChargeAdjustment()) {
|
||||
createJournalEntriesForChargeAdjustment(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
// Logic for Charge-Off
|
||||
else if (loanTransactionDTO.getTransactionType().isChargeoff()) {
|
||||
else if (transactionType.isChargeoff()) {
|
||||
createJournalEntriesForChargeOff(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
}
|
||||
@@ -138,7 +143,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
@@ -174,14 +178,14 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
// create credit entries
|
||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), glAccount);
|
||||
}
|
||||
// create debit entries
|
||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, debitEntry.getValue(),
|
||||
glAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +234,12 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||
|
||||
// handle principal payment (and reversals)
|
||||
// handle principal payment
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
@@ -244,7 +247,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
accountMap.put(account, principalAmount);
|
||||
}
|
||||
|
||||
// handle interest payment (and reversals)
|
||||
// handle interest payment
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
@@ -297,8 +300,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
}
|
||||
|
||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||
entry.getKey());
|
||||
}
|
||||
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -309,8 +312,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
} else {
|
||||
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||
}
|
||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||
transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,13 +332,12 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||
|
||||
// handle principal payment (and reversals)
|
||||
// handle principal payment
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
@@ -343,7 +345,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
accountMap.put(account, principalAmount);
|
||||
}
|
||||
|
||||
// handle interest payment (and reversals)
|
||||
// handle interest payment
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
@@ -396,8 +398,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
}
|
||||
|
||||
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||
entry.getKey());
|
||||
}
|
||||
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -408,8 +410,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
} else {
|
||||
accountMappingTypeId = CashAccountsForLoan.INCOME_FROM_FEES.getValue();
|
||||
}
|
||||
this.helper.createDebitJournalEntryOrReversalForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId,
|
||||
loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, accountMappingTypeId, loanProductId, chargeId, loanId,
|
||||
transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,20 +432,15 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount,
|
||||
isReversal);
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 loanTransactionDTO
|
||||
* @param office
|
||||
@@ -461,36 +458,32 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal overpaymentPortion = loanTransactionDTO.getOverPayment() != null ? loanTransactionDTO.getOverPayment()
|
||||
: BigDecimal.ZERO;
|
||||
final BigDecimal principalPortion = loanTransactionDTO.getAmount().subtract(overpaymentPortion);
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
if (MathUtil.isGreaterThanZero(principalPortion)) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPortion, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalPortion);
|
||||
}
|
||||
|
||||
if (MathUtil.isGreaterThanZero(overpaymentPortion)) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overpaymentPortion);
|
||||
}
|
||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||
} else {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount(), isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, loanTransactionDTO.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 loanTransactionDTO
|
||||
* @param office
|
||||
@@ -505,17 +498,16 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
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,
|
||||
refundAmount, isReversal);
|
||||
refundAmount);
|
||||
} 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,
|
||||
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,
|
||||
* Interest on loans for interest repayments, Income from fees for fees payment and Income from penalties for
|
||||
* 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,
|
||||
final Office office) {
|
||||
@@ -532,7 +522,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
||||
if (isMarkedChargeOff) {
|
||||
createJournalEntriesForChargeOffLoanRepayments(loanDTO, loanTransactionDTO, office);
|
||||
|
||||
} else {
|
||||
createJournalEntriesForLoanRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
@@ -555,7 +544,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
@@ -707,36 +695,35 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
// create credit entries
|
||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
creditEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
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()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
// create debit entries
|
||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), isReversal, glAccount);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
debitEntry.getValue(), glAccount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
||||
* those related to the repayment above
|
||||
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||
* repayment above
|
||||
***/
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount, isReversal);
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -755,7 +742,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
@@ -763,8 +749,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
populateDebitAccountEntry(loanProductId, principalAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
||||
debitAccountMapForGoodwillCredit, paymentTypeId);
|
||||
@@ -773,8 +759,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
populateDebitAccountEntry(loanProductId, interestAmount,
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CashAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
||||
isReversal, loanTransactionDTO.getFeePayments());
|
||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
populateDebitAccountEntry(loanProductId, feesAmount, CashAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(),
|
||||
debitAccountMapForGoodwillCredit, paymentTypeId);
|
||||
@@ -795,9 +780,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
|
||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount, isReversal, loanTransactionDTO.getPenaltyPayments());
|
||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, loanTransactionDTO.getPenaltyPayments());
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
populateDebitAccountEntry(loanProductId, penaltiesAmount,
|
||||
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) {
|
||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, isReversal);
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, overPaymentAmount);
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
populateDebitAccountEntry(loanProductId, overPaymentAmount, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
||||
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()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||
|
||||
// create debit entries
|
||||
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(), isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey(), loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, debitEntry.getValue());
|
||||
}
|
||||
|
||||
} else {
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge Refunds (and their reversals) have an extra refund related pair of journal entries in addition to
|
||||
* those related to the repayment above
|
||||
* Charge Refunds have an extra refund related pair of journal entries in addition to those related to the
|
||||
* repayment above
|
||||
***/
|
||||
if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, incomeAccount,
|
||||
CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount, isReversal);
|
||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,8 +846,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
|
||||
/**
|
||||
* 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,
|
||||
final Office office) {
|
||||
@@ -877,12 +858,11 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal amount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
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,
|
||||
amount, isReversal);
|
||||
amount);
|
||||
|
||||
}
|
||||
|
||||
@@ -907,18 +887,16 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
// final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
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,
|
||||
principalAmount, isReversal);
|
||||
principalAmount);
|
||||
} else if (loanTransactionDTO.getTransactionType().isApproveTransfer()
|
||||
|| 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,
|
||||
principalAmount, isReversal);
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,7 +910,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
@@ -951,8 +928,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
}
|
||||
|
||||
JournalAmountHolder totalAmountHolder = new JournalAmountHolder(CashAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
|
||||
helper.createSplitJournalEntriesAndReversalsForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, isReversal);
|
||||
helper.createSplitJournalEntriesForLoan(office, currencyCode, journalAmountHolders, totalAmountHolder, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate);
|
||||
}
|
||||
|
||||
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 penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, principalAmount);
|
||||
}
|
||||
|
||||
if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount);
|
||||
}
|
||||
|
||||
if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -997,9 +973,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
: chargePaymentDTO.getAmount(),
|
||||
chargePaymentDTO.getLoanChargeId()));
|
||||
}
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CashAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
||||
!isReversal, chargePaymentDTOs);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, feesAmount, chargePaymentDTOs);
|
||||
}
|
||||
|
||||
if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1013,20 +988,18 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
chargePaymentDTO.getLoanChargeId()));
|
||||
}
|
||||
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount, !isReversal, chargePaymentDTOs);
|
||||
this.helper.createDebitJournalEntryForLoanCharges(office, currencyCode, CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, chargePaymentDTOs);
|
||||
}
|
||||
|
||||
if (overPaymentAmount != null && overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, !isReversal);
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount);
|
||||
}
|
||||
|
||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
||||
|
||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -39,6 +39,8 @@ public interface JournalEntryWritePlatformService {
|
||||
|
||||
CommandProcessingResult defineOpeningBalance(JsonCommand command);
|
||||
|
||||
void createJournalEntryForReversedLoanTransaction(LocalDate transactionDate, String loanTransactionId, Long officeId);
|
||||
|
||||
String revertProvisioningJournalEntries(LocalDate reversalTransactionDate, Long entityId, Integer entityType);
|
||||
|
||||
String createProvisioningJournalEntries(ProvisioningEntry entry);
|
||||
|
||||
+22
@@ -298,6 +298,28 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
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) {
|
||||
final Long officeId = journalEntries.get(0).getOffice().getId();
|
||||
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)).getLinkedGLAccountForLoanProduct(1L, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 1L);
|
||||
verify(helper, times(1)).createCreditJournalEntryOrReversalForLoan(helper.getOfficeById(1L), "USD",
|
||||
AccrualAccountsForLoan.LOAN_PORTFOLIO, 1L, null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()),
|
||||
new BigDecimal("500.00"), false);
|
||||
verify(helper, times(1)).createDebitJournalEntryOrReversalForLoan(helper.getOfficeById(1L), "USD",
|
||||
verify(helper, times(1)).createCreditJournalEntryForLoan(helper.getOfficeById(1L), "USD", AccrualAccountsForLoan.LOAN_PORTFOLIO, 1L,
|
||||
null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()), new BigDecimal("500.00"));
|
||||
verify(helper, times(1)).createDebitJournalEntryForLoan(helper.getOfficeById(1L), "USD",
|
||||
AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), 1L, null, 1L, "txn-123", LocalDate.now(ZoneId.systemDefault()),
|
||||
new BigDecimal("500.00"), false);
|
||||
new BigDecimal("500.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user