diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java index c7a6a8966..f33fb53b6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java @@ -59,7 +59,6 @@ import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGL import org.apache.fineract.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; -import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OfficeRepository; import org.apache.fineract.portfolio.account.PortfolioAccountType; @@ -105,7 +104,7 @@ public class AccountingProcessorHelper { final Long loanId = (Long) accountingBridgeData.get("loanId"); final Long loanProductId = (Long) accountingBridgeData.get("loanProductId"); final Long officeId = (Long) accountingBridgeData.get("officeId"); - final CurrencyData currencyData = (CurrencyData) accountingBridgeData.get("currency"); + final String currencyCode = (String) accountingBridgeData.get("currencyCode"); final List newLoanTransactions = new ArrayList<>(); boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer"); @@ -160,8 +159,8 @@ public class AccountingProcessorHelper { } - return new LoanDTO(loanId, loanProductId, officeId, currencyData.code(), cashBasedAccountingEnabled, - upfrontAccrualBasedAccountingEnabled, periodicAccrualBasedAccountingEnabled, newLoanTransactions); + return new LoanDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled, + periodicAccrualBasedAccountingEnabled, newLoanTransactions); } public SavingsDTO populateSavingsDtoFromMap(final Map accountingBridgeData, final boolean cashBasedAccountingEnabled, @@ -169,7 +168,7 @@ public class AccountingProcessorHelper { final Long loanId = (Long) accountingBridgeData.get("savingsId"); final Long loanProductId = (Long) accountingBridgeData.get("savingsProductId"); final Long officeId = (Long) accountingBridgeData.get("officeId"); - final CurrencyData currencyData = (CurrencyData) accountingBridgeData.get("currency"); + final String currencyCode = (String) accountingBridgeData.get("currencyCode"); final List newSavingsTransactions = new ArrayList<>(); boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer"); @@ -230,8 +229,8 @@ public class AccountingProcessorHelper { } - return new SavingsDTO(loanId, loanProductId, officeId, currencyData.code(), cashBasedAccountingEnabled, - accrualBasedAccountingEnabled, newSavingsTransactions); + return new SavingsDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, + newSavingsTransactions); } public SharesDTO populateSharesDtoFromMap(final Map accountingBridgeData, final boolean cashBasedAccountingEnabled, @@ -239,7 +238,7 @@ public class AccountingProcessorHelper { final Long shareAccountId = (Long) accountingBridgeData.get("shareAccountId"); final Long shareProductId = (Long) accountingBridgeData.get("shareProductId"); final Long officeId = (Long) accountingBridgeData.get("officeId"); - final CurrencyData currencyData = (CurrencyData) accountingBridgeData.get("currency"); + final String currencyCode = (String) accountingBridgeData.get("currencyCode"); final List newTransactions = new ArrayList<>(); @SuppressWarnings("unchecked") @@ -275,7 +274,7 @@ public class AccountingProcessorHelper { } - return new SharesDTO(shareAccountId, shareProductId, officeId, currencyData.code(), cashBasedAccountingEnabled, + return new SharesDTO(shareAccountId, shareProductId, officeId, currencyCode, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newTransactions); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java index 6fed9e74e..42ac49451 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java @@ -19,11 +19,7 @@ package org.apache.fineract.cob.loan; import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; @@ -34,24 +30,16 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class ApplyChargeToOverdueLoansBusinessStep implements LoanCOBBusinessStep { - private final ConfigurationDomainService configurationDomainService; private final LoanReadPlatformService loanReadPlatformService; private final LoanWritePlatformService loanWritePlatformService; @Override - public Loan execute(Loan input) { - final Long penaltyWaitPeriodValue = configurationDomainService.retrievePenaltyWaitPeriod(); - final Boolean backdatePenalties = configurationDomainService.isBackdatePenaltiesEnabled(); - final Collection overdueLoanScheduledInstallments = loanReadPlatformService - .retrieveAllLoansWithOverdueInstallments(penaltyWaitPeriodValue, backdatePenalties); - // TODO: this is very much not effective to get all overdue installments for each loan, a new method needs to be - // implemented for it - Map> groupedOverdueData = overdueLoanScheduledInstallments.stream() - .collect(Collectors.groupingBy(OverdueLoanScheduleData::getLoanId)); - for (Long loanId : groupedOverdueData.keySet()) { - loanWritePlatformService.applyOverdueChargesForLoan(input.getId(), groupedOverdueData.get(loanId)); - } - return input; + public Loan execute(Loan loan) { + final Collection overdueLoanScheduleDataList = loanReadPlatformService + .retrieveAllOverdueInstallmentsForLoan(loan); + + loanWritePlatformService.applyOverdueChargesForLoan(loan.getId(), overdueLoanScheduleDataList); + return loan; } @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 974894682..3a2c045bd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -71,7 +71,6 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator; import org.apache.fineract.organisation.holiday.domain.Holiday; import org.apache.fineract.organisation.holiday.service.HolidayUtil; -import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; @@ -2394,8 +2393,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return actualChanges; } - public Collection findExistingTransactionIds() { - final Collection ids = new ArrayList<>(); + public List findExistingTransactionIds() { + final List ids = new ArrayList<>(); List transactions = getLoanTransactions(); for (final LoanTransaction transaction : transactions) { ids.add(transaction.getId()); @@ -2404,9 +2403,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return ids; } - public Collection findExistingReversedTransactionIds() { + public List findExistingReversedTransactionIds() { - final Collection ids = new ArrayList<>(); + final List ids = new ArrayList<>(); List transactions = getLoanTransactions(); for (final LoanTransaction transaction : transactions) { if (transaction.isReversed()) { @@ -4411,14 +4410,14 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return this.proposedPrincipal; } - public Map deriveAccountingBridgeData(final CurrencyData currencyData, final List existingTransactionIds, + public Map deriveAccountingBridgeData(final String currencyCode, final List existingTransactionIds, final List existingReversedTransactionIds, boolean isAccountTransfer) { final Map accountingBridgeData = new LinkedHashMap<>(); accountingBridgeData.put("loanId", getId()); accountingBridgeData.put("loanProductId", productId()); accountingBridgeData.put("officeId", getOfficeId()); - accountingBridgeData.put("currency", currencyData); + accountingBridgeData.put("currencyCode", currencyCode); accountingBridgeData.put("calculatedInterest", this.summary.getTotalInterestCharged()); accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnLoanProduct()); accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", isUpfrontAccrualAccountingEnabledOnLoanProduct()); @@ -4429,9 +4428,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { for (final LoanTransaction transaction : this.loanTransactions) { if (transaction.isReversed() && existingTransactionIds.contains(transaction.getId()) && !existingReversedTransactionIds.contains(transaction.getId())) { - newLoanTransactions.add(transaction.toMapData(currencyData)); + newLoanTransactions.add(transaction.toMapData(currencyCode)); } else if (!existingTransactionIds.contains(transaction.getId())) { - newLoanTransactions.add(transaction.toMapData(currencyData)); + newLoanTransactions.add(transaction.toMapData(currencyCode)); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index cbc1ba16b..01ce781df 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -111,7 +111,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { private final HolidayRepository holidayRepository; private final WorkingDaysRepositoryWrapper workingDaysRepository; - private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper; private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final NoteRepository noteRepository; private final AccountTransferRepository accountTransferRepository; @@ -417,10 +416,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final List existingReversedTransactionIds, boolean isAccountTransfer, boolean isLoanToLoanTransfer) { final MonetaryCurrency currency = loanAccount.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - final Map accountingBridgeData = loanAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loanAccount.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); accountingBridgeData.put("isLoanToLoanTransfer", isLoanToLoanTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -535,14 +533,13 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { */ @Override public void recalculateAccruals(Loan loan) { - boolean isInterestCalcualtionHappened = loan.repaymentScheduleDetail().isInterestRecalculationEnabled(); - recalculateAccruals(loan, isInterestCalcualtionHappened); + recalculateAccruals(loan, loan.repaymentScheduleDetail().isInterestRecalculationEnabled()); } @Override - public void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened) { + public void recalculateAccruals(Loan loan, boolean isInterestCalculationHappened) { LocalDate accruedTill = loan.getAccruedTill(); - if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !isInterestCalcualtionHappened || accruedTill == null || loan.isNpa() + if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !isInterestCalculationHappened || accruedTill == null || loan.isNpa() || !loan.status().isActive()) { return; } @@ -552,7 +549,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { if (isOrganisationDateEnabled) { organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate(); } - Collection loanScheduleAccrualDatas = new ArrayList<>(); + Collection loanScheduleAccrualList = new ArrayList<>(); List installments = loan.getRepaymentScheduleInstallments(); Long loanId = loan.getId(); Long officeId = loan.getOfficeId(); @@ -571,15 +568,15 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { accruedTill = DateUtils.getBusinessLocalDate(); } if (!isOrganisationDateEnabled || organisationStartDate.isBefore(installment.getDueDate())) { - generateLoanScheduleAccrualData(accruedTill, loanScheduleAccrualDatas, loanId, officeId, accrualStartDate, + generateLoanScheduleAccrualData(accruedTill, loanScheduleAccrualList, loanId, officeId, accrualStartDate, repaymentFrequency, repayEvery, interestCalculatedFrom, loanProductId, currency, currencyData, loanCharges, installment); } } - if (!loanScheduleAccrualDatas.isEmpty()) { + if (!loanScheduleAccrualList.isEmpty()) { try { - this.loanAccrualPlatformService.addPeriodicAccruals(accruedTill, loanScheduleAccrualDatas); + this.loanAccrualPlatformService.addPeriodicAccruals(accruedTill, loanScheduleAccrualList); } catch (MultiException e) { String globalisationMessageCode = "error.msg.accrual.exception"; throw new GeneralPlatformDomainRuleException(globalisationMessageCode, e.getMessage(), e); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java index bbfe1f231..29206fd5d 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java @@ -23,9 +23,11 @@ import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import lombok.Getter; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; @Entity +@Getter @Table(name = "m_loan_overdue_installment_charge") public class LoanOverdueInstallmentCharge extends AbstractPersistableCustom { @@ -54,9 +56,4 @@ public class LoanOverdueInstallmentCharge extends AbstractPersistableCustom { public void updateLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) { this.installment = loanRepaymentScheduleInstallment; } - - public LoanRepaymentScheduleInstallment getInstallment() { - return this.installment; - } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index 60e83ac2a..a4d5d3e00 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -656,7 +656,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { transfer, null, outstandingLoanBalance, this.unrecognizedIncomePortion, this.manuallyAdjustedOrReversed); } - public Map toMapData(final CurrencyData currencyData) { + public Map toMapData(final String currencyCode) { final Map thisTransactionData = new LinkedHashMap<>(); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf); @@ -666,7 +666,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { thisTransactionData.put("type", transactionType); thisTransactionData.put("reversed", Boolean.valueOf(isReversed())); thisTransactionData.put("date", getTransactionDate()); - thisTransactionData.put("currency", currencyData); + thisTransactionData.put("currencyCode", currencyCode); thisTransactionData.put("amount", this.amount); thisTransactionData.put("netDisbursalAmount", this.loan.getNetDisbursalAmount()); thisTransactionData.put("principalPortion", this.principalPortion); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java index 70dbc7452..78361571d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java @@ -42,8 +42,6 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService; @@ -99,7 +97,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche private final PlatformSecurityContext platformSecurityContext; private final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator; private final LoanRescheduleRequestRepository loanRescheduleRequestRepository; - private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository; private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService; private final LoanTransactionRepository loanTransactionRepository; @@ -125,7 +122,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche final PlatformSecurityContext platformSecurityContext, final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator, final LoanRescheduleRequestRepository loanRescheduleRequestRepository, - final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository, final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService, final LoanTransactionRepository loanTransactionRepository, @@ -140,7 +136,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche this.platformSecurityContext = platformSecurityContext; this.loanRescheduleRequestDataValidator = loanRescheduleRequestDataValidator; this.loanRescheduleRequestRepository = loanRescheduleRequestRepository; - this.applicationCurrencyRepository = applicationCurrencyRepository; this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository; this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService; this.loanTransactionRepository = loanTransactionRepository; @@ -538,10 +533,9 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche private void postJournalEntries(Loan loan, List existingTransactionIds, List existingReversedTransactionIds) { final MonetaryCurrency currency = loan.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); boolean isAccountTransfer = false; - final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java index 2f21fffdc..e6bc7002f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java @@ -33,8 +33,6 @@ import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlat import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; @@ -49,7 +47,6 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations; import org.apache.fineract.useradministration.domain.AppUser; -import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -64,10 +61,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat private final JdbcTemplate jdbcTemplate; private final DatabaseSpecificSQLGenerator sqlGenerator; private final JournalEntryWritePlatformService journalEntryWritePlatformService; - private final AppUserRepositoryWrapper userRepository; private final PlatformSecurityContext context; private final LoanRepositoryWrapper loanRepositoryWrapper; - private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; @Override @Transactional @@ -289,7 +284,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat accountingBridgeData.put("loanId", loanScheduleAccrualData.getLoanId()); accountingBridgeData.put("loanProductId", loanScheduleAccrualData.getLoanProductId()); accountingBridgeData.put("officeId", loanScheduleAccrualData.getOfficeId()); - accountingBridgeData.put("currency", loanScheduleAccrualData.getCurrencyData()); + accountingBridgeData.put("currencyCode", loanScheduleAccrualData.getCurrencyData().getCode()); accountingBridgeData.put("cashBasedAccountingEnabled", false); accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", false); accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", true); @@ -489,10 +484,9 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat private void postJournalEntries(final Loan loan, final List existingTransactionIds, final List existingReversedTransactionIds) { final MonetaryCurrency currency = loan.getCurrency(); - final ApplicationCurrency applicationCurrency = applicationCurrencyRepository.findOneWithNotFoundDetection(currency); boolean isAccountTransfer = false; - final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java index b36cc54ec..e90943e63 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java @@ -20,9 +20,11 @@ package org.apache.fineract.portfolio.loanaccount.service; import java.util.Collection; import org.apache.fineract.portfolio.charge.data.ChargeData; +import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; public interface LoanChargeReadPlatformService { @@ -37,7 +39,7 @@ public interface LoanChargeReadPlatformService { Collection retrieveInstallmentLoanCharges(Long loanChargeId, boolean onlyPaymentPendingCharges); - Collection retrieveOverdueInstallmentChargeFrequencyNumber(Long loanId, Long chargeId, Integer periodNumber); + Collection retrieveOverdueInstallmentChargeFrequencyNumber(Loan loan, Charge charge, Integer periodNumber); Collection retrieveLoanChargesForAccural(Long loanId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java index 62b95d458..3c5a7f12c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java @@ -31,15 +31,17 @@ import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.glaccount.data.GLAccountData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.portfolio.charge.data.ChargeData; +import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService; import org.apache.fineract.portfolio.charge.service.ChargeEnumerations; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.tax.data.TaxGroupData; import org.springframework.jdbc.core.JdbcTemplate; @@ -51,7 +53,6 @@ import org.springframework.stereotype.Service; public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatformService { private final JdbcTemplate jdbcTemplate; - private final PlatformSecurityContext context; private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService; private final DropdownReadPlatformService dropdownReadPlatformService; @@ -243,16 +244,18 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform } @Override - public Collection retrieveOverdueInstallmentChargeFrequencyNumber(final Long loanId, final Long chargeId, + public Collection retrieveOverdueInstallmentChargeFrequencyNumber(final Loan loan, final Charge charge, final Integer periodNumber) { - String sql = "select oic.frequency_number from m_loan_overdue_installment_charge oic inner join m_loan_charge lc on lc.id=oic.loan_charge_id inner join m_loan_repayment_schedule rs on rs.id = oic.loan_schedule_id inner join m_loan loan on loan.id=rs.loan_id " - + "where lc.is_active = true and loan.id = ? and rs.installment=?"; - Object[] params = { loanId, periodNumber }; - if (chargeId != null) { - sql += " and lc.charge_id = ? "; - params = new Object[] { loanId, periodNumber, chargeId }; + + List frequencyNumbers = new ArrayList<>(); + for (LoanCharge loanCharge : loan.getLoanCharges()) { + if (loanCharge.isOverdueInstallmentCharge() && charge.equals(loanCharge.getCharge()) && loanCharge.isActive() + && periodNumber.equals(loanCharge.getOverdueInstallmentCharge().getInstallment().getInstallmentNumber())) { + frequencyNumbers.add(loanCharge.getOverdueInstallmentCharge().getFrequencyNumber()); + } } - return this.jdbcTemplate.queryForList(sql, Integer.class, params); + + return frequencyNumbers; } @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java index f8402066f..f52f20163 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java @@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData; import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; @@ -93,6 +94,8 @@ public interface LoanReadPlatformService { */ Collection retrieveAllLoansWithOverdueInstallments(Long penaltyWaitPeriod, Boolean backdatePenalties); + Collection retrieveAllOverdueInstallmentsForLoan(Loan loan); + Integer retriveLoanCounter(Long groupId, Integer loanType, Long productId); Integer retriveLoanCounter(Long clientId, Long productId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index b87cb4fb6..01f429879 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -31,7 +31,9 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.infrastructure.codes.data.CodeValueData; @@ -63,6 +65,7 @@ import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; +import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; import org.apache.fineract.portfolio.client.data.ClientData; @@ -151,7 +154,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { private final CalendarReadPlatformService calendarReadPlatformService; private final StaffReadPlatformService staffReadPlatformService; private final PaginationHelper paginationHelper; - private final LoanMapper loaanLoanMapper; + private final LoanMapper loanMapper; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final PaymentTypeReadPlatformService paymentTypeReadPlatformService; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; @@ -199,7 +202,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { this.configurationDomainService = configurationDomainService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.columnValidator = columnValidator; - this.loaanLoanMapper = new LoanMapper(sqlGenerator, delinquencyReadPlatformService); + this.loanMapper = new LoanMapper(sqlGenerator, delinquencyReadPlatformService); this.sqlGenerator = sqlGenerator; this.paginationHelper = paginationHelper; this.delinquencyReadPlatformService = delinquencyReadPlatformService; @@ -303,7 +306,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final StringBuilder sqlBuilder = new StringBuilder(200); sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " "); - sqlBuilder.append(this.loaanLoanMapper.loanSchema()); + sqlBuilder.append(this.loanMapper.loanSchema()); // TODO - for time being this will data scope list of loans returned to // only loans that have a client associated. @@ -367,7 +370,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { } final Object[] objectArray = extraCriterias.toArray(); final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos); - return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.loaanLoanMapper); + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.loanMapper); } @Override @@ -1040,7 +1043,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal amount = rs.getBigDecimal("amount"); final String dateFormat = "yyyy-MM-dd"; final String dueDate = rs.getString("dueDate"); - final String locale = "en_GB"; + final String locale = Locale.ENGLISH.toLanguageTag(); final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue"); final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid"); @@ -1558,6 +1561,46 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { return this.jdbcTemplate.query(sqlBuilder.toString(), rm, penaltyWaitPeriod, penaltyWaitPeriod); } + @Override + public Collection retrieveAllOverdueInstallmentsForLoan(final Loan loan) { + Collection list = new ArrayList<>(); + + if (!loan.isOpen()) { + return list; + } + final Long penaltyWaitPeriod = configurationDomainService.retrievePenaltyWaitPeriod(); + final boolean backdatePenalties = configurationDomainService.isBackdatePenaltiesEnabled(); + + for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) { + if (installment.isObligationsMet() || installment.isRecalculatedInterestComponent()) { + continue; + } + + boolean isPenaltyDue = installment.isOverdueOn(DateUtils.getBusinessLocalDate().plusDays(penaltyWaitPeriod + 1)); + boolean isDueToday = installment.getDueDate().equals(DateUtils.getBusinessLocalDate().plusDays(penaltyWaitPeriod)); + + if (isPenaltyDue) { + if (!backdatePenalties && !isDueToday) { + continue; + } + Optional penaltyCharge = loan.getLoanProduct().getLoanProductCharges().stream() + .filter((e) -> ChargeTimeType.OVERDUE_INSTALLMENT.getValue().equals(e.getChargeTimeType()) && e.isLoanCharge()) + .findFirst(); + + if (penaltyCharge.isEmpty()) { + continue; + } + + list.add(new OverdueLoanScheduleData(loan.getId(), penaltyCharge.get().getId(), + DateUtils.DEFAULT_DATE_FORMATTER.format(installment.getDueDate()), penaltyCharge.get().getAmount(), + DateUtils.DEFAULT_DATE_FORMAT, Locale.ENGLISH.toLanguageTag(), + installment.getPrincipalOutstanding(loan.getCurrency()).getAmount(), + installment.getInterestOutstanding(loan.getCurrency()).getAmount(), installment.getInstallmentNumber())); + } + } + return list; + } + @SuppressWarnings("deprecation") @Override public Integer retriveLoanCounter(final Long groupId, final Integer loanType, Long productId) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index aba9c411d..5d50eb2f4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -33,6 +33,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -57,8 +58,6 @@ import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChe import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.holiday.domain.Holiday; import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.office.domain.Office; @@ -120,6 +119,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException; import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; +import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeAppliedToException; import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException; @@ -235,7 +235,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final LoanAssembler loanAssembler; private final ChargeRepositoryWrapper chargeRepository; private final LoanChargeRepository loanChargeRepository; - private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final CalendarInstanceRepository calendarInstanceRepository; private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; @@ -828,7 +827,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingReversedTransactionIds = new ArrayList<>(); // final MonetaryCurrency currency = loan.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); final LocalDate recalculateFrom = null; loan.setActualDisbursementDate(null); @@ -852,7 +850,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan); this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN); - String noteText = null; + String noteText; if (command.hasParameter("note")) { noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -861,8 +859,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } boolean isAccountTransfer = false; - final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan)); } @@ -887,9 +885,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf glimRepository.findById(parentLoanId).orElseThrow(); JsonArray repayments = command.arrayOfParameterNamed("formDataArray"); - JsonCommand childCommand = null; + JsonCommand childCommand; CommandProcessingResult result = null; - JsonObject jsonObject = null; + JsonObject jsonObject; Long[] childLoanId = new Long[repayments.size()]; for (int i = 0; i < repayments.size(); i++) { @@ -982,7 +980,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf List transactionIds = new ArrayList<>(); boolean isAccountTransfer = false; HolidayDetailDTO holidayDetailDTO = null; - Boolean isHolidayValidationDone = false; + boolean isHolidayValidationDone = false; final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); for (final SingleRepaymentCommand singleLoanRepaymentCommand : repaymentCommand) { if (singleLoanRepaymentCommand != null) { @@ -991,7 +989,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf singleLoanRepaymentCommand.getTransactionDate()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); - boolean isHolidayEnabled = false; + boolean isHolidayEnabled; isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay); @@ -1033,7 +1031,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf Loan loan = this.loanAssembler.assembleFrom(loanId); if (loan.status().isClosed() && loan.getLoanSubStatus() != null && loan.getLoanSubStatus().equals(LoanSubStatus.FORECLOSED.getValue())) { - final String defaultUserMessage = "The loan cannot reopend as it is foreclosed."; + final String defaultUserMessage = "The loan cannot reopened as it is foreclosed."; throw new LoanForeclosureException("loan.cannot.be.reopened.as.it.is.foreclosured", defaultUserMessage, loanId); } checkClientOrGroupActive(loan); @@ -1121,7 +1119,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { changes.put("note", noteText); - Note note = null; + Note note; /** * If a new transaction is not created, associate note with the transaction to be adjusted **/ @@ -1165,8 +1163,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override public CommandProcessingResult waiveInterestOnLoan(final Long loanId, final JsonCommand command) { - AppUser currentUser = getAppUserIfPresent(); - this.loanEventApiJsonValidator.validateTransaction(command.json()); final Map changes = new LinkedHashMap<>(); @@ -1304,8 +1300,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override public CommandProcessingResult closeLoan(final Long loanId, final JsonCommand command) { - AppUser currentUser = getAppUserIfPresent(); - this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json()); final Loan loan = this.loanAssembler.assembleFrom(loanId); @@ -1373,7 +1367,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf // disable all active standing instructions linked to the loan this.loanAccountDomainService.disableStandingInstructionsLinkedToClosedLoan(loan); - CommandProcessingResult result = null; + CommandProcessingResult result; if (possibleClosingTransaction != null) { result = new CommandProcessingResultBuilder().withCommandId(command.commandId()) @@ -1485,7 +1479,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf LoanCharge loanCharge = null; LocalDate recalculateFrom = loan.fetchInterestRecalculateFromDate(); if (chargeDefinition.isPercentageOfDisbursementAmount()) { - LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null; + LoanTrancheDisbursementCharge loanTrancheDisbursementCharge; for (LoanDisbursementDetails disbursementDetail : loanDisburseDetails) { if (disbursementDetail.actualDisbursementDate() == null) { loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, disbursementDetail.principal(), null, null, null, @@ -1501,6 +1495,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } } + if (loanCharge == null) { + final String errorMessage = "Charge with identifier " + chargeDefinition.getId() + + " cannot be applied: No valid loan disbursement available"; + throw new ChargeCannotBeAppliedToException("loan", errorMessage, chargeDefinition.getId()); + } loan.addTrancheLoanCharge(chargeDefinition); } else { loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command); @@ -1607,7 +1606,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private boolean addCharge(final Loan loan, final Charge chargeDefinition, final LoanCharge loanCharge) { - AppUser currentUser = getAppUserIfPresent(); if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) { final String errorMessage = "Charge and Loan must have the same currency."; throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage); @@ -1634,11 +1632,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null); this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction); } - boolean isAppliedOnBackDate = false; - if (loanCharge.getDueLocalDate() == null || DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate())) { - isAppliedOnBackDate = true; - } - return isAppliedOnBackDate; + return loanCharge.getDueLocalDate() == null || DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate()); } @Transactional @@ -1694,7 +1688,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } final BigDecimal fullRefundAbleAmount = loanChargeValidateRefundAmount(loanCharge, installmentChargeEntry, transactionAmount); - JsonCommand repaymentJsonCommand = adaptLoanChargeRefundCommandForFutherRepaymentProcessing(command, fullRefundAbleAmount); + JsonCommand repaymentJsonCommand = adaptLoanChargeRefundCommandForFurtherRepaymentProcessing(command, fullRefundAbleAmount); boolean isRecoveryRepayment = false; String chargeRefundChargeType = "F"; @@ -1709,7 +1703,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf Long loanChargeRefundTransactionId = result.resourceId(); LoanTransaction newChargeRefundTxn = null; for (LoanTransaction chargeRefundTxn : loanCharge.getLoan().getLoanTransactions()) { - if (chargeRefundTxn.getId().equals(loanChargeRefundTransactionId)) { + if (loanChargeRefundTransactionId.equals(chargeRefundTxn.getId())) { newChargeRefundTxn = chargeRefundTxn; final BigDecimal appliedRefundAmount = newChargeRefundTxn.getAmount(loanCharge.getLoan().getCurrency()).getAmount() .multiply(BigDecimal.valueOf(-1)); @@ -1726,7 +1720,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } - private JsonCommand adaptLoanChargeRefundCommandForFutherRepaymentProcessing(JsonCommand command, BigDecimal fullRefundAbleAmount) { + private JsonCommand adaptLoanChargeRefundCommandForFurtherRepaymentProcessing(JsonCommand command, BigDecimal fullRefundAbleAmount) { // creates JsonCommand for onward repayment processing JsonObject jsonObject = (JsonObject) this.fromApiJsonHelper.parse(command.json()); @@ -1748,14 +1742,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf jsonObject.remove("installmentNumber"); jsonObject.remove("dueDate"); - JsonCommand repaymentJsonCommand = JsonCommand.fromExistingCommand(command, jsonObject); - return repaymentJsonCommand; + return JsonCommand.fromExistingCommand(command, jsonObject); } private BigDecimal loanChargeValidateRefundAmount(LoanCharge loanCharge, LoanInstallmentCharge installmentChargeEntry, BigDecimal transactionAmount) { // if transactionAmount not provided return max refundable amount (amount paid minus previous refunds) - BigDecimal chargeAmountPaid = BigDecimal.ZERO; + BigDecimal chargeAmountPaid; BigDecimal chargeAmountRefunded = BigDecimal.ZERO; MonetaryCurrency loanCurrency = loanCharge.getLoan().getCurrency(); if (loanCharge.isInstalmentFee()) { @@ -1780,7 +1773,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (chargeAmountRefunded.compareTo(chargeAmountPaid) > 0) { final String errorMessage = "loan.charge.more.refunded.than.paid.unexpected.system.error"; - final String details = "Paid: " + chargeAmountPaid.toString() + " Refunded: " + chargeAmountPaid.toString(); + final String details = "Paid: " + chargeAmountPaid.toString() + " Refunded: " + chargeAmountPaid; throw new LoanChargeRefundException(errorMessage, details); } @@ -1788,8 +1781,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (transactionAmount != null) { // refund amount was provided. if (transactionAmount.compareTo(refundableAmount) > 0) { final String errorMessage = "loan.charge.transaction.amount.is.more.than.is.refundable"; - final String details = "transactionAmount: " + transactionAmount.toString() + " Refundable: " - + refundableAmount.toString(); + final String details = "transactionAmount: " + transactionAmount + " Refundable: " + refundableAmount; throw new LoanChargeRefundException(errorMessage, details); } } @@ -1900,7 +1892,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf businessEventNotifierService.notifyPreBusinessEvent(new LoanWaiveChargeUndoBusinessEvent(loanCharge)); if (loanCharge.isInstalmentFee()) { - LoanInstallmentCharge chargePerInstallment = null; + LoanInstallmentCharge chargePerInstallment; // final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber"); if (installmentNumber != null) { @@ -2004,8 +1996,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override public CommandProcessingResult waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) { - AppUser currentUser = getAppUserIfPresent(); - final Loan loan = this.loanAssembler.assembleFrom(loanId); checkClientOrGroupActive(loan); this.loanEventApiJsonValidator.validateInstallmentChargeTransaction(command.json()); @@ -2056,9 +2046,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf Money accruedCharge = Money.zero(loan.getCurrency()); if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) { - Collection chargePaidByDatas = this.loanChargeReadPlatformService + Collection chargePaidByCollection = this.loanChargeReadPlatformService .retriveLoanChargesPaidBy(loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber); - for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) { + for (LoanChargePaidByData chargePaidByData : chargePaidByCollection) { accruedCharge = accruedCharge.plus(chargePaidByData.getAmount()); } } @@ -2409,7 +2399,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf loanUpdateCommand.validate(); - final LocalDate dateOfLoanOfficerunAssigned = command.localDateValueOfParameterNamed("unassignedDate"); + final LocalDate dateOfLoanOfficerUnassigned = command.localDateValueOfParameterNamed("unassignedDate"); final Loan loan = this.loanAssembler.assembleFrom(loanId); checkClientOrGroupActive(loan); @@ -2419,7 +2409,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } businessEventNotifierService.notifyPreBusinessEvent(new LoanRemoveOfficerBusinessEvent(loan)); - loan.removeLoanOfficer(dateOfLoanOfficerunAssigned); + loan.removeLoanOfficer(dateOfLoanOfficerUnassigned); saveLoanWithDataIntegrityViolationChecks(loan); businessEventNotifierService.notifyPostBusinessEvent(new LoanRemoveOfficerBusinessEvent(loan)); @@ -2438,10 +2428,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingReversedTransactionIds) { final MonetaryCurrency currency = loan.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); boolean isAccountTransfer = false; - final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -2449,22 +2438,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override public void applyMeetingDateChanges(final Calendar calendar, final Collection loanCalendarInstances) { - final Boolean reschedulebasedOnMeetingDates = null; + final Boolean rescheduleBasedOnMeetingDates = null; final LocalDate presentMeetingDate = null; final LocalDate newMeetingDate = null; - applyMeetingDateChanges(calendar, loanCalendarInstances, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate); + applyMeetingDateChanges(calendar, loanCalendarInstances, rescheduleBasedOnMeetingDates, presentMeetingDate, newMeetingDate); } @Transactional @Override public void applyMeetingDateChanges(final Calendar calendar, final Collection loanCalendarInstances, - final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate, final LocalDate newMeetingDate) { + final Boolean rescheduleBasedOnMeetingDates, final LocalDate presentMeetingDate, final LocalDate newMeetingDate) { final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); final WorkingDays workingDays = this.workingDaysRepository.findOne(); - final AppUser currentUser = getAppUserIfPresent(); final List existingTransactionIds = new ArrayList<>(); final List existingReversedTransactionIds = new ArrayList<>(); final Collection loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), @@ -2477,7 +2465,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } final List loans = this.loanRepositoryWrapper.findByIdsAndLoanStatusAndLoanType(loanIds, loanStatuses, loanTypes); - List holidays = null; + List holidays; final LocalDate recalculateFrom = null; // loop through each loan to reschedule the repayment dates for (final Loan loan : loans) { @@ -2489,7 +2477,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } Boolean isSkipRepaymentOnFirstMonth = false; - Integer numberOfDays = 0; + int numberOfDays = 0; boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled(); if (isSkipRepaymentOnFirstMonthEnabled) { isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar); @@ -2505,9 +2493,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, existingTransactionIds, existingReversedTransactionIds); createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); - } else if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) { + } else if (rescheduleBasedOnMeetingDates != null && rescheduleBasedOnMeetingDates) { loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled, - holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate, + holidays, workingDays, rescheduleBasedOnMeetingDates, presentMeetingDate, newMeetingDate, isSkipRepaymentOnFirstMonth, numberOfDays); } else { loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled, @@ -2603,7 +2591,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf loanToUpdate.updateClientLoanCounter(++currentLoanCounter); } - if (loanToUpdate.loanProduct().getId().equals(loan.loanProduct().getId())) { + if (Objects.equals(loan.loanProduct().getId(), loanToUpdate.loanProduct().getId())) { Integer loanProductLoanCounter = loanToUpdate.getLoanProductLoanCounter(); if (newLoanProductCounter > loanProductLoanCounter) { newLoanProductCounter = loanProductLoanCounter; @@ -2646,17 +2634,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private void updateLoanCycleCounter(final List loansToUpdate, final Loan loan) { - final Integer currentLoancounter = loan.getCurrentLoanCounter(); + final Integer currentLoanCounter = loan.getCurrentLoanCounter(); final Integer currentLoanProductCounter = loan.getLoanProductLoanCounter(); for (final Loan loanToUpdate : loansToUpdate) { if (loan.loanProduct().isIncludeInBorrowerCycle()) { - Integer runningLoancounter = loanToUpdate.getCurrentLoanCounter(); - if (runningLoancounter > currentLoancounter) { - loanToUpdate.updateClientLoanCounter(--runningLoancounter); + Integer runningLoanCounter = loanToUpdate.getCurrentLoanCounter(); + if (runningLoanCounter > currentLoanCounter) { + loanToUpdate.updateClientLoanCounter(--runningLoanCounter); } } - if (loan.loanProduct().getId().equals(loanToUpdate.loanProduct().getId())) { + if (Objects.equals(loan.loanProduct().getId(), loanToUpdate.loanProduct().getId())) { Integer runningLoanProductCounter = loanToUpdate.getLoanProductLoanCounter(); if (runningLoanProductCounter > currentLoanProductCounter) { loanToUpdate.updateLoanProductLoanCounter(--runningLoanProductCounter); @@ -2683,21 +2671,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override @Transactional - public void applyOverdueChargesForLoan(final Long loanId, Collection overdueLoanScheduleDatas) { + public void applyOverdueChargesForLoan(final Long loanId, Collection overdueLoanScheduleDataList) { - Loan loan = null; - final List existingTransactionIds = new ArrayList<>(); - final List existingReversedTransactionIds = new ArrayList<>(); + Loan loan = this.loanAssembler.assembleFrom(loanId); + final List existingTransactionIds = loan.findExistingTransactionIds(); + final List existingReversedTransactionIds = loan.findExistingReversedTransactionIds(); boolean runInterestRecalculation = false; LocalDate recalculateFrom = DateUtils.getBusinessLocalDate(); LocalDate lastChargeDate = null; - for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduleDatas) { + for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduleDataList) { final JsonElement parsedCommand = this.fromApiJsonHelper.parse(overdueInstallment.toString()); final JsonCommand command = JsonCommand.from(overdueInstallment.toString(), parsedCommand, this.fromApiJsonHelper, null, null, null, null, null, loanId, null, null, null, null, null, null); - LoanOverdueDTO overdueDTO = applyChargeToOverdueLoanInstallment(loanId, overdueInstallment.getChargeId(), - overdueInstallment.getPeriodNumber(), command, loan, existingTransactionIds, existingReversedTransactionIds); + LoanOverdueDTO overdueDTO = applyChargeToOverdueLoanInstallment(loan, overdueInstallment.getChargeId(), + overdueInstallment.getPeriodNumber(), command); loan = overdueDTO.getLoan(); runInterestRecalculation = runInterestRecalculation || overdueDTO.isRunInterestRecalculation(); if (recalculateFrom.isAfter(overdueDTO.getRecalculateFrom())) { @@ -2735,7 +2723,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } - saveLoanWithDataIntegrityViolationChecks(loan); } postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); @@ -2745,7 +2732,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanAccountDomainService.recalculateAccruals(loan); } businessEventNotifierService.notifyPostBusinessEvent(new LoanApplyOverdueChargeBusinessEvent(loan)); - } } @@ -2772,14 +2758,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } - public LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Long loanId, final Long loanChargeId, final Integer periodNumber, - final JsonCommand command, Loan loan, final List existingTransactionIds, - final List existingReversedTransactionIds) { + public LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Loan loan, final Long loanChargeId, final Integer periodNumber, + final JsonCommand command) { boolean runInterestRecalculation = false; final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(loanChargeId); - Collection frequencyNumbers = loanChargeReadPlatformService.retrieveOverdueInstallmentChargeFrequencyNumber(loanId, - chargeDefinition.getId(), periodNumber); + Collection frequencyNumbers = loanChargeReadPlatformService.retrieveOverdueInstallmentChargeFrequencyNumber(loan, + chargeDefinition, periodNumber); Integer feeFrequency = chargeDefinition.feeFrequency(); final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator(); @@ -2787,21 +2772,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Long penaltyWaitPeriodValue = this.configurationDomainService.retrievePenaltyWaitPeriod(); final Long penaltyPostingWaitPeriodValue = this.configurationDomainService.retrieveGraceOnPenaltyPostingPeriod(); final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate"); - Long diff = penaltyWaitPeriodValue + 1 - penaltyPostingWaitPeriodValue; + long diff = penaltyWaitPeriodValue + 1 - penaltyPostingWaitPeriodValue; if (diff < 1) { diff = 1L; } LocalDate startDate = dueDate.plusDays(penaltyWaitPeriodValue.intValue() + 1); - Integer frequencyNunber = 1; + int frequencyNumber = 1; if (feeFrequency == null) { - scheduleDates.put(frequencyNunber++, startDate.minusDays(diff)); + scheduleDates.put(frequencyNumber++, startDate.minusDays(diff)); } else { while (!startDate.isAfter(DateUtils.getBusinessLocalDate())) { - scheduleDates.put(frequencyNunber++, startDate.minusDays(diff)); - LocalDate scheduleDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency), - chargeDefinition.feeInterval(), startDate); + scheduleDates.put(frequencyNumber++, startDate.minusDays(diff)); - startDate = scheduleDate; + startDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency), + chargeDefinition.feeInterval(), startDate); } } @@ -2812,12 +2796,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf LoanRepaymentScheduleInstallment installment = null; LocalDate lastChargeAppliedDate = dueDate; if (!scheduleDates.isEmpty()) { - if (loan == null) { - loan = this.loanAssembler.assembleFrom(loanId); - checkClientOrGroupActive(loan); - existingTransactionIds.addAll(loan.findExistingTransactionIds()); - existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds()); - } installment = loan.fetchRepaymentScheduleInstallment(periodNumber); lastChargeAppliedDate = installment.getDueDate(); } @@ -2852,7 +2830,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf @Override public CommandProcessingResult undoWriteOff(Long loanId) { - final AppUser currentUser = getAppUserIfPresent(); final Loan loan = this.loanAssembler.assembleFrom(loanId); checkClientOrGroupActive(loan); @@ -2972,7 +2949,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } if (loan.getDisbursementDetails().size() > loan.loanProduct().maxTrancheCount()) { - final String errorMessage = "Number of tranche shouldn't be greter than " + loan.loanProduct().maxTrancheCount(); + final String errorMessage = "Number of tranche shouldn't be greater than " + loan.loanProduct().maxTrancheCount(); throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage, loan.loanProduct().maxTrancheCount(), loan.getDisbursementDetails().size()); } @@ -2983,16 +2960,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private CommandProcessingResult processLoanDisbursementDetail(Loan loan, Long loanId, JsonCommand command, LoanDisbursementDetails loanDisbursementDetails) { - final List existingTransactionIds = new ArrayList<>(); - final List existingReversedTransactionIds = new ArrayList<>(); - existingTransactionIds.addAll(loan.findExistingTransactionIds()); - existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds()); + final List existingTransactionIds = loan.findExistingTransactionIds(); + final List existingReversedTransactionIds = loan.findExistingReversedTransactionIds(); final Map changes = new LinkedHashMap<>(); LocalDate recalculateFrom = null; ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); ChangedTransactionDetail changedTransactionDetail = null; - AppUser currentUser = getAppUserIfPresent(); if (command.entityId() != null) { @@ -3302,7 +3276,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf businessEventNotifierService.notifyPreBusinessEvent(new LoanUndoLastDisbursalBusinessEvent(loan)); final MonetaryCurrency currency = loan.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); final List existingTransactionIds = new ArrayList<>(); final List existingReversedTransactionIds = new ArrayList<>(); @@ -3312,7 +3285,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf existingReversedTransactionIds, loan); if (!changes.isEmpty()) { loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan); - String noteText = null; + String noteText; if (command.hasParameter("note")) { noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -3321,8 +3294,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } boolean isAccountTransfer = false; - final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, + existingReversedTransactionIds, isAccountTransfer); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoLastDisbursalBusinessEvent(loan)); } @@ -3354,7 +3327,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf for (LoanDisbursementDetails loanDisbursementDetails : loan.getDisbursementDetails()) { if (!loanDisbursementDetails.expectedDisbursementDateAsLocalDate().isAfter(transactionDate) && loanDisbursementDetails.actualDisbursementDate() == null) { - final String defaultUserMessage = "The loan with undisbrsed tranche before foreclosure cannot be foreclosed."; + final String defaultUserMessage = "The loan with undisbursed tranche before foreclosure cannot be foreclosed."; throw new LoanForeclosureException("loan.with.undisbursed.tranche.before.foreclosure.cannot.be.foreclosured", defaultUserMessage, transactionDate); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java index 1f1d09bc5..563c4fe5c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java @@ -40,9 +40,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.portfolio.account.PortfolioAccountType; import org.apache.fineract.portfolio.account.data.AccountTransferDTO; import org.apache.fineract.portfolio.account.domain.AccountTransferType; @@ -574,11 +572,9 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final Set existingReversedTransactionIds, boolean isAccountTransfer) { - final MonetaryCurrency currency = savingsAccount.getCurrency(); final boolean backdatedTxnsAllowedTill = false; - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), + final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java index f5ab802ab..459fac396 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java @@ -82,7 +82,6 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator; import org.apache.fineract.interoperation.domain.InteropIdentifier; -import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; @@ -1878,13 +1877,13 @@ public class SavingsAccount extends AbstractPersistableCustom { } } - public Map deriveAccountingBridgeData(final CurrencyData currencyData, final Set existingTransactionIds, + public Map deriveAccountingBridgeData(final String currencyCode, final Set existingTransactionIds, final Set existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill) { final Map accountingBridgeData = new LinkedHashMap<>(); accountingBridgeData.put("savingsId", getId()); accountingBridgeData.put("savingsProductId", productId()); - accountingBridgeData.put("currency", currencyData); + accountingBridgeData.put("currencyCode", currencyCode); accountingBridgeData.put("officeId", officeId()); accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnSavingsProduct()); accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnSavingsProduct()); @@ -1903,9 +1902,9 @@ public class SavingsAccount extends AbstractPersistableCustom { // Adding new transactions to the array for (final SavingsAccountTransaction transaction : trans) { if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) { - newSavingsTransactions.add(transaction.toMapData(currencyData)); + newSavingsTransactions.add(transaction.toMapData(currencyCode)); } else if (!existingTransactionIds.contains(transaction.getId())) { - newSavingsTransactions.add(transaction.toMapData(currencyData)); + newSavingsTransactions.add(transaction.toMapData(currencyCode)); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index 45436ce42..713dd416b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -32,9 +32,7 @@ import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlat import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.portfolio.businessevent.domain.savings.transaction.SavingsDepositBusinessEvent; @@ -273,10 +271,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final Set existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill) { - final MonetaryCurrency currency = savingsAccount.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - - final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), + final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index 8459da909..21a5a1ee0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -39,7 +39,6 @@ import javax.persistence.Table; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.infrastructure.core.domain.LocalDateInterval; import org.apache.fineract.infrastructure.core.service.DateUtils; -import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.office.domain.Office; @@ -544,7 +543,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { return transactionAmount.isNotEqualTo(amountToCheck); } - public Map toMapData(final CurrencyData currencyData) { + public Map toMapData(final String currencyCode) { final Map thisTransactionData = new LinkedHashMap<>(); final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(this.typeOf); @@ -552,9 +551,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { thisTransactionData.put("id", getId()); thisTransactionData.put("officeId", this.office.getId()); thisTransactionData.put("type", transactionType); - thisTransactionData.put("reversed", Boolean.valueOf(isReversed())); + thisTransactionData.put("reversed", isReversed()); thisTransactionData.put("date", getTransactionLocalDate()); - thisTransactionData.put("currency", currencyData); + thisTransactionData.put("currencyCode", currencyCode); thisTransactionData.put("amount", this.amount); thisTransactionData.put("overdraftAmount", this.overdraftAmount); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index 5d5904e10..c979f8d9a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -52,9 +52,7 @@ import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavaila import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.organisation.office.domain.Office; @@ -1369,10 +1367,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final Set existingReversedTransactionIds) { - final MonetaryCurrency currency = savingsAccount.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); boolean isAccountTransfer = false; - final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), + final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, false); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 89e94e749..7d40ce214 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -64,9 +64,7 @@ import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.organisation.office.domain.Office; @@ -1544,10 +1542,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final Set existingReversedTransactionIds, final boolean backdatedTxnsAllowedTill) { - final MonetaryCurrency currency = savingsAccount.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); boolean isAccountTransfer = false; - final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), + final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java index ae5932b25..233eaa915 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java @@ -38,8 +38,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.service.DateUtils; -import org.apache.fineract.organisation.monetary.data.CurrencyData; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants; import org.apache.fineract.portfolio.businessevent.domain.share.ShareAccountApproveBusinessEvent; import org.apache.fineract.portfolio.businessevent.domain.share.ShareAccountCreateBusinessEvent; @@ -130,16 +128,13 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA private Map populateJournalEntries(final ShareAccount account, final Set transactions) { final Map accountingBridgeData = new HashMap<>(); - Boolean cashBasedAccounting = account.getShareProduct().getAccountingType().intValue() == 2 ? Boolean.TRUE : Boolean.FALSE; + Boolean cashBasedAccounting = account.getShareProduct().getAccountingType() == 2 ? Boolean.TRUE : Boolean.FALSE; accountingBridgeData.put("cashBasedAccountingEnabled", cashBasedAccounting); accountingBridgeData.put("accrualBasedAccountingEnabled", Boolean.FALSE); accountingBridgeData.put("shareAccountId", account.getId()); accountingBridgeData.put("shareProductId", account.getShareProduct().getId()); accountingBridgeData.put("officeId", account.getOfficeId()); - MonetaryCurrency currency = account.getCurrency(); - final CurrencyData currencyData = new CurrencyData(currency.getCode(), "", currency.getDigitsAfterDecimal(), - currency.getCurrencyInMultiplesOf(), "", ""); - accountingBridgeData.put("currency", currencyData); + accountingBridgeData.put("currencyCode", account.getCurrency().getCode()); final List> newTransactionsMap = new ArrayList<>(); accountingBridgeData.put("newTransactions", newTransactionsMap); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index 05589ef69..f2a61b0db 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -4167,7 +4167,7 @@ public class ClientLoanIntegrationTest { todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant()); Integer overdueFeeChargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, - ChargesHelper.getLoanOverdueFeeJSONWithCalculattionTypePercentage("10")); + ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("10")); Assertions.assertNotNull(overdueFeeChargeId); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java index b7d0435fc..52695379e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java @@ -230,7 +230,8 @@ public class SchedulerJobsTestResults { final Integer loanProductID = createLoanProduct(null); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), savingsId.toString()); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), savingsId.toString(), + "10 January 2013"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -281,7 +282,7 @@ public class SchedulerJobsTestResults { final Integer loanProductID = createLoanProduct(null); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2013"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -378,7 +379,7 @@ public class SchedulerJobsTestResults { } @Test - public void testUpdateAccountingRunningBalancesJobOutcome() throws InterruptedException { + public void testUpdateAccountingRunningBalancesJobOutcome() { this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec); final Account assetAccount = this.accountHelper.createAssetAccount(); @@ -421,7 +422,7 @@ public class SchedulerJobsTestResults { } @Test - public void testUpdateLoanArrearsAgingJobOutcome() throws InterruptedException { + public void testUpdateLoanArrearsAgingJobOutcome() { loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); @@ -430,7 +431,7 @@ public class SchedulerJobsTestResults { final Integer loanProductID = createLoanProduct(null); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2013"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -560,18 +561,18 @@ public class SchedulerJobsTestResults { final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); - loanStatusHashMap = this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID); + loanStatusHashMap = this.loanTransactionHelper.approveLoan("01 March 2020", loanID); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID); - loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE, - loanID, JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); + loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID, + JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); String JobName = "Apply penalty to overdue loans"; @@ -592,6 +593,59 @@ public class SchedulerJobsTestResults { LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); } + @Test + public void testLoanCOBJobOutcome() { + this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec); + this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + + final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); + Assertions.assertNotNull(clientID); + + Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1")); + Assertions.assertNotNull(overdueFeeChargeId); + + final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); + Assertions.assertNotNull(loanProductID); + List loanIDs = new ArrayList<>(); + HashMap loanStatusHashMap; + for (int i = 0; i < 10; i++) { + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); + + Assertions.assertNotNull(loanID); + + loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + loanStatusHashMap = this.loanTransactionHelper.approveLoan("01 March 2020", loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + + String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID); + loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID, + JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + loanIDs.add(loanID); + + } + + String jobName = "Loan COB"; + this.schedulerJobHelper.executeAndAwaitJob(jobName); + for (Integer loanId : loanIDs) { + List repaymentScheduleDataAfter = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, + loanId); + + Assertions.assertEquals(39.39f, (Float) repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"), + "Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job"); + Assertions.assertEquals(39.39f, (Float) repaymentScheduleDataAfter.get(2).get("penaltyChargesDue"), + "Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job"); + Assertions.assertEquals(39.39f, (Float) repaymentScheduleDataAfter.get(3).get("penaltyChargesDue"), + "Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job"); + Assertions.assertEquals(39.39f, (Float) repaymentScheduleDataAfter.get(4).get("penaltyChargesDue"), + "Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job"); + + } + } + @Test public void testAvoidUnncessaryPenaltyWhenAmountZeroForOverdueLoansJobOutcome() throws InterruptedException { this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec); @@ -601,13 +655,13 @@ public class SchedulerJobsTestResults { Assertions.assertNotNull(clientID); Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, - ChargesHelper.getLoanOverdueFeeJSONWithCalculattionTypePercentage("0.000001")); + ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("0.000001")); Assertions.assertNotNull(overdueFeeChargeId); final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2013"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -659,7 +713,7 @@ public class SchedulerJobsTestResults { final Integer loanProductID = createLoanProduct(null); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null); + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2013"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -794,7 +848,7 @@ public class SchedulerJobsTestResults { return collateral; } - private Integer applyForLoanApplication(final String clientID, final String loanProductID, final String savingsID) { + private Integer applyForLoanApplication(final String clientID, final String loanProductID, final String savingsID, final String date) { List collaterals = new ArrayList<>(); final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); @@ -808,7 +862,7 @@ public class SchedulerJobsTestResults { .withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1") .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withAmortizationTypeAsEqualInstallments() .withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("10 January 2013").withSubmittedOnDate("10 January 2013").withCollaterals(collaterals) + .withExpectedDisbursementDate(date).withSubmittedOnDate(date).withCollaterals(collaterals) .build(clientID, loanProductID, savingsID); return this.loanTransactionHelper.getLoanId(loanApplicationJSON); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java index baf1cfa7f..38119c95d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java @@ -302,7 +302,7 @@ public final class ChargesHelper { return chargesCreateJson; } - public static String getLoanOverdueFeeJSONWithCalculattionTypePercentage(String penaltyPercentageAmount) { + public static String getLoanOverdueFeeJSONWithCalculationTypePercentage(String penaltyPercentageAmount) { final HashMap map = populateDefaultsForLoan(); map.put("penalty", ChargesHelper.PENALTY); map.put("amount", penaltyPercentageAmount);