|
82 | 82 | import org.apache.fineract.portfolio.client.domain.ClientEnumerations; |
83 | 83 | import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; |
84 | 84 | import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; |
| 85 | +import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; |
85 | 86 | import org.apache.fineract.portfolio.common.service.CommonEnumerations; |
86 | 87 | import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData; |
87 | 88 | import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; |
@@ -1728,16 +1729,57 @@ public LoanTransactionData retrieveLoanWriteoffTemplate(final Long loanId) { |
1728 | 1729 |
|
1729 | 1730 | @Override |
1730 | 1731 | public LoanTransactionData retrieveLoanReAgeTemplate(final Long loanId) { |
1731 | | - final LoanAccountData loan = this.retrieveOne(loanId); |
| 1732 | + final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true); |
1732 | 1733 | final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REAGE); |
1733 | 1734 | final BigDecimal totalOutstanding = loan.getSummary() != null ? loan.getSummary().getTotalOutstanding() : null; |
1734 | 1735 | final List<CodeValueData> reAgeReasonOptions = new ArrayList<>( |
1735 | 1736 | codeValueReadPlatformService.retrieveCodeValuesByCode(LoanApiConstants.REAGE_REASONS)); |
1736 | | - return LoanTransactionData.builder().type(transactionType).currency(loan.getCurrency()).date(DateUtils.getBusinessLocalDate()) |
1737 | | - .amount(totalOutstanding).netDisbursalAmount(loan.getNetDisbursalAmount()).loanId(loanId) |
1738 | | - .externalLoanId(loan.getExternalId()).periodFrequencyOptions(CommonEnumerations.BASIC_PERIOD_FREQUENCY_TYPES) |
1739 | | - .reAgeReasonOptions(reAgeReasonOptions) |
1740 | | - .reAgeInterestHandlingOptions(LoanReAgeInterestHandlingType.getValuesAsEnumOptionDataList()).build(); |
| 1737 | + |
| 1738 | + final LocalDate businessDate = DateUtils.getBusinessLocalDate(); |
| 1739 | + final List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments(); |
| 1740 | + |
| 1741 | + int futureInstallmentCount = 0; |
| 1742 | + int pastInstallmentCount = 0; |
| 1743 | + LocalDate nextInstallmentDueDate = null; |
| 1744 | + |
| 1745 | + for (LoanRepaymentScheduleInstallment installment : installments) { |
| 1746 | + LocalDate dueDate = installment.getDueDate(); |
| 1747 | + if (DateUtils.isAfter(dueDate, businessDate)) { |
| 1748 | + futureInstallmentCount++; |
| 1749 | + if (nextInstallmentDueDate == null || DateUtils.isBefore(dueDate, nextInstallmentDueDate)) { |
| 1750 | + nextInstallmentDueDate = dueDate; |
| 1751 | + } |
| 1752 | + } else { |
| 1753 | + pastInstallmentCount++; |
| 1754 | + } |
| 1755 | + } |
| 1756 | + |
| 1757 | + final PeriodFrequencyType frequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType(); |
| 1758 | + final LocalDate calculatedStartDate = calculateReAgeStartDate(businessDate, frequencyType); |
| 1759 | + |
| 1760 | + final CurrencyData currencyData = new CurrencyData(loan.getCurrencyCode(), null, loan.getCurrency().getDigitsAfterDecimal(), |
| 1761 | + loan.getCurrency().getInMultiplesOf(), null, null); |
| 1762 | + |
| 1763 | + return LoanTransactionData.builder().type(transactionType).currency(currencyData).date(businessDate).amount(totalOutstanding) |
| 1764 | + .netDisbursalAmount(loan.getNetDisbursalAmount()).loanId(loanId).externalLoanId(loan.getExternalId()) |
| 1765 | + .periodFrequencyOptions(CommonEnumerations.BASIC_PERIOD_FREQUENCY_TYPES).reAgeReasonOptions(reAgeReasonOptions) |
| 1766 | + .reAgeInterestHandlingOptions(LoanReAgeInterestHandlingType.getValuesAsEnumOptionDataList()) |
| 1767 | + .numberOfFutureInstallments(futureInstallmentCount).numberOfPastInstallments(pastInstallmentCount) |
| 1768 | + .nextInstallmentDueDate(nextInstallmentDueDate).calculatedStartDate(calculatedStartDate).build(); |
| 1769 | + } |
| 1770 | + |
| 1771 | + private LocalDate calculateReAgeStartDate(LocalDate businessDate, PeriodFrequencyType frequencyType) { |
| 1772 | + if (frequencyType == null) { |
| 1773 | + return null; |
| 1774 | + } |
| 1775 | + // Per PS-2795: calculated start date = current date + 1 unit of original frequency type |
| 1776 | + return switch (frequencyType) { |
| 1777 | + case DAYS -> businessDate.plusDays(1); |
| 1778 | + case WEEKS -> businessDate.plusWeeks(1); |
| 1779 | + case MONTHS -> businessDate.plusMonths(1); |
| 1780 | + case YEARS -> businessDate.plusYears(1); |
| 1781 | + case WHOLE_TERM, INVALID -> null; |
| 1782 | + }; |
1741 | 1783 | } |
1742 | 1784 |
|
1743 | 1785 | @Override |
|
0 commit comments