FINERACT-2374: Advance Accounting rule for classification type
This commit is contained in:
committed by
Adam Saghy
parent
6d3e5fa150
commit
cb70555485
+2
@@ -48,4 +48,6 @@ public class LoanDTO {
|
||||
private Long chargeOffReasonCodeValue;
|
||||
private boolean markedAsWrittenOff;
|
||||
private boolean merchantBuyDownFee;
|
||||
private List<AdvancedMappingtDTO> buydownFeeAdvancedMappingData;
|
||||
private List<AdvancedMappingtDTO> capitalizedIncomeAdvancedMappingData;
|
||||
}
|
||||
|
||||
+30
-1
@@ -35,6 +35,7 @@ import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsFor
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount;
|
||||
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
@@ -171,7 +172,9 @@ public class AccountingProcessorHelper {
|
||||
|
||||
return new LoanDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled,
|
||||
periodicAccrualBasedAccountingEnabled, newLoanTransactions, isLoanMarkedAsChargeOff, isLoanMarkedAsFraud,
|
||||
chargeOffReasonCodeValue, isLoanMarkedAsWrittenOff, merchantBuyDownFee);
|
||||
chargeOffReasonCodeValue, isLoanMarkedAsWrittenOff, merchantBuyDownFee,
|
||||
accountingBridgeData.getBuydownFeeClassificationCodeValue(),
|
||||
accountingBridgeData.getCapitalizedIncomeClassificationCodeValue());
|
||||
}
|
||||
|
||||
public ProductToGLAccountMapping getChargeOffMappingByCodeValue(Long loanProductId, PortfolioProductType productType,
|
||||
@@ -179,6 +182,16 @@ public class AccountingProcessorHelper {
|
||||
return accountMappingRepository.findChargeOffReasonMapping(loanProductId, productType.getValue(), chargeOffReasonId);
|
||||
}
|
||||
|
||||
public ProductToGLAccountMapping getClassificationMappingByCodeValue(Long loanProductId, PortfolioProductType productType,
|
||||
final Long classificationId, final String classificationType) {
|
||||
if (LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue().equals(classificationType)) {
|
||||
return accountMappingRepository.findBuydownFeeClassificationMapping(loanProductId, productType.getValue(), classificationId);
|
||||
} else {
|
||||
return accountMappingRepository.findCapitalizedIncomeClassificationMapping(loanProductId, productType.getValue(),
|
||||
classificationId);
|
||||
}
|
||||
}
|
||||
|
||||
public SavingsDTO populateSavingsDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled) {
|
||||
final Long loanId = (Long) accountingBridgeData.get("savingsId");
|
||||
@@ -472,6 +485,14 @@ public class AccountingProcessorHelper {
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createJournalEntriesForLoan(final Office office, final String currencyCode, final Integer accountTypeToBeDebited,
|
||||
final GLAccount accountToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||
int accountTypeToDebitId = accountTypeToBeDebited;
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountToBeCredited, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createSplitJournalEntriesForLoan(Office office, String currencyCode, List<JournalAmountHolder> splitAccountsHolder,
|
||||
JournalAmountHolder totalAccountHolder, Long loanProductId, Long paymentTypeId, Long loanId, String transactionId,
|
||||
LocalDate transactionDate) {
|
||||
@@ -534,6 +555,14 @@ public class AccountingProcessorHelper {
|
||||
createCreditJournalEntryForLoan(office, currencyCode, creditAccount, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
private void createJournalEntriesForLoan(final Office office, final String currencyCode, final int accountTypeToDebitId,
|
||||
final GLAccount creditAccount, final Long loanProductId, final Long paymentTypeId, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||
final GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId, paymentTypeId);
|
||||
createDebitJournalEntryForLoan(office, currencyCode, debitAccount, loanId, transactionId, transactionDate, amount);
|
||||
createCreditJournalEntryForLoan(office, currencyCode, creditAccount, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
private void createJournalEntriesForSavings(final Office office, final String currencyCode, final int accountTypeToDebitId,
|
||||
final int accountTypeToCreditId, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||
|
||||
+106
-8
@@ -29,7 +29,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
import org.apache.fineract.accounting.journalentry.data.AdvancedMappingtDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.GLAccountBalanceHolder;
|
||||
import org.apache.fineract.accounting.journalentry.data.LoanDTO;
|
||||
@@ -296,17 +298,57 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
final List<AdvancedMappingtDTO> classificationCodeValues = loanDTO.getCapitalizedIncomeAdvancedMappingData();
|
||||
|
||||
// interest payment
|
||||
final AccrualAccountsForLoan creditAccountType = isLoanWrittenOff ? AccrualAccountsForLoan.LOSSES_WRITTEN_OFF
|
||||
: AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION;
|
||||
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
||||
populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
if (classificationCodeValues.isEmpty()) {
|
||||
populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
} else {
|
||||
classificationCodeValues.stream().forEach(classificationCodeValue -> {
|
||||
ProductToGLAccountMapping mapping = null;
|
||||
if (classificationCodeValue.getReferenceValueId() != null) {
|
||||
mapping = fetchAdvanceAccountingMappingForCodeValue(loanProductId, classificationCodeValue.getReferenceValueId(),
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue());
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId,
|
||||
creditAccountType.getValue(), AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
|
||||
glAccountBalanceHolder);
|
||||
} else {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId, mapping.getGlAccount(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// handle fees payment
|
||||
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
||||
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
if (classificationCodeValues.isEmpty()) {
|
||||
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
} else {
|
||||
classificationCodeValues.stream().forEach(classificationCodeValue -> {
|
||||
ProductToGLAccountMapping mapping = null;
|
||||
if (classificationCodeValue.getReferenceValueId() != null) {
|
||||
mapping = fetchAdvanceAccountingMappingForCodeValue(loanProductId, classificationCodeValue.getReferenceValueId(),
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue());
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId,
|
||||
creditAccountType.getValue(), AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
|
||||
glAccountBalanceHolder);
|
||||
} else {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId, mapping.getGlAccount(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// create credit entries
|
||||
@@ -327,6 +369,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
}
|
||||
|
||||
private ProductToGLAccountMapping fetchAdvanceAccountingMappingForCodeValue(final Long loanProductId, final Long codeValueId,
|
||||
final String codeName) {
|
||||
return helper.getClassificationMappingByCodeValue(loanProductId, PortfolioProductType.LOAN, codeValueId, codeName);
|
||||
}
|
||||
|
||||
private void createJournalEntriesForChargeOffLoanCapitalizedIncomeAmortization(final LoanDTO loanDTO,
|
||||
final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||
// loan properties
|
||||
@@ -493,17 +540,57 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
final GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||
|
||||
final List<AdvancedMappingtDTO> classificationCodeValues = loanDTO.getBuydownFeeAdvancedMappingData();
|
||||
|
||||
// interest payment
|
||||
final AccrualAccountsForLoan creditAccountType = isLoanWrittenOff ? AccrualAccountsForLoan.LOSSES_WRITTEN_OFF
|
||||
: AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN;
|
||||
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
||||
populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
if (classificationCodeValues.isEmpty()) {
|
||||
populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
} else {
|
||||
classificationCodeValues.stream().forEach(classificationCodeValue -> {
|
||||
ProductToGLAccountMapping mapping = null;
|
||||
if (classificationCodeValue.getReferenceValueId() != null) {
|
||||
mapping = fetchAdvanceAccountingMappingForCodeValue(loanProductId, classificationCodeValue.getReferenceValueId(),
|
||||
LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue());
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId,
|
||||
creditAccountType.getValue(), AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
|
||||
glAccountBalanceHolder);
|
||||
} else {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId, mapping.getGlAccount(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// handle fees payment
|
||||
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
||||
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
if (classificationCodeValues.isEmpty()) {
|
||||
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, creditAccountType.getValue(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
} else {
|
||||
classificationCodeValues.stream().forEach(classificationCodeValue -> {
|
||||
ProductToGLAccountMapping mapping = null;
|
||||
if (classificationCodeValue.getReferenceValueId() != null) {
|
||||
mapping = fetchAdvanceAccountingMappingForCodeValue(loanProductId, classificationCodeValue.getReferenceValueId(),
|
||||
LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue());
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId,
|
||||
creditAccountType.getValue(), AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
|
||||
glAccountBalanceHolder);
|
||||
} else {
|
||||
populateCreditDebitMaps(loanProductId, classificationCodeValue.getAmount(), paymentTypeId, mapping.getGlAccount(),
|
||||
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), glAccountBalanceHolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// create credit entries
|
||||
@@ -800,6 +887,17 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
}
|
||||
|
||||
private void populateCreditDebitMaps(Long loanProductId, BigDecimal transactionPartAmount, Long paymentTypeId, GLAccount accountCredit,
|
||||
Integer debitAccountType, GLAccountBalanceHolder glAccountBalanceHolder) {
|
||||
if (MathUtil.isGreaterThanZero(transactionPartAmount)) {
|
||||
// Resolve Credit
|
||||
glAccountBalanceHolder.addToCredit(accountCredit, transactionPartAmount);
|
||||
// Resolve Debit
|
||||
GLAccount accountDebit = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, debitAccountType, paymentTypeId);
|
||||
glAccountBalanceHolder.addToDebit(accountDebit, transactionPartAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private void createJournalEntriesForChargeAdjustment(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
|
||||
final boolean isMarkedAsChargeOff = loanDTO.isMarkedAsChargeOff();
|
||||
if (isMarkedAsChargeOff) {
|
||||
|
||||
+36
-1
@@ -44,6 +44,7 @@ import org.apache.fineract.accounting.glaccount.service.GLAccountReadPlatformSer
|
||||
import org.apache.fineract.accounting.journalentry.api.JournalEntryJsonInputParams;
|
||||
import org.apache.fineract.accounting.journalentry.command.JournalEntryCommand;
|
||||
import org.apache.fineract.accounting.journalentry.command.SingleDebitOrCreditEntryCommand;
|
||||
import org.apache.fineract.accounting.journalentry.data.AdvancedMappingtDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.ClientTransactionDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.LoanDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
@@ -61,6 +62,7 @@ import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
|
||||
import org.apache.fineract.accounting.rule.domain.AccountingRule;
|
||||
import org.apache.fineract.accounting.rule.domain.AccountingRuleRepository;
|
||||
import org.apache.fineract.accounting.rule.exception.AccountingRuleNotFoundException;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
||||
import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
@@ -90,11 +92,14 @@ import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAmortizationAllocationMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAmortizationAllocationMappingRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
@@ -128,6 +133,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final ConfigurationReadPlatformService configurationReadPlatformService;
|
||||
private final AccountingService accountingService;
|
||||
private final ExternalAssetOwnerRepository externalAssetOwnerRepository;
|
||||
private final LoanAmortizationAllocationMappingRepository loanAmortizationAllocationMappingRepository;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -857,11 +864,39 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
}
|
||||
}
|
||||
|
||||
List<AdvancedMappingtDTO> buydownFeeAdvancedMappingData = null;
|
||||
List<AdvancedMappingtDTO> capitalizedIncomeAdvancedMappingData = null;
|
||||
if (loanTransaction.isBuyDownFeeAmortization()) {
|
||||
buydownFeeAdvancedMappingData = getLoanTransactionClassificationId(loanTransaction);
|
||||
} else if (loanTransaction.isCapitalizedIncomeAmortization()) {
|
||||
capitalizedIncomeAdvancedMappingData = getLoanTransactionClassificationId(loanTransaction);
|
||||
}
|
||||
|
||||
return new AccountingBridgeDataDTO(loan.getId(), loan.productId(), loan.getOfficeId(), currencyCode,
|
||||
loan.getSummary().getTotalInterestCharged(), loan.isCashBasedAccountingEnabledOnLoanProduct(),
|
||||
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(),
|
||||
isAccountTransfer, wasChargedOffAtTransactionTime, loan.isFraud(), loan.fetchChargeOffReasonId(), loan.isClosedWrittenOff(),
|
||||
transactions, loan.getLoanProductRelatedDetail().isMerchantBuyDownFee());
|
||||
transactions, loan.getLoanProductRelatedDetail().isMerchantBuyDownFee(), buydownFeeAdvancedMappingData,
|
||||
capitalizedIncomeAdvancedMappingData);
|
||||
}
|
||||
|
||||
private List<AdvancedMappingtDTO> getLoanTransactionClassificationId(final LoanTransaction loanTransaction) {
|
||||
List<AdvancedMappingtDTO> advancedMappingData = new ArrayList<AdvancedMappingtDTO>();
|
||||
if (loanTransaction.isCapitalizedIncomeAmortization() || loanTransaction.isBuyDownFeeAmortization()) {
|
||||
final List<LoanAmortizationAllocationMapping> loanTransactionAllocations = loanAmortizationAllocationMappingRepository
|
||||
.fetchLoanTransactionAllocationByAmortizationLoanTransactionId(loanTransaction.getId(),
|
||||
loanTransaction.getLoan().getId());
|
||||
loanTransactionAllocations.stream().forEach(loanTransactionAllocation -> {
|
||||
final CodeValue classification = loanTransactionRepository
|
||||
.fetchClassificationCodeValueByTransactionId(loanTransactionAllocation.getBaseLoanTransactionId());
|
||||
if (classification != null) {
|
||||
advancedMappingData.add(new AdvancedMappingtDTO(classification.getId(), loanTransactionAllocation.getAmount()));
|
||||
} else {
|
||||
advancedMappingData.add(new AdvancedMappingtDTO(null, loanTransactionAllocation.getAmount()));
|
||||
}
|
||||
});
|
||||
}
|
||||
return advancedMappingData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-2
@@ -49,6 +49,8 @@ import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAmortizationAllocationMappingRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -94,12 +96,14 @@ public class AccountingJournalEntryConfiguration {
|
||||
FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper,
|
||||
CashBasedAccountingProcessorForClientTransactions accountingProcessorForClientTransactions,
|
||||
ConfigurationReadPlatformService configurationReadPlatformService, AccountingService accountingService,
|
||||
ExternalAssetOwnerRepository externalAssetOwnerRepository) {
|
||||
ExternalAssetOwnerRepository externalAssetOwnerRepository,
|
||||
LoanAmortizationAllocationMappingRepository loanAmortizationAllocationMappingRepository,
|
||||
LoanTransactionRepository loanTransactionRepository) {
|
||||
return new JournalEntryWritePlatformServiceJpaRepositoryImpl(glClosureRepository, glAccountRepository, glJournalEntryRepository,
|
||||
officeRepositoryWrapper, accountingProcessorForLoanFactory, accountingProcessorForSavingsFactory,
|
||||
accountingProcessorForSharesFactory, helper, fromApiJsonDeserializer, accountingRuleRepository,
|
||||
glAccountReadPlatformService, organisationCurrencyRepository, context, paymentDetailWritePlatformService,
|
||||
financialActivityAccountRepositoryWrapper, accountingProcessorForClientTransactions, configurationReadPlatformService,
|
||||
accountingService, externalAssetOwnerRepository);
|
||||
accountingService, externalAssetOwnerRepository, loanAmortizationAllocationMappingRepository, loanTransactionRepository);
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -140,6 +140,10 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveChargeOffReasonToExpenseAccountMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveBuyDownFeeClassificationToIncomeAccountMappings(command, element,
|
||||
loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveCapitalizedIncomeClassificationToIncomeAccountMappings(command, element,
|
||||
loanProductId, null);
|
||||
break;
|
||||
case ACCRUAL_UPFRONT:
|
||||
// Fall Through
|
||||
@@ -233,6 +237,10 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveChargeOffReasonToExpenseAccountMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveBuyDownFeeClassificationToIncomeAccountMappings(command, element,
|
||||
loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveCapitalizedIncomeClassificationToIncomeAccountMappings(command, element,
|
||||
loanProductId, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -411,6 +419,10 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
this.loanProductToGLAccountMappingHelper.updateChargesToIncomeAccountMappings(command, element, loanProductId, changes);
|
||||
this.loanProductToGLAccountMappingHelper.updateChargeOffReasonToExpenseAccountMappings(command, element, loanProductId,
|
||||
changes);
|
||||
this.loanProductToGLAccountMappingHelper.updateBuyDownFeeClassificationToIncomeAccountMappings(command, element, loanProductId,
|
||||
changes);
|
||||
this.loanProductToGLAccountMappingHelper.updateCapitalizedIncomeClassificationToIncomeAccountMappings(command, element,
|
||||
loanProductId, changes);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.codes.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* Created by sanyam on 30/7/17.
|
||||
*/
|
||||
final class CodeValuesApiResourceSwagger {
|
||||
|
||||
private CodeValuesApiResourceSwagger() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "GetCodeValuesDataResponse")
|
||||
public static final class GetCodeValuesDataResponse {
|
||||
|
||||
private GetCodeValuesDataResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long id;
|
||||
@Schema(example = "Passport")
|
||||
public String name;
|
||||
@Schema(example = "Passport information")
|
||||
public String description;
|
||||
@Schema(example = "0")
|
||||
public Integer position;
|
||||
}
|
||||
|
||||
@Schema(description = "PostCodeValuesDataRequest")
|
||||
public static final class PostCodeValuesDataRequest {
|
||||
|
||||
private PostCodeValuesDataRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "Passport")
|
||||
public String name;
|
||||
@Schema(example = "true")
|
||||
public Boolean isActive;
|
||||
@Schema(example = "Passport information")
|
||||
public String description;
|
||||
@Schema(example = "0")
|
||||
public Integer position;
|
||||
}
|
||||
|
||||
@Schema(description = "PostCodeValueDataResponse")
|
||||
public static final class PostCodeValueDataResponse {
|
||||
|
||||
private PostCodeValueDataResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
@Schema(example = "4")
|
||||
public Long subResourceId;
|
||||
}
|
||||
|
||||
@Schema(description = "PutCodeValuesDataRequest")
|
||||
public static final class PutCodeValuesDataRequest {
|
||||
|
||||
private PutCodeValuesDataRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "Passport")
|
||||
public String name;
|
||||
@Schema(example = "Passport information")
|
||||
public String description;
|
||||
@Schema(example = "0")
|
||||
public Integer position;
|
||||
@Schema(example = "true")
|
||||
public Boolean isActive;
|
||||
}
|
||||
|
||||
@Schema(description = "PutCodeValueDataResponse")
|
||||
public static final class PutCodeValueDataResponse {
|
||||
|
||||
private PutCodeValueDataResponse() {
|
||||
|
||||
}
|
||||
|
||||
private static final class PutCodeValuechangesSwagger {
|
||||
|
||||
private PutCodeValuechangesSwagger() {}
|
||||
|
||||
@Schema(example = "Passport")
|
||||
public String name;
|
||||
@Schema(example = "Passport information")
|
||||
public String description;
|
||||
@Schema(example = "0")
|
||||
public Integer position;
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
public PutCodeValuechangesSwagger changes;
|
||||
}
|
||||
|
||||
@Schema(description = "DeleteCodeValueDataResponse")
|
||||
public static final class DeleteCodeValueDataResponse {
|
||||
|
||||
private DeleteCodeValueDataResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
}
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.codes.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* Created by sanyam on 29/7/17.
|
||||
*/
|
||||
final class CodesApiResourceSwagger {
|
||||
|
||||
private CodesApiResourceSwagger() {
|
||||
// this class is only for Swagger Live Documentation
|
||||
}
|
||||
|
||||
@Schema(description = "GetCodesResponse")
|
||||
public static final class GetCodesResponse {
|
||||
|
||||
private GetCodesResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long id;
|
||||
@Schema(example = "Education")
|
||||
public String name;
|
||||
@Schema(example = "true")
|
||||
public boolean systemDefined;
|
||||
}
|
||||
|
||||
@Schema(description = "PostCodesRequest")
|
||||
public static final class PostCodesRequest {
|
||||
|
||||
private PostCodesRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "MyNewCode")
|
||||
public String name;
|
||||
}
|
||||
|
||||
@Schema(description = "PostCodesResponse")
|
||||
public static final class PostCodesResponse {
|
||||
|
||||
private PostCodesResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
}
|
||||
|
||||
@Schema(description = "PutCodesRequest")
|
||||
public static final class PutCodesRequest {
|
||||
|
||||
private PutCodesRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "MyNewCode(changed)")
|
||||
public String name;
|
||||
}
|
||||
|
||||
@Schema(description = "PutCodesResponse")
|
||||
public static final class PutCodesResponse {
|
||||
|
||||
private PutCodesResponse() {
|
||||
|
||||
}
|
||||
|
||||
private static final class PutCodesApichangesSwagger {
|
||||
|
||||
private PutCodesApichangesSwagger() {}
|
||||
|
||||
@Schema(example = "MyNewCode(changed)")
|
||||
public String name;
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
public PutCodesApichangesSwagger changes;
|
||||
}
|
||||
|
||||
@Schema(description = "DeleteCodesResponse")
|
||||
public static final class DeleteCodesResponse {
|
||||
|
||||
private DeleteCodesResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "4")
|
||||
public Long resourceId;
|
||||
}
|
||||
}
|
||||
+18
-2
@@ -46,10 +46,12 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ClassificationToGLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
@@ -82,6 +84,7 @@ import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlat
|
||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||
import org.apache.fineract.portfolio.fund.service.FundReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeCalculationType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeIncomeType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeStrategy;
|
||||
@@ -352,6 +355,8 @@ public class LoanProductsApiResource {
|
||||
Collection<ChargeToGLAccountMapper> feeToGLAccountMappings;
|
||||
Collection<ChargeToGLAccountMapper> penaltyToGLAccountMappings;
|
||||
List<ChargeOffReasonToGLAccountMapper> chargeOffReasonToGLAccountMappings;
|
||||
List<ClassificationToGLAccountData> capitalizedIncomeClassificationToGLAccountMappings;
|
||||
List<ClassificationToGLAccountData> buydowFeeClassificationToGLAccountMappings;
|
||||
if (loanProduct.hasAccountingEnabled()) {
|
||||
accountingMappings = this.accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId,
|
||||
loanProduct.getAccountingRule().getId().intValue());
|
||||
@@ -362,8 +367,14 @@ public class LoanProductsApiResource {
|
||||
.fetchPenaltyToIncomeAccountMappingsForLoanProduct(productId);
|
||||
chargeOffReasonToGLAccountMappings = this.accountMappingReadPlatformService
|
||||
.fetchChargeOffReasonMappingsForLoanProduct(productId);
|
||||
capitalizedIncomeClassificationToGLAccountMappings = accountMappingReadPlatformService
|
||||
.fetchClassificationMappingsForLoanProduct(productId,
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
buydowFeeClassificationToGLAccountMappings = accountMappingReadPlatformService.fetchClassificationMappingsForLoanProduct(
|
||||
productId, LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
feeToGLAccountMappings, penaltyToGLAccountMappings, chargeOffReasonToGLAccountMappings);
|
||||
feeToGLAccountMappings, penaltyToGLAccountMappings, chargeOffReasonToGLAccountMappings,
|
||||
capitalizedIncomeClassificationToGLAccountMappings, buydowFeeClassificationToGLAccountMappings);
|
||||
}
|
||||
|
||||
if (settings.isTemplate()) {
|
||||
@@ -464,6 +475,10 @@ public class LoanProductsApiResource {
|
||||
.getValuesAsStringEnumOptionDataList(LoanBuyDownFeeStrategy.class);
|
||||
final List<StringEnumOptionData> buyDownFeeIncomeTypeOptions = ApiFacingEnum
|
||||
.getValuesAsStringEnumOptionDataList(LoanBuyDownFeeIncomeType.class);
|
||||
final List<CodeValueData> capitalizedIncomeClassificationOptions = codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE);
|
||||
final List<CodeValueData> buydownFeeClassificationOptions = codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE);
|
||||
|
||||
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
|
||||
@@ -477,7 +492,8 @@ public class LoanProductsApiResource {
|
||||
LoanScheduleProcessingType.getValuesAsEnumOptionDataList(), creditAllocationTransactionTypes,
|
||||
creditAllocationAllocationTypes, supportedInterestRefundTypesOptions, chargeOffBehaviourOptions, chargeOffReasonOptions,
|
||||
daysInYearCustomStrategyOptions, capitalizedIncomeCalculationTypeOptions, capitalizedIncomeStrategyOptions,
|
||||
capitalizedIncomeTypeOptions, buyDownFeeCalculationTypeOptions, buyDownFeeStrategyOptions, buyDownFeeIncomeTypeOptions);
|
||||
capitalizedIncomeTypeOptions, buyDownFeeCalculationTypeOptions, buyDownFeeStrategyOptions, buyDownFeeIncomeTypeOptions,
|
||||
capitalizedIncomeClassificationOptions, buydownFeeClassificationOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+72
-2
@@ -49,6 +49,7 @@ import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeCalculationType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeIncomeType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeStrategy;
|
||||
@@ -202,7 +203,10 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.ENABLE_BUY_DOWN_FEE_PARAM_NAME, LoanProductConstants.BUY_DOWN_FEE_CALCULATION_TYPE_PARAM_NAME,
|
||||
LoanProductConstants.BUY_DOWN_FEE_STRATEGY_PARAM_NAME, LoanProductConstants.BUY_DOWN_FEE_INCOME_TYPE_PARAM_NAME,
|
||||
LoanProductAccountingParams.BUY_DOWN_EXPENSE.getValue(), LoanProductAccountingParams.INCOME_FROM_BUY_DOWN.getValue(),
|
||||
LoanProductConstants.MERCHANT_BUY_DOWN_FEE_PARAM_NAME));
|
||||
LoanProductConstants.MERCHANT_BUY_DOWN_FEE_PARAM_NAME,
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue(), //
|
||||
LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue() //
|
||||
));
|
||||
|
||||
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
||||
@@ -744,7 +748,10 @@ public final class LoanProductDataValidator {
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
validateChargeOffToExpenseMappings(baseDataValidator, element);
|
||||
|
||||
validateClassificationToIncomeMappings(baseDataValidator, element,
|
||||
LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
validateClassificationToIncomeMappings(baseDataValidator, element,
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
}
|
||||
|
||||
if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
@@ -1877,6 +1884,10 @@ public final class LoanProductDataValidator {
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
validateChargeOffToExpenseMappings(baseDataValidator, element);
|
||||
validateClassificationToIncomeMappings(baseDataValidator, element,
|
||||
LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
validateClassificationToIncomeMappings(baseDataValidator, element,
|
||||
LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS);
|
||||
|
||||
validateMinMaxConstraints(element, baseDataValidator, loanProduct);
|
||||
|
||||
@@ -2109,6 +2120,65 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateClassificationToIncomeMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final LoanProductAccountingParams classificationParameter) {
|
||||
String parameterName = classificationParameter.getValue();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray classificationToIncomeMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (classificationToIncomeMappingArray != null && classificationToIncomeMappingArray.size() > 0) {
|
||||
Map<Long, Set<Long>> classificationToAccounts = new HashMap<>();
|
||||
List<JsonObject> processedMappings = new ArrayList<>(); // Collect processed mappings for the new method
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = classificationToIncomeMappingArray.get(i).getAsJsonObject();
|
||||
final Long incomeGlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
final Long classificationCodeValueId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.CLASSIFICATION_CODE_VALUE_ID.getValue(), jsonObject);
|
||||
|
||||
// Validate parameters locally
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + OPENING_SQUARE_BRACKET + i + CLOSING_SQUARE_BRACKET + DOT
|
||||
+ LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeGlAccountId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + OPENING_SQUARE_BRACKET + i + CLOSING_SQUARE_BRACKET + DOT
|
||||
+ LoanProductAccountingParams.CLASSIFICATION_CODE_VALUE_ID.getValue())
|
||||
.value(classificationCodeValueId).notNull().integerGreaterThanZero();
|
||||
|
||||
// Handle duplicate classification and GL Account validation
|
||||
classificationToAccounts.putIfAbsent(classificationCodeValueId, new HashSet<>());
|
||||
Set<Long> associatedAccounts = classificationToAccounts.get(classificationCodeValueId);
|
||||
|
||||
if (associatedAccounts.contains(incomeGlAccountId)) {
|
||||
baseDataValidator.reset().parameter(parameterName + OPENING_SQUARE_BRACKET + i + CLOSING_SQUARE_BRACKET)
|
||||
.failWithCode("duplicate.classification.and.glAccount");
|
||||
}
|
||||
associatedAccounts.add(incomeGlAccountId);
|
||||
|
||||
if (associatedAccounts.size() > 1) {
|
||||
baseDataValidator.reset().parameter(parameterName + OPENING_SQUARE_BRACKET + i + CLOSING_SQUARE_BRACKET)
|
||||
.failWithCode("multiple.glAccounts.for.classification");
|
||||
}
|
||||
|
||||
// Collect mapping for additional validations
|
||||
processedMappings.add(jsonObject);
|
||||
|
||||
i++;
|
||||
} while (i < classificationToIncomeMappingArray.size());
|
||||
|
||||
// Call the new validation method for additional checks
|
||||
final String dataCodeName = classificationParameter
|
||||
.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)
|
||||
? LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE
|
||||
: LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE;
|
||||
productToGLAccountMappingHelper.validateClassificationMappingsInDatabase(processedMappings, dataCodeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateMinMaxConstraints(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
||||
final LoanProduct loanProduct) {
|
||||
validatePrincipalMinMaxConstraint(element, loanProduct, baseDataValidator);
|
||||
|
||||
@@ -216,4 +216,5 @@
|
||||
<include file="parts/0195_create_loan_amortization_allocation_mapping.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0196_add_deleted_and_closed_to_buy_down_fee_balance.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0197_add_deleted_and_closed_to_capitalized_income_balance.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0198_add_classification_id_to_acc_product_mapping.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
|
||||
<changeSet id="1" author="fineract">
|
||||
<addColumn tableName="acc_product_mapping">
|
||||
<column name="capitalized_income_classification_id" type="INT" defaultValueNumeric="NULL">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="acc_product_mapping"
|
||||
baseColumnNames="capitalized_income_classification_id"
|
||||
referencedTableName="m_code_value"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_acc_product_mapping_capitalized_income_classification"/>
|
||||
</changeSet>
|
||||
<changeSet id="2" author="fineract">
|
||||
<addColumn tableName="acc_product_mapping">
|
||||
<column name="buydown_fee_classification_id" type="INT" defaultValueNumeric="NULL">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="acc_product_mapping"
|
||||
baseColumnNames="buydown_fee_classification_id"
|
||||
referencedTableName="m_code_value"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_acc_product_mapping_buydown_fee_classification"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+1
-1
@@ -73,7 +73,7 @@ class CreateJournalEntriesForChargeOffLoanTest {
|
||||
Collections.emptyList(), false, "", null, null, null, null);
|
||||
|
||||
loanDTO = new LoanDTO(1L, 1L, 1L, "USD", false, true, true, List.of(loanTransactionDTO), false, false, chargeOffReasonId, false,
|
||||
false);
|
||||
false, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user