FINERACT-2080: Extract DTO mappers from loan entity

This commit is contained in:
Oleksii Novikov
2025-04-07 13:13:35 +02:00
committed by Adam Saghy
parent b01dca3ecc
commit 2ba7e28108
28 changed files with 995 additions and 776 deletions
@@ -29,8 +29,8 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.closure.domain.GLClosure;
import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
import org.apache.fineract.accounting.common.AccountingConstants;
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
@@ -68,12 +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.ClientTransactionRepository;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
import org.springframework.dao.DataAccessException;
@@ -92,55 +91,53 @@ public class AccountingProcessorHelper {
private final GLClosureRepository closureRepository;
private final GLAccountRepository glAccountRepository;
private final OfficeRepository officeRepository;
private final LoanTransactionRepository loanTransactionRepository;
private final ClientTransactionRepository clientTransactionRepository;
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
private final ChargeRepositoryWrapper chargeRepositoryWrapper;
private final BusinessEventNotifierService businessEventNotifierService;
public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
final boolean upfrontAccrualBasedAccountingEnabled, final boolean periodicAccrualBasedAccountingEnabled) {
final Long loanId = (Long) accountingBridgeData.get("loanId");
final Long loanProductId = (Long) accountingBridgeData.get("loanProductId");
final Long officeId = (Long) accountingBridgeData.get("officeId");
final String currencyCode = (String) accountingBridgeData.get("currencyCode");
public LoanDTO populateLoanDtoFromDTO(
final org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO accountingBridgeData) {
final Long loanId = accountingBridgeData.getLoanId();
final Long loanProductId = accountingBridgeData.getLoanProductId();
final Long officeId = accountingBridgeData.getOfficeId();
final String currencyCode = accountingBridgeData.getCurrencyCode();
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<>();
boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer");
boolean isLoanMarkedAsChargeOff = (Boolean) accountingBridgeData.get("isChargeOff");
boolean isLoanMarkedAsFraud = (Boolean) accountingBridgeData.get("isFraud");
final Long chargeOffReasonCodeValue = (Long) accountingBridgeData.get("chargeOffReasonCodeValue");
boolean isAccountTransfer = accountingBridgeData.isAccountTransfer();
boolean isLoanMarkedAsChargeOff = accountingBridgeData.isChargeOff();
boolean isLoanMarkedAsFraud = accountingBridgeData.isFraud();
final Long chargeOffReasonCodeValue = accountingBridgeData.getChargeOffReasonCodeValue();
final boolean cashBasedAccountingEnabled = accountingBridgeData.isCashBasedAccountingEnabled();
final boolean upfrontAccrualBasedAccountingEnabled = accountingBridgeData.isUpfrontAccrualBasedAccountingEnabled();
final boolean periodicAccrualBasedAccountingEnabled = accountingBridgeData.isPeriodicAccrualBasedAccountingEnabled();
@SuppressWarnings("unchecked")
final List<Map<String, Object>> newTransactionsMap = (List<Map<String, Object>>) accountingBridgeData.get("newLoanTransactions");
final List<AccountingBridgeLoanTransactionDTO> loanTransactionDTOs = accountingBridgeData.getNewLoanTransactions();
for (final Map<String, Object> map : newTransactionsMap) {
final Long transactionOfficeId = (Long) map.get("officeId");
final String transactionId = ((Long) map.get("id")).toString();
final LocalDate transactionDate = ((LocalDate) map.get("date"));
final LoanTransactionEnumData transactionType = (LoanTransactionEnumData) map.get("type");
final BigDecimal amount = (BigDecimal) map.get("amount");
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
final BigDecimal overPayments = (BigDecimal) map.get("overPaymentPortion");
final boolean reversed = (Boolean) map.get("reversed");
final Long paymentTypeId = (Long) map.get("paymentTypeId");
final String chargeRefundChargeType = (String) map.get("chargeRefundChargeType");
final LoanChargeData loanChargeData = (LoanChargeData) map.get("loanChargeData");
for (final AccountingBridgeLoanTransactionDTO loanTxnDto : loanTransactionDTOs) {
final Long transactionOfficeId = loanTxnDto.getOfficeId();
final String transactionId = loanTxnDto.getId().toString();
final LocalDate transactionDate = loanTxnDto.getDate();
final LoanTransactionEnumData transactionType = loanTxnDto.getType();
final BigDecimal amount = loanTxnDto.getAmount();
final BigDecimal principal = loanTxnDto.getPrincipalPortion();
final BigDecimal interest = loanTxnDto.getInterestPortion();
final BigDecimal fees = loanTxnDto.getFeeChargesPortion();
final BigDecimal penalties = loanTxnDto.getPenaltyChargesPortion();
final BigDecimal overPayments = loanTxnDto.getOverPaymentPortion();
final boolean reversed = loanTxnDto.isReversed();
final Long paymentTypeId = loanTxnDto.getPaymentTypeId();
final String chargeRefundChargeType = loanTxnDto.getChargeRefundChargeType();
final LoanChargeData loanChargeData = loanTxnDto.getLoanChargeData();
final List<ChargePaymentDTO> feePaymentDetails = new ArrayList<>();
final List<ChargePaymentDTO> penaltyPaymentDetails = new ArrayList<>();
// extract charge payment details (if exists)
if (map.containsKey("loanChargesPaid")) {
@SuppressWarnings("unchecked")
final List<Map<String, Object>> loanChargesPaidData = (List<Map<String, Object>>) map.get("loanChargesPaid");
for (final Map<String, Object> loanChargePaid : loanChargesPaidData) {
final Long chargeId = (Long) loanChargePaid.get("chargeId");
final Long loanChargeId = (Long) loanChargePaid.get("loanChargeId");
final boolean isPenalty = (Boolean) loanChargePaid.get("isPenalty");
final BigDecimal chargeAmountPaid = (BigDecimal) loanChargePaid.get("amount");
if (loanTxnDto.getLoanChargesPaid() != null) {
List<LoanChargePaidByDTO> loanChargesPaidData = loanTxnDto.getLoanChargesPaid();
for (final LoanChargePaidByDTO loanChargePaid : loanChargesPaidData) {
final Long chargeId = loanChargePaid.getChargeId();
final Long loanChargeId = loanChargePaid.getLoanChargeId();
final boolean isPenalty = loanChargePaid.getIsPenalty();
final BigDecimal chargeAmountPaid = loanChargePaid.getAmount();
final ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, chargeAmountPaid, loanChargeId);
if (isPenalty) {
penaltyPaymentDetails.add(chargePaymentDTO);
@@ -150,23 +147,23 @@ public class AccountingProcessorHelper {
}
}
if (!isAccountTransfer) {
isAccountTransfer = this.accountTransfersReadPlatformService.isAccountTransfer(Long.parseLong(transactionId),
boolean localIsAccountTransfer = isAccountTransfer;
if (!localIsAccountTransfer) {
localIsAccountTransfer = this.accountTransfersReadPlatformService.isAccountTransfer(Long.parseLong(transactionId),
PortfolioAccountType.LOAN);
}
BigDecimal principalPaid = (BigDecimal) map.get("principalPaid");
BigDecimal feePaid = (BigDecimal) map.get("feePaid");
BigDecimal penaltyPaid = (BigDecimal) map.get("penaltyPaid");
BigDecimal principalPaid = loanTxnDto.getPrincipalPaid();
BigDecimal feePaid = loanTxnDto.getFeePaid();
BigDecimal penaltyPaid = loanTxnDto.getPenaltyPaid();
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed,
penaltyPaymentDetails, feePaymentDetails, isAccountTransfer, chargeRefundChargeType, loanChargeData, principalPaid,
penaltyPaymentDetails, feePaymentDetails, localIsAccountTransfer, chargeRefundChargeType, loanChargeData, principalPaid,
feePaid, penaltyPaid);
Boolean isLoanToLoanTransfer = (Boolean) accountingBridgeData.get("isLoanToLoanTransfer");
transaction.setLoanToLoanTransfer(isLoanToLoanTransfer != null && isLoanToLoanTransfer);
newLoanTransactions.add(transaction);
transaction.setLoanToLoanTransfer(loanTxnDto.isLoanToLoanTransfer());
newLoanTransactions.add(transaction);
}
return new LoanDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled,
@@ -559,10 +556,10 @@ public class AccountingProcessorHelper {
}
public void createAccrualBasedJournalEntriesAndReversalsForSavingsTax(final Office office, final String currencyCode,
final AccrualAccountsForSavings accountTypeToBeDebited, final AccrualAccountsForSavings accountTypeToBeCredited,
final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeDebited,
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeCredited, final Long savingsProductId,
final Long paymentTypeId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
for (TaxPaymentDTO taxPaymentDTO : taxDetails) {
if (taxPaymentDTO.getAmount() != null) {
if (taxPaymentDTO.getCreditAccountId() == null) {
@@ -769,10 +766,10 @@ public class AccountingProcessorHelper {
}
public void createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
final AccrualAccountsForSavings accountTypeToBeDebited, AccrualAccountsForSavings accountTypeToBeCredited,
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
final List<ChargePaymentDTO> chargePaymentDTOs) {
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeDebited,
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeCredited, final Long savingsProductId,
final Long paymentTypeId, final Long loanId, final String transactionId, final LocalDate transactionDate,
final BigDecimal totalAmount, final Boolean isReversal, final List<ChargePaymentDTO> chargePaymentDTOs) {
// TODO Vishwas: Remove this validation, as and when appropriate Junit
// tests are written for accounting
/**
@@ -24,6 +24,7 @@ import java.util.Map;
import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
public interface JournalEntryWritePlatformService {
@@ -31,7 +32,7 @@ public interface JournalEntryWritePlatformService {
CommandProcessingResult revertJournalEntry(JsonCommand command);
void createJournalEntriesForLoan(Map<String, Object> accountingBridgeData);
void createJournalEntriesForLoan(AccountingBridgeDataDTO accountingBridgeData);
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
@@ -75,6 +75,7 @@ import org.apache.fineract.organisation.monetary.domain.OrganisationCurrencyRepo
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
import org.apache.fineract.portfolio.PortfolioProductType;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
@@ -480,15 +481,13 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
@Transactional
@Override
public void createJournalEntriesForLoan(final Map<String, Object> accountingBridgeData) {
final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled");
final boolean upfrontAccrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("upfrontAccrualBasedAccountingEnabled");
final boolean periodicAccrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("periodicAccrualBasedAccountingEnabled");
public void createJournalEntriesForLoan(final AccountingBridgeDataDTO accountingBridgeData) {
final boolean cashBasedAccountingEnabled = accountingBridgeData.isCashBasedAccountingEnabled();
final boolean upfrontAccrualBasedAccountingEnabled = accountingBridgeData.isUpfrontAccrualBasedAccountingEnabled();
final boolean periodicAccrualBasedAccountingEnabled = accountingBridgeData.isPeriodicAccrualBasedAccountingEnabled();
if (cashBasedAccountingEnabled || upfrontAccrualBasedAccountingEnabled || periodicAccrualBasedAccountingEnabled) {
final LoanDTO loanDTO = this.helper.populateLoanDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
upfrontAccrualBasedAccountingEnabled, periodicAccrualBasedAccountingEnabled);
final LoanDTO loanDTO = this.helper.populateLoanDtoFromDTO(accountingBridgeData);
final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory
.determineProcessor(loanDTO);
accountingProcessorForLoan.createJournalEntriesForLoan(loanDTO);
@@ -46,10 +46,7 @@ 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.client.domain.ClientTransactionRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -63,14 +60,11 @@ public class AccountingJournalEntryConfiguration {
public AccountingProcessorHelper accountingProcessorHelper(JournalEntryRepository glJournalEntryRepository,
ProductToGLAccountMappingRepository accountMappingRepository,
FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository, GLClosureRepository closureRepository,
GLAccountRepository glAccountRepository, OfficeRepository officeRepository, LoanTransactionRepository loanTransactionRepository,
ClientTransactionRepository clientTransactionRepository,
SavingsAccountTransactionRepository savingsAccountTransactionRepository,
GLAccountRepository glAccountRepository, OfficeRepository officeRepository,
AccountTransfersReadPlatformService accountTransfersReadPlatformService, ChargeRepositoryWrapper chargeRepositoryWrapper,
BusinessEventNotifierService businessEventNotifierService) {
return new AccountingProcessorHelper(glJournalEntryRepository, accountMappingRepository, financialActivityAccountRepository,
closureRepository, glAccountRepository, officeRepository, loanTransactionRepository, clientTransactionRepository,
savingsAccountTransactionRepository, accountTransfersReadPlatformService, chargeRepositoryWrapper,
closureRepository, glAccountRepository, officeRepository, accountTransfersReadPlatformService, chargeRepositoryWrapper,
businessEventNotifierService);
}
@@ -87,6 +87,7 @@ import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatfor
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
@@ -94,6 +95,7 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanForeclosureValidator;
@@ -157,6 +159,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private final LoanRefundService loanRefundService;
private final LoanAccountService loanAccountService;
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
@Transactional
@Override
@@ -449,19 +452,26 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final MonetaryCurrency currency = loanAccount.getCurrency();
List<Map<String, Object>> accountingBridgeData = new ArrayList<>();
if (loanAccount.isChargedOff()) {
accountingBridgeData = loanAccount.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
} else {
accountingBridgeData.add(loanAccount.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer));
}
for (Map<String, Object> accountingData : accountingBridgeData) {
accountingData.put("isLoanToLoanTransfer", isLoanToLoanTransfer);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingData);
}
final List<AccountingBridgeDataDTO> accountingBridgeDataList = loanAccountingBridgeMapper
.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds, existingReversedTransactionIds,
isAccountTransfer, loanAccount);
if (isLoanToLoanTransfer) {
accountingBridgeDataList.forEach(dto -> dto.getNewLoanTransactions().forEach(tx -> tx.setLoanToLoanTransfer(true)));
}
for (AccountingBridgeDataDTO accountingBridgeData : accountingBridgeDataList) {
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
} else {
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loanAccount);
if (isLoanToLoanTransfer) {
accountingBridgeData.getNewLoanTransactions().forEach(tx -> tx.setLoanToLoanTransfer(true));
}
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
}
private void checkClientOrGroupActive(final Loan loan) {
@@ -985,7 +995,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final List<LoanRepaymentScheduleInstallment> newInstallments = new ArrayList<>(loan.getRepaymentScheduleInstallments());
final MonetaryCurrency currency = loan.getCurrency();
Money totalPrincipal = Money.zero(currency);
final Money[] balances = loan.retriveIncomeForOverlappingPeriod(transactionDate);
final Money[] balances = loan.retrieveIncomeForOverlappingPeriod(transactionDate);
boolean isInterestComponent = true;
for (final LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
if (!DateUtils.isAfter(transactionDate, installment.getDueDate())) {
@@ -42,6 +42,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
@@ -59,6 +60,7 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final LoanUtilService loanUtilService;
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanTermVariationsMapper loanTermVariationsMapper;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
@@ -120,7 +122,8 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
private void adjustRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
loan);
// first repayment's from date is same as disbursement date.
LocalDate tmpFromDate = loan.getDisbursementDate();
@@ -152,7 +155,8 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
private void adjustAllRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
loan);
// first repayment's from date is same as disbursement date.
LocalDate tmpFromDate = loan.getDisbursementDate();
@@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleD
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanScheduleValidator;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
@@ -63,6 +64,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
private final LoanUtilService loanUtilService;
private final LoanRepositoryWrapper loanRepository;
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
private final LoanTermVariationsMapper loanTermVariationsMapper;
@Override
public LoanScheduleModel calculateLoanSchedule(final JsonQuery query, Boolean validateParams) {
@@ -204,7 +206,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
private LoanApplicationTerms constructLoanApplicationTerms(final Loan loan) {
final LocalDate recalculateFrom = null;
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
return loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
return loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO, loan);
}
private Loan fetchLoan(final Long accountId) {
@@ -23,6 +23,7 @@ import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
@@ -38,32 +39,23 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplica
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
private static final DefaultScheduledDateGenerator DEFAULT_SCHEDULED_DATE_GENERATOR = new DefaultScheduledDateGenerator();
private final LoanRescheduleRequestRepositoryWrapper loanRescheduleRequestRepository;
private final LoanUtilService loanUtilService;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final LoanScheduleGeneratorFactory loanScheduleFactory;
private static final DefaultScheduledDateGenerator DEFAULT_SCHEDULED_DATE_GENERATOR = new DefaultScheduledDateGenerator();
@Autowired
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepositoryWrapper loanRescheduleRequestRepository,
final LoanUtilService loanUtilService,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanScheduleGeneratorFactory loanScheduleFactory) {
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
this.loanUtilService = loanUtilService;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.loanScheduleFactory = loanScheduleFactory;
}
private final LoanTermVariationsMapper loanTermVariationsMapper;
@Override
public LoanScheduleModel previewLoanReschedule(Long requestId) {
@@ -80,7 +72,8 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
loanRescheduleRequest.getRescheduleFromDate());
LocalDate rescheduleFromDate = null;
List<LoanTermVariationsData> removeLoanTermVariationsData = new ArrayList<>();
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
loan);
LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
if (dueDateVariationInCurrentRequest != null) {
for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
@@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -68,6 +69,8 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepayme
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
@@ -116,6 +119,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
private final LoanChargeService loanChargeService;
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
private final LoanTermVariationsMapper loanTermVariationsMapper;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
private final LoanScheduleComponent loanSchedule;
/**
@@ -363,7 +368,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
loan);
LocalDate rescheduleFromDate = null;
List<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
@@ -403,7 +409,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
}
BigDecimal annualNominalInterestRate = null;
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
loan.constructLoanTermVariations(scheduleGeneratorDTO.getFloatingRateDTO(), annualNominalInterestRate, loanTermVariations);
loanTermVariationsMapper.constructLoanTermVariations(scheduleGeneratorDTO.getFloatingRateDTO(), annualNominalInterestRate,
loanTermVariations, loan);
loanApplicationTerms.getLoanTermVariations().setExceptionData(loanTermVariations);
/*
@@ -495,8 +502,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
private void postJournalEntries(Loan loan, List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds) {
final MonetaryCurrency currency = loan.getCurrency();
boolean isAccountTransfer = false;
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
@@ -28,6 +28,7 @@ import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -90,6 +91,7 @@ import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
@@ -109,6 +111,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
@@ -200,6 +203,7 @@ public final class LoanApplicationValidator {
private final CalendarInstanceRepository calendarInstanceRepository;
private final LoanUtilService loanUtilService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final LoanMapper loanMapper;
public void validateForCreate(final Loan loan) {
final LocalDate expectedFirstRepaymentOnDate = loan.getExpectedFirstRepaymentOnDate();
@@ -1404,12 +1408,11 @@ public final class LoanApplicationValidator {
BigDecimal loanOutstanding = this.loanReadPlatformService
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate)
.getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
final BigDecimal firstDisbursalAmount = getFirstDisbursalAmount(loan);
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
}
}
}
@@ -1953,7 +1956,7 @@ public final class LoanApplicationValidator {
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
}
public void validateTopupLoan(Loan loan, LocalDate expectedDisbursementDate) {
public BigDecimal validateTopupLoan(final Loan loan, final LocalDate disbursementDate) {
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
final Loan loanToClose = loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
if (loanToClose == null) {
@@ -1969,16 +1972,15 @@ public final class LoanApplicationValidator {
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
}
BigDecimal loanOutstanding = loanReadPlatformService
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
final BigDecimal loanOutstanding = loanReadPlatformService
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, disbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = getFirstDisbursalAmount(loan);
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
}
BigDecimal netDisbursalAmount = loan.getApprovedPrincipal().subtract(loanOutstanding);
loan.adjustNetDisbursalAmount(netDisbursalAmount);
return loanOutstanding;
}
public void validateApproval(JsonCommand command, Long loanId) {
@@ -2074,7 +2076,9 @@ public final class LoanApplicationValidator {
StatusEnum.APPROVE.getValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
if (loan.isTopup() && loan.getClientId() != null) {
validateTopupLoan(loan, expectedDisbursementDate);
final BigDecimal loanOutstanding = validateTopupLoan(loan, expectedDisbursementDate);
final BigDecimal netDisbursalAmountAdjusted = loan.getApprovedPrincipal().subtract(loanOutstanding);
loan.adjustNetDisbursalAmount(netDisbursalAmountAdjusted);
}
if (!loan.getStatus().isSubmittedAndPendingApproval()) {
@@ -2202,4 +2206,18 @@ public final class LoanApplicationValidator {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
private BigDecimal getFirstDisbursalAmount(final Loan loan) {
BigDecimal firstDisbursalAmount;
if (loan.isMultiDisburmentLoan()) {
List<DisbursementData> disbursementData = loanMapper.getDisbursementData(loan);
Collections.sort(disbursementData);
firstDisbursalAmount = disbursementData.get(disbursementData.size() - 1).getPrincipal();
} else {
firstDisbursalAmount = loan.getLoanRepaymentScheduleDetail().getPrincipal().getAmount();
}
return firstDisbursalAmount;
}
}
@@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -60,6 +59,8 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
import org.apache.fineract.portfolio.loanaccount.data.AccrualBalances;
import org.apache.fineract.portfolio.loanaccount.data.AccrualChargeData;
import org.apache.fineract.portfolio.loanaccount.data.AccrualPeriodData;
@@ -79,6 +80,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepayme
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -109,6 +111,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
@Qualifier(TaskExecutorConstant.CONFIGURABLE_TASK_EXECUTOR_BEAN_NAME)
private final ThreadPoolTaskExecutor taskExecutor;
private final TransactionTemplate transactionTemplate;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
/**
* method adds accrual for batch job "Add Periodic Accrual Transactions" and add accruals api for Loan
@@ -413,7 +416,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
if (!isFinal || progressiveAccrual) {
loan.setAccruedTill(isFinal ? accrualDate : tillDate);
}
ArrayList<Map<String, Object>> newTransactionMapping = new ArrayList<>();
List<AccountingBridgeLoanTransactionDTO> newTransactionDTOs = new ArrayList<>();
for (LoanTransaction accrualTransaction : accrualTransactions) {
accrualTransaction = loanTransactionRepository.saveAndFlush(accrualTransaction);
if (addJournal) {
@@ -421,11 +424,17 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
? new LoanAccrualTransactionCreatedBusinessEvent(accrualTransaction)
: new LoanAccrualAdjustmentTransactionBusinessEvent(accrualTransaction);
businessEventNotifierService.notifyPostBusinessEvent(businessEvent);
newTransactionMapping.add(accrualTransaction.toMapData(currency.getCode()));
AccountingBridgeLoanTransactionDTO transactionDTO = loanAccountingBridgeMapper.mapToLoanTransactionData(accrualTransaction,
currency.getCode());
newTransactionDTOs.add(transactionDTO);
}
}
if (addJournal) {
Map<String, Object> accountingBridgeData = deriveAccountingBridgeData(loan, newTransactionMapping);
AccountingBridgeDataDTO accountingBridgeData = new AccountingBridgeDataDTO(loan.getId(), loan.getLoanProduct().getId(),
loan.getOfficeId(), loan.getCurrencyCode(), loan.getSummary().getTotalInterestCharged(),
loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct(),
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(), false,
false, false, null, newTransactionDTOs);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
}
@@ -1110,30 +1119,12 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
}
}
// Utility
private Map<String, Object> deriveAccountingBridgeData(@NotNull Loan loan, List<Map<String, Object>> newLoanTransactions) {
final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
accountingBridgeData.put("loanId", loan.getId());
accountingBridgeData.put("loanProductId", loan.getLoanProduct().getId());
accountingBridgeData.put("officeId", loan.getOfficeId());
accountingBridgeData.put("currencyCode", loan.getCurrencyCode());
accountingBridgeData.put("cashBasedAccountingEnabled", loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct());
accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", loan.isUpfrontAccrualAccountingEnabledOnLoanProduct());
accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", loan.isPeriodicAccrualAccountingEnabledOnLoanProduct());
accountingBridgeData.put("isAccountTransfer", false);
accountingBridgeData.put("isChargeOff", false);
accountingBridgeData.put("isFraud", false);
accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
return accountingBridgeData;
}
private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) {
final MonetaryCurrency currency = loan.getCurrency();
boolean isAccountTransfer = false;
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
@@ -90,6 +90,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -128,6 +129,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanSc
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
@@ -178,6 +180,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
private final LoanAccountService loanAccountService;
private final LoanAdjustmentService loanAdjustmentService;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
return DateUtils.isAfter(loanCharge.getDueDate(), e.getFromDate()) && !DateUtils.isAfter(loanCharge.getDueDate(), e.getDueDate());
@@ -929,8 +932,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(loan.getCurrency().getCode(),
existingTransactionIds, existingReversedTransactionIds, false);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(
loan.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, false, loan);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
loanAccountDomainService.setLoanDelinquencyTag(loan, transactionDate);
@@ -1302,8 +1305,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
final MonetaryCurrency currency = loan.getCurrency();
boolean isAccountTransfer = false;
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
@@ -24,15 +24,18 @@ import com.google.common.base.Splitter;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
@@ -76,14 +79,14 @@ public class LoanDisbursementService {
if (disbursementDataArray != null && !disbursementDataArray.isEmpty()) {
String dateFormat;
Locale locale = null;
final Map<String, String> dateAndLocale = loan.getDateFormatAndLocale(jsonCommand);
final Map<String, String> dateAndLocale = getDateFormatAndLocale(jsonCommand);
dateFormat = dateAndLocale.get(LoanApiConstants.dateFormatParameterName);
if (dateAndLocale.containsKey(LoanApiConstants.localeParameterName)) {
locale = JsonParserHelper.localeFromString(dateAndLocale.get(LoanApiConstants.localeParameterName));
}
for (JsonElement jsonElement : disbursementDataArray) {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
final Map<String, Object> parsedDisbursementData = loan.parseDisbursementDetails(jsonObject, dateFormat, locale);
final Map<String, Object> parsedDisbursementData = parseDisbursementDetails(jsonObject, dateFormat, locale);
final LocalDate expectedDisbursementDate = (LocalDate) parsedDisbursementData
.get(LoanApiConstants.expectedDisbursementDateParameterName);
final BigDecimal principal = (BigDecimal) parsedDisbursementData
@@ -298,4 +301,63 @@ public class LoanDisbursementService {
}) //
.forEach(loanCharge -> reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge));
}
// This method returns date format and locale if present in the JsonCommand
private Map<String, String> getDateFormatAndLocale(final JsonCommand jsonCommand) {
Map<String, String> returnObject = new HashMap<>();
JsonElement jsonElement = jsonCommand.parsedJson();
if (jsonElement.isJsonObject()) {
JsonObject topLevel = jsonElement.getAsJsonObject();
if (topLevel.has(LoanApiConstants.dateFormatParameterName)
&& topLevel.get(LoanApiConstants.dateFormatParameterName).isJsonPrimitive()) {
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.dateFormatParameterName).getAsJsonPrimitive();
returnObject.put(LoanApiConstants.dateFormatParameterName, primitive.getAsString());
}
if (topLevel.has(LoanApiConstants.localeParameterName)
&& topLevel.get(LoanApiConstants.localeParameterName).isJsonPrimitive()) {
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.localeParameterName).getAsJsonPrimitive();
String localeString = primitive.getAsString();
returnObject.put(LoanApiConstants.localeParameterName, localeString);
}
}
return returnObject;
}
private Map<String, Object> parseDisbursementDetails(final JsonObject jsonObject, String dateFormat, Locale locale) {
Map<String, Object> returnObject = new HashMap<>();
if (jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName) != null
&& jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).isJsonPrimitive()) {
final JsonPrimitive primitive = jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
LocalDate date = JsonParserHelper.convertFrom(valueAsString, LoanApiConstants.expectedDisbursementDateParameterName,
dateFormat, locale);
if (date != null) {
returnObject.put(LoanApiConstants.expectedDisbursementDateParameterName, date);
}
}
}
if (jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString())) {
BigDecimal principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
returnObject.put(LoanApiConstants.disbursementPrincipalParameterName, principal);
}
if (jsonObject.has(LoanApiConstants.disbursementIdParameterName)
&& jsonObject.get(LoanApiConstants.disbursementIdParameterName).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementIdParameterName).getAsString())) {
Long id = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementIdParameterName).getAsLong();
returnObject.put(LoanApiConstants.disbursementIdParameterName, id);
}
if (jsonObject.has(LoanApiConstants.loanChargeIdParameterName)
&& jsonObject.get(LoanApiConstants.loanChargeIdParameterName).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.loanChargeIdParameterName).getAsString())) {
returnObject.put(LoanApiConstants.loanChargeIdParameterName,
jsonObject.getAsJsonPrimitive(LoanApiConstants.loanChargeIdParameterName).getAsString());
}
return returnObject;
}
}
@@ -18,13 +18,13 @@
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.springframework.stereotype.Component;
@Component
@@ -32,23 +32,24 @@ import org.springframework.stereotype.Component;
public class LoanJournalEntryPoster {
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
public void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) {
final MonetaryCurrency currency = loan.getCurrency();
boolean isAccountTransfer = false;
List<Map<String, Object>> accountingBridgeData = new ArrayList<>();
if (loan.isChargedOff()) {
accountingBridgeData = loan.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
} else {
accountingBridgeData.add(loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer));
}
for (Map<String, Object> accountingData : accountingBridgeData) {
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingData);
}
if (loan.isChargedOff()) {
List<AccountingBridgeDataDTO> accountingBridgeDataList = loanAccountingBridgeMapper.deriveAccountingBridgeDataForChargeOff(
currency.getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
for (AccountingBridgeDataDTO accountingBridgeData : accountingBridgeDataList) {
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
} else {
AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
}
}
@@ -38,7 +38,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
@@ -141,15 +141,13 @@ import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@AllArgsConstructor
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, LoanReadPlatformServiceCommon {
private static final String ACCRUAL_ON_CHARGE_SUBMITTED_ON_DATE = "submitted-date";
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final LoanRepositoryWrapper loanRepositoryWrapper;
@@ -164,7 +162,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
private final CalendarReadPlatformService calendarReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final PaginationHelper paginationHelper;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
@@ -179,6 +176,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
private final LoanTransactionRelationReadService loanTransactionRelationReadService;
private final LoanForeclosureValidator loanForeclosureValidator;
private final LoanTransactionMapper loanTransactionMapper;
private final org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper loanMapper;
private final LoanTransactionProcessingService loadTransactionProcessingService;
@Override
@@ -149,6 +149,7 @@ import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand;
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
@@ -163,7 +164,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachin
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
@@ -195,6 +195,8 @@ import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDoma
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
@@ -247,14 +249,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final FromJsonHelper fromApiJsonHelper;
private final CalendarRepository calendarRepository;
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
private final LoanApplicationValidator loanApplicationCommandFromApiJsonHelper;
private final LoanApplicationValidator loanApplicationValidator;
private final AccountAssociationsRepository accountAssociationRepository;
private final AccountTransferDetailRepository accountTransferDetailRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final GuarantorDomainService guarantorDomainService;
private final LoanUtilService loanUtilService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
private final CodeValueRepositoryWrapper codeValueRepository;
private final CashierTransactionDataValidator cashierTransactionDataValidator;
private final GLIMAccountInfoRepository glimRepository;
@@ -280,6 +281,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanAccountService loanAccountService;
private final LoanJournalEntryPoster journalEntryPoster;
private final LoanAdjustmentService loanAdjustmentService;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
private final LoanMapper loanMapper;
private final LoanTransactionProcessingService loanTransactionProcessingService;
@Transactional
@@ -378,27 +381,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName);
if (loan.isTopup() && loan.getClientId() != null) {
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
final Loan loanToClose = this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
if (loanToClose == null) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active",
"Loan to be closed with this topup is not active.");
}
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + loan.getDisbursementDate()
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
}
BigDecimal loanOutstanding = this.loanReadPlatformService
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, actualDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
}
final BigDecimal loanOutstanding = loanApplicationValidator.validateTopupLoan(loan, actualDisbursementDate);
amountToDisburse = disburseAmount.minus(loanOutstanding);
disburseLoanToLoan(loan, command, loanOutstanding);
@@ -625,7 +608,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private void createAndSaveLoanScheduleArchive(final Loan loan, ScheduleGeneratorDTO scheduleGeneratorDTO) {
LoanRescheduleRequest loanRescheduleRequest = null;
LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(scheduleGeneratorDTO);
LoanScheduleModel loanScheduleModel = loanMapper.regenerateScheduleModel(scheduleGeneratorDTO, loan);
List<LoanRepaymentScheduleInstallment> installments = retrieveRepaymentScheduleFromModel(loanScheduleModel);
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(installments, loan, loanRescheduleRequest);
}
@@ -922,11 +905,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
String noteText;
createNote(loan, command, changes);
boolean isAccountTransfer = false;
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
@@ -2353,8 +2335,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("approvedLoanAmount", element);
loanApplicationCommandFromApiJsonHelper.validateLoanMultiDisbursementDate(element, baseDataValidator, expectedDisbursementDate,
principal);
loanApplicationValidator.validateLoanMultiDisbursementDate(element, baseDataValidator, expectedDisbursementDate, principal);
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
@@ -2791,8 +2772,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
createNote(loan, command, changes);
boolean isAccountTransfer = false;
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
existingReversedTransactionIds, isAccountTransfer);
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoLastDisbursalBusinessEvent(loan));
@@ -83,8 +83,10 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanChargeMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanCollateralManagementMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTransactionMapper;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionValidator;
@@ -162,7 +164,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@Configuration
public class LoanAccountConfiguration {
@@ -302,7 +303,8 @@ public class LoanAccountConfiguration {
LoanAccrualsProcessingService loanAccrualsProcessingService,
LoanDownPaymentTransactionValidator loanDownPaymentTransactionValidator, LoanChargeValidator loanChargeValidator,
LoanScheduleService loanScheduleService, ReprocessLoanTransactionsService reprocessLoanTransactionsService,
LoanAccountService loanAccountService, LoanAdjustmentService loanAdjustmentService) {
LoanAccountService loanAccountService, LoanAdjustmentService loanAdjustmentService,
LoanAccountingBridgeMapper loanAccountingBridgeMapper) {
return new LoanChargeWritePlatformServiceImpl(loanChargeApiJsonValidator, loanAssembler, chargeRepository,
businessEventNotifierService, loanTransactionRepository, accountTransfersWritePlatformService, loanRepositoryWrapper,
journalEntryWritePlatformService, loanAccountDomainService, loanChargeRepository, loanWritePlatformService, loanUtilService,
@@ -310,7 +312,8 @@ public class LoanAccountConfiguration {
configurationDomainService, loanRepaymentScheduleTransactionProcessorFactory, externalIdFactory,
accountTransferDetailRepository, loanChargeAssembler, paymentDetailWritePlatformService, noteRepository,
loanAccrualTransactionBusinessEventService, loanAccrualsProcessingService, loanDownPaymentTransactionValidator,
loanChargeValidator, loanScheduleService, reprocessLoanTransactionsService, loanAccountService, loanAdjustmentService);
loanChargeValidator, loanScheduleService, reprocessLoanTransactionsService, loanAccountService, loanAdjustmentService,
loanAccountingBridgeMapper);
}
@Bean
@@ -322,23 +325,23 @@ public class LoanAccountConfiguration {
FundReadPlatformService fundReadPlatformService, ChargeReadPlatformService chargeReadPlatformService,
CodeValueReadPlatformService codeValueReadPlatformService, CalendarReadPlatformService calendarReadPlatformService,
StaffReadPlatformService staffReadPlatformService, PaginationHelper paginationHelper,
NamedParameterJdbcTemplate namedParameterJdbcTemplate, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
FloatingRatesReadPlatformService floatingRatesReadPlatformService, LoanUtilService loanUtilService,
ConfigurationDomainService configurationDomainService, AccountDetailsReadPlatformService accountDetailsReadPlatformService,
ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator,
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanTransactionRepository loanTransactionRepository,
LoanChargePaidByReadService loanChargePaidByReadService, LoanTransactionRelationReadService loanTransactionRelationReadService,
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper,
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper, LoanMapper loanMapper,
LoanTransactionProcessingService loanTransactionProcessingService) {
return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository,
loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService,
fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService,
staffReadPlatformService, paginationHelper, namedParameterJdbcTemplate, paymentTypeReadPlatformService,
staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService,
loanRepaymentScheduleTransactionProcessorFactory, floatingRatesReadPlatformService, loanUtilService,
configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService,
loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService);
loanForeclosureValidator, loanTransactionMapper, loanMapper, loanTransactionProcessingService);
}
@Bean
@@ -387,9 +390,9 @@ public class LoanAccountConfiguration {
AccountTransferDetailRepository accountTransferDetailRepository, BusinessEventNotifierService businessEventNotifierService,
GuarantorDomainService guarantorDomainService, LoanUtilService loanUtilService,
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy, CodeValueRepositoryWrapper codeValueRepository,
CashierTransactionDataValidator cashierTransactionDataValidator, GLIMAccountInfoRepository glimRepository,
LoanRepository loanRepository, RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler,
CodeValueRepositoryWrapper codeValueRepository, CashierTransactionDataValidator cashierTransactionDataValidator,
GLIMAccountInfoRepository glimRepository, LoanRepository loanRepository,
RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler,
PostDatedChecksRepository postDatedChecksRepository,
LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository,
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine, LoanAccountLockService loanAccountLockService,
@@ -401,6 +404,7 @@ public class LoanAccountConfiguration {
LoanChargeValidator loanChargeValidator, LoanOfficerService loanOfficerService,
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanAccountService loanAccountService,
LoanJournalEntryPoster journalEntryPoster, LoanAdjustmentService loanAdjustmentService,
LoanAccountingBridgeMapper loanAccountingBridgeMapper, LoanMapper loanMapper,
LoanTransactionProcessingService loanTransactionProcessingService) {
return new LoanWritePlatformServiceJpaRepositoryImpl(context, loanTransactionValidator, loanUpdateCommandFromApiJsonDeserializer,
loanRepositoryWrapper, loanAccountDomainService, noteRepository, loanTransactionRepository,
@@ -409,14 +413,14 @@ public class LoanAccountConfiguration {
accountTransfersWritePlatformService, accountTransfersReadPlatformService, accountAssociationsReadPlatformService,
loanReadPlatformService, fromApiJsonHelper, calendarRepository, loanScheduleHistoryWritePlatformService,
loanApplicationValidator, accountAssociationRepository, accountTransferDetailRepository, businessEventNotifierService,
guarantorDomainService, loanUtilService, entityDatatableChecksWritePlatformService, transactionProcessingStrategy,
codeValueRepository, cashierTransactionDataValidator, glimRepository, loanRepository, repaymentWithPostDatedChecksAssembler,
guarantorDomainService, loanUtilService, entityDatatableChecksWritePlatformService, codeValueRepository,
cashierTransactionDataValidator, glimRepository, loanRepository, repaymentWithPostDatedChecksAssembler,
postDatedChecksRepository, loanRepaymentScheduleInstallmentRepository, defaultLoanLifecycleStateMachine,
loanAccountLockService, externalIdFactory, loanAccrualTransactionBusinessEventService, errorHandler,
loanDownPaymentHandlerService, loanTransactionAssembler, loanAccrualsProcessingService, loanOfficerValidator,
loanDownPaymentTransactionValidator, loanDisbursementService, loanScheduleService, loanChargeValidator, loanOfficerService,
reprocessLoanTransactionsService, loanAccountService, journalEntryPoster, loanAdjustmentService,
loanTransactionProcessingService);
reprocessLoanTransactionsService, loanAccountService, journalEntryPoster, loanAdjustmentService, loanAccountingBridgeMapper,
loanMapper, loanTransactionProcessingService);
}
@Bean
@@ -461,10 +465,11 @@ public class LoanAccountConfiguration {
@Bean
@ConditionalOnMissingBean(LoanScheduleService.class)
public LoanScheduleService loanScheduleService(LoanChargeService loanChargeService,
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule) {
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanTransactionProcessingService, loanSchedule);
public LoanScheduleService loanScheduleService(final LoanChargeService loanChargeService,
final ReprocessLoanTransactionsService reprocessLoanTransactionsService, final LoanMapper loanMapper,
final LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule) {
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanMapper, loanTransactionProcessingService,
loanSchedule);
}
@Bean