diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java index e4fdafdc0b9..13b2344eb14 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java @@ -1654,7 +1654,9 @@ public void setCustomChargeHonorarioMaps(Set customCha public boolean isVatChargeOfHonoCharge() { for (LoanCharge parentCharge : this.loan.getCharges()) { - return parentCharge.isFlatHono() && parentCharge.getCharge().getId().equals(this.getCharge().getParentChargeId()); + if (parentCharge.isFlatHono() && parentCharge.getCharge().getId().equals(this.getCharge().getParentChargeId())) { + return true; + } } return false; } @@ -1664,7 +1666,7 @@ public BigDecimal getVatAmountOfHonoCharge(Integer installmentNumber) { for (LoanCharge parentCharge : this.loan.getCharges()) { if (parentCharge.isFlatHono() && parentCharge.getCharge().getId().equals(this.getCharge().getParentChargeId())) { if (!parentCharge.getCustomChargeHonorarioMaps().isEmpty()) { - for (CustomChargeHonorarioMap customCharge : this.getCustomChargeHonorarioMaps()) { + for (CustomChargeHonorarioMap customCharge : parentCharge.getCustomChargeHonorarioMaps()) { if (customCharge.getLoanInstallmentNr().equals(installmentNumber)) { customAmout = customAmout.add(customCharge.getFeeVatAmount()); } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java index 4116bda7fca..42b9a1421af 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java @@ -99,7 +99,11 @@ private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final L cumulative = cumulative.plus(loanCharge.calculateCustomFeeChargeToInstallment(period.getInstallmentNumber(), totalPrincipal, totalInstallments, outstandingBalance)); } else { - cumulative = cumulative.plus(getInstallmentFee(monetaryCurrency, period, loanCharge)); + if (loanCharge.getChargeCalculation().isFlatHono()) { + cumulative = Money.zero(monetaryCurrency); + } else { + cumulative = cumulative.plus(getInstallmentFee(monetaryCurrency, period, loanCharge)); + } } } else if (loanCharge.isOverdueInstallmentCharge() && isDue && loanCharge.getChargeCalculation().isPercentageBased()) { cumulative = cumulative.plus(loanCharge.chargeAmount()); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index 81bb6719b27..2e262da33e7 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -1133,7 +1133,7 @@ private Money processAllocationsHorizontally(LoanTransaction loanTransaction, Mo } LoanRepaymentScheduleInstallment dueInstallment = installments.stream() .filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) - .filter(e -> loanTransaction.isOnOrBetween(e.getFromDate(), e.getDueDate())) + .filter(e -> loanTransaction.isOnOrBetween(e.getFromDate(), e.getDueDate()) || loanTransaction.isOn(e.getDueDate())) .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).orElse(null); found = false; 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 8d2c15cd090..8291f5fbca0 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 @@ -334,7 +334,16 @@ public void updateRepaymentInstalmentCharge(LoanRepaymentScheduleInstallment loa @Override public FeeCalculationHonorario calculateFeeHonorario(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, BigDecimal repaymentAmount) { - Integer ageOverdue = loanRepaymentScheduleInstallment.getLoan().getAgeOfOverdueDays(DateUtils.getBusinessLocalDate()).intValue(); + // SU-529 Get maximum age of any of the client's loan + List clientActiveLoans = this.loanRepositoryWrapper + .findActiveLoansByClientId(loanRepaymentScheduleInstallment.getLoan().getClientId()); + Integer ageOverdue = 0; + for (Loan loan : clientActiveLoans) { + int overdue = loan.getAgeOfOverdueDays(DateUtils.getBusinessLocalDate()).intValue(); + if (overdue > ageOverdue) { + ageOverdue = overdue; + } + } BigDecimal delinquencyValue = BigDecimal.ZERO; // Retrieve VAT configuration and percentage diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepositoryWrapper.java index 78e5cb3bbea..3b43b960e91 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepositoryWrapper.java @@ -221,6 +221,16 @@ public List findByGroupOfficeIdsAndLoanStatus(@Param("officeIds") Collecti return loans; } + public List findActiveLoansByClientId(@Param("clientId") Long clientId) { + List loans = this.repository.findActiveLoansByClientId(clientId); + if (loans != null && loans.size() > 0) { + for (Loan loan : loans) { + loan.initializeRepaymentSchedule(); + } + } + return loans; + } + public List findActiveLoansLoanProductIdsByClient(@Param("clientId") Long clientId, @Param("loanStatus") Integer loanStatus) { return this.repository.findActiveLoansLoanProductIdsByClient(clientId, loanStatus); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java index 2bae2b5bf62..5eff74454be 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java @@ -2551,7 +2551,9 @@ private Money calculateInstallmentCharge(final PrincipalInterest principalIntere numberOfRepayments, outstandingBalance); cumulative = cumulative.plus(calculatedAmount); } else { - if (loanCharge.defaultFromInstallment() != null && installmentNumber >= loanCharge.defaultFromInstallment()) { + if (loanCharge.isFlatHono()) { + calculatedAmount = BigDecimal.ZERO; + } else if (loanCharge.defaultFromInstallment() != null && installmentNumber >= loanCharge.defaultFromInstallment()) { calculatedAmount = BigDecimal.ZERO; } else { calculatedAmount = loanCharge.amountOrPercentage(); 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 d22631b83ba..8dce2be7975 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 @@ -234,7 +234,17 @@ public LoanAccountData retrieveLoanByLoanAccount(String loanAccountNumber) { private FeeCalculationHonorario calculateFeeDetails(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, BigDecimal repaymentAmount) { - Integer ageOverdue = loanRepaymentScheduleInstallment.getLoan().getAgeOfOverdueDays(DateUtils.getBusinessLocalDate()).intValue(); + // SU-529 Get maximum age of any of the client's loan + List clientActiveLoans = this.loanRepositoryWrapper + .findActiveLoansByClientId(loanRepaymentScheduleInstallment.getLoan().getClientId()); + Integer ageOverdue = 0; + for (Loan loan : clientActiveLoans) { + int overdue = loan.getAgeOfOverdueDays(DateUtils.getBusinessLocalDate()).intValue(); + if (overdue > ageOverdue) { + ageOverdue = overdue; + } + } + BigDecimal delinquencyValue = BigDecimal.ZERO; // Retrieve VAT configuration and percentage Integer vatConfig = configurationDomainService.retriveIvaConfiguration(); @@ -3992,6 +4002,7 @@ private BigDecimal calculateHonoChargeAmount(Loan loan, LocalDate transactionDat remainingAmount = remainingAmount.minus(installmentOutstandingAmount); } else { feeCalculationHonorario = this.calculateFeeDetails(installment, remainingAmount.getAmount()); + remainingAmount = remainingAmount.zero(); } feeHono = feeHono.add(feeCalculationHonorario.getFeeBasis()); if (vatHono.isPresent()) { 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 8985dbec70c..ddf97e16639 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 @@ -1170,10 +1170,15 @@ public CommandProcessingResult makeLoanRepayment(final LoanTransactionType repay fee = this.loanAccountDomainService.updateCalculationHonoLoanChargeOverDueVat(installmentOutstandingAmount, installment, installmentNumber, version); remainingAmount = remainingAmount.minus(installmentOutstandingAmount); + remainingAmount = remainingAmount.minus(fee.getFeeBasis()); + if (vatChargeOptional.isPresent()) { + remainingAmount = remainingAmount.minus(fee.getFeeVat()); + } } else { fee = this.loanAccountDomainService.updateCalculationHonoLoanChargeOverDueVat(remainingAmount.getAmount(), installment, installmentNumber, version); + remainingAmount = remainingAmount.zero(); } remainingAmount = remainingAmount.minus(fee.getFeeBasis()); @@ -1543,6 +1548,10 @@ public CommandProcessingResult adjustLoanTransaction(final Long loanId, final Lo } remove.forEach(chargePaidBy.getLoanCharge().getCustomChargeHonorarioMaps()::remove); customChargeHonorarioMapRepository.deleteLatestVersionMapEntryOnReversal(loanId, versionToBeDeleted); + transactionToAdjust.getLoanTransactionToRepaymentScheduleMappings().clear(); + final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper(); + wrapper.reprocess(loan.getCurrency(), loan.getDisbursementDate(), loan.getRepaymentScheduleInstallments(), + loan.getActiveCharges()); break; } }