From 7e06bae2f56bdb7b5a2c9859dff8e1709411a372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Soma=20S=C3=B6r=C3=B6s?= Date: Wed, 8 Jul 2026 10:35:26 +0200 Subject: [PATCH 1/2] FINERACT-2455: Working Capital - Delinquency Reset --- ...ngCapitalDelinquencyRescheduleStepDef.java | 30 +- .../WorkingCapitalDelinquencyReset.feature | 284 ++++++++++++++++++ .../delinquency/domain/DelinquencyAction.java | 4 +- ...ngCapitalLoanDelinquencyRangeSchedule.java | 16 + ...inquencyRangeScheduleTagHistoryMapper.java | 4 +- ...oanDelinquencyRangeScheduleRepository.java | 26 ++ ...LoanDelinquencyActionWriteServiceImpl.java | 14 + ...lLoanDelinquencyClassificationService.java | 4 + ...nDelinquencyClassificationServiceImpl.java | 3 +- ...alLoanDelinquencyRangeScheduleService.java | 4 + ...anDelinquencyRangeScheduleServiceImpl.java | 51 +++- ...oanDelinquencyActionParseAndValidator.java | 28 ++ .../module-changelog-master.xml | 1 + .../parts/0054_wc_loan_delinquency_reset.xml | 59 ++++ 14 files changed, 515 insertions(+), 13 deletions(-) create mode 100644 fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature create mode 100644 fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0054_wc_loan_delinquency_reset.xml diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java index f13f03ceafd..739fb2817ce 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java @@ -126,6 +126,24 @@ public void createWcDelinquencyBucket(final int frequency, final String frequenc frequencyType, minimumPayment, minimumPaymentType); } + @When("Admin creates WC delinquency reset action") + public void createResetAction() { + final PostWorkingCapitalLoansDelinquencyActionRequest request = new PostWorkingCapitalLoansDelinquencyActionRequest(); + request.setAction("reset"); + request.setLocale("en"); + + executeRescheduleAction(request); + } + + @When("Admin creates WC delinquency undo reset action") + public void createUndoResetAction() { + final PostWorkingCapitalLoansDelinquencyActionRequest request = new PostWorkingCapitalLoansDelinquencyActionRequest(); + request.setAction("undo_reset"); + request.setLocale("en"); + + executeRescheduleAction(request); + } + @When("Admin creates WC delinquency reschedule action with the following parameters:") public void createRescheduleAction(final DataTable table) { final Map params = table.asMaps().get(0); @@ -318,9 +336,15 @@ private void verifyFullScheduleField(final WorkingCapitalLoanDelinquencyRangeSch case "periodNumber" -> assertThat(actual.getPeriodNumber()).as(label).isEqualTo(Integer.parseInt(expected)); case "fromDate" -> assertThat(actual.getFromDate()).as(label).isEqualTo(LocalDate.parse(expected, DATE_FORMAT)); case "toDate" -> assertThat(actual.getToDate()).as(label).isEqualTo(LocalDate.parse(expected, DATE_FORMAT)); - case "expectedAmount" -> assertThat(actual.getExpectedAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)); - case "paidAmount" -> assertThat(actual.getPaidAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)); - case "outstandingAmount" -> assertThat(actual.getOutstandingAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)); + case "expectedAmount" -> verifyOptionalField(expected, + v -> assertThat(actual.getExpectedAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)), + () -> assertThat(actual.getExpectedAmount()).as(label).isNull()); + case "paidAmount" -> verifyOptionalField(expected, + v -> assertThat(actual.getPaidAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)), + () -> assertThat(actual.getPaidAmount()).as(label).isNull()); + case "outstandingAmount" -> verifyOptionalField(expected, + v -> assertThat(actual.getOutstandingAmount()).as(label).isEqualByComparingTo(new BigDecimal(expected)), + () -> assertThat(actual.getOutstandingAmount()).as(label).isNull()); case "minPaymentCriteriaMet" -> verifyOptionalField(expected, v -> assertThat(actual.getMinPaymentCriteriaMet()).as(label).isEqualTo(Boolean.parseBoolean(v)), () -> assertThat(actual.getMinPaymentCriteriaMet()).as(label).isNull()); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature new file mode 100644 index 00000000000..4976bbe73b9 --- /dev/null +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature @@ -0,0 +1,284 @@ +@WorkingCapital +@WorkingCapitalDelinquencyResetActionFeature @WCCOBFeature +Feature: Working Capital Delinquency Reset Action + + @TestRailId:TODO_ADD_1 + Scenario: Verify that Reset Delinquency Action has correct values on the delinquency range schedule and delinquency tags are lifted then verify undo + When Admin sets the business date to "01 January 2026" + When Admin creates a client with random data + When Admin creates a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | + When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount + When Admin sets the business date to "01 June 2026" + When Admin runs inline COB job for Working Capital Loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | false | + | 6 | 31 May 2026 | 29 June 2026 | 300 | 0 | 300 | | + + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 5 | 2026-06-01 | | D00 | 1 | 30 | + | 4 | 2026-06-01 | | D30 | 31 | 60 | + | 3 | 2026-06-01 | | D60 | 61 | 90 | + | 2 | 2026-06-01 | | D90 | 91 | 120 | + | 1 | 2026-06-01 | | D120 | 121 | 150 | + When Admin creates WC delinquency reset action + Then WC loan last delinquency action has the following data: + | action | startDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 01 June 2026 | | | | | + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | | | | | + | 5 | 01 May 2026 | 30 May 2026 | | | | | + | 6 | 31 May 2026 | 29 June 2026 | 300 | 0 | 300 | | + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 5 | 2026-06-01 | 2026-06-01 | D00 | 1 | 30 | + | 4 | 2026-06-01 | 2026-06-01 | D30 | 31 | 60 | + | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | + | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | + | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | + + When Admin sets the business date to "01 July 2026" + When Admin runs inline COB job for Working Capital Loan + + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 6 | 2026-06-30 | | D00 | 1 | 30 | + | 5 | 2026-06-01 | 2026-06-01 | D00 | 1 | 30 | + | 4 | 2026-06-01 | 2026-06-01 | D30 | 31 | 60 | + | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | + | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | + | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | + + Then Admin creates WC delinquency undo reset action + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | false | + | 6 | 31 May 2026 | 29 June 2026 | 300 | 0 | 300 | false | + | 7 | 30 June 2026 | 29 July 2026 | 300 | 0 | 300 | | + + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 5 | 2026-07-01 | | D30 | 31 | 60 | + | 4 | 2026-07-01 | | D60 | 61 | 90 | + | 3 | 2026-07-01 | | D90 | 91 | 120 | + | 2 | 2026-07-01 | | D120 | 121 | 150 | + | 1 | 2026-07-01 | | D150 | 151 | 180 | + | 6 | 2026-06-30 | | D00 | 1 | 30 | + | 5 | 2026-06-01 | 2026-06-01 | D00 | 1 | 30 | + | 4 | 2026-06-01 | 2026-06-01 | D30 | 31 | 60 | + | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | + | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | + | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | + Then Admin closes the Working Capital loan with a full repayment on "01 July 2026" + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | 300 | 300 | 0 | true | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 300 | 0 | true | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 300 | 0 | true | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 300 | 0 | true | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 300 | 0 | true | + | 6 | 31 May 2026 | 29 June 2026 | 300 | 300 | 0 | true | + | 7 | 30 June 2026 | 29 July 2026 | 300 | 8200 | 0 | true | + + @TestRailId:TODO_ADD_2 + Scenario: Verify multiple Reset Delinquency Action and undo reset + When Admin sets the business date to "01 January 2026" + When Admin creates a client with random data + When Admin creates a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | + When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount + + When Admin sets the business date to "31 January 2026" + When Admin runs inline COB job for Working Capital Loan + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 1 | 2026-01-31 | | D00 | 1 | 30 | + + When Admin creates WC delinquency reset action + + Then WC loan last delinquency action has the following data: + | action | startDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 31 January 2026 | | | | | + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | + + When Admin sets the business date to "2 March 2026" + When Admin runs inline COB job for Working Capital Loan + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | | + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 2 | 2026-03-02 | | D00 | 1 | 30 | + | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | + + When Admin creates WC delinquency reset action + + Then WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 31 January 2026 | | | | | | + | RESET | 02 March 2026 | | | | | | + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | | + And Delinquency Tag History for Working Capital loan has lines: + | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | + | 2 | 2026-03-02 | 2026-03-02 | D00 | 1 | 30 | + | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | + + When Admin sets the business date to "2 April 2026" + When Admin runs inline COB job for Working Capital Loan + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | + + Then Admin creates WC delinquency undo reset action + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | + + When Admin creates WC delinquency reset action + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | + Then Admin closes the Working Capital loan with a full repayment on "02 April 2026" + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 10000 | 0 | true | + + @TestRailId:TODO_ADD_3 + Scenario: Verify multiple Reset Delinquency Action and undo reset for 2nd and 4th reset + When Admin sets the business date to "01 January 2026" + When Admin creates a client with random data + When Admin creates a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | + When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount + + When Admin sets the business date to "31 January 2026" + When Admin runs inline COB job for Working Capital Loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | + When Admin creates WC delinquency reset action + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | + + When Admin sets the business date to "02 March 2026" + When Admin runs inline COB job for Working Capital Loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | | + + When Admin creates WC delinquency reset action + + When Admin sets the business date to "02 April 2026" + When Admin runs inline COB job for Working Capital Loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | + + Then Admin creates WC delinquency undo reset action + When Admin creates WC delinquency reset action + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | + + + When Admin sets the business date to "02 May 2026" + When Admin runs inline COB job for Working Capital Loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | + + When Admin creates WC delinquency reset action + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | | | | | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | + + Then Admin creates WC delinquency undo reset action + + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | + Then Admin closes the Working Capital loan with a full repayment on "02 May 2026" + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 300 | 300 | 0 | true | + | 5 | 01 May 2026 | 30 May 2026 | 300 | 9700 | 0 | true | diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/domain/DelinquencyAction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/domain/DelinquencyAction.java index b2192bf8410..05b273b4bcb 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/domain/DelinquencyAction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/domain/DelinquencyAction.java @@ -21,5 +21,7 @@ public enum DelinquencyAction { PAUSE, // RESUME, // - RESCHEDULE // + RESCHEDULE, // + RESET, // + UNDO_RESET // } diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoanDelinquencyRangeSchedule.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoanDelinquencyRangeSchedule.java index 1ecc8b50c76..c5ddd694202 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoanDelinquencyRangeSchedule.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoanDelinquencyRangeSchedule.java @@ -79,4 +79,20 @@ public class WorkingCapitalLoanDelinquencyRangeSchedule extends AbstractAuditabl @Column(name = "delinquent_amount", scale = 6, precision = 19) private BigDecimal delinquentAmount; + @Column(name = "reset") + private Boolean reset = false; + + public void reset() { + setReset(true); + setDelinquentDays(null); + setDelinquentAmount(null); + setMinPaymentCriteriaMet(null); + setPaidAmount(null); + setOutstandingAmount(null); + } + + public BigDecimal getExpectedAmount() { + return reset ? null : this.expectedAmount; + } + } diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/mapper/WorkingCapitalLoanDelinquencyRangeScheduleTagHistoryMapper.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/mapper/WorkingCapitalLoanDelinquencyRangeScheduleTagHistoryMapper.java index 5f9eb42969b..7bf71bc92bd 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/mapper/WorkingCapitalLoanDelinquencyRangeScheduleTagHistoryMapper.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/mapper/WorkingCapitalLoanDelinquencyRangeScheduleTagHistoryMapper.java @@ -45,7 +45,9 @@ public interface WorkingCapitalLoanDelinquencyRangeScheduleTagHistoryMapper { @AfterMapping default void calculateTotal(WorkingCapitalLoanDelinquencyRangeScheduleTagHistory source, @MappingTarget WorkingCapitalLoanDelinquencyTagHistoryData target) { - target.setDelinquentDays(source.getRangeSchedule().getDelinquentDays() - source.getDelinquencyRange().getMinimumAgeDays() + 1); + if (source.getRangeSchedule().getDelinquentDays() != null) { + target.setDelinquentDays(source.getRangeSchedule().getDelinquentDays() - source.getDelinquencyRange().getMinimumAgeDays() + 1); + } } @Mapping(target = "rangeId", source = "delinquencyRange.id") diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/repository/WorkingCapitalLoanDelinquencyRangeScheduleRepository.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/repository/WorkingCapitalLoanDelinquencyRangeScheduleRepository.java index c6dab6297f4..ec6e9bcaba3 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/repository/WorkingCapitalLoanDelinquencyRangeScheduleRepository.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/repository/WorkingCapitalLoanDelinquencyRangeScheduleRepository.java @@ -24,6 +24,7 @@ import java.util.Optional; import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyRangeSchedule; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -42,6 +43,7 @@ public interface WorkingCapitalLoanDelinquencyRangeScheduleRepository WHERE s.loan.id = :loanId AND s.toDate < :transactionDate AND (s.minPaymentCriteriaMet IS NULL OR s.minPaymentCriteriaMet = FALSE) + AND s.reset = false ORDER BY s.periodNumber ASC""") List findPastOpenPeriodsForRepayment(@Param("loanId") Long loanId, @Param("transactionDate") LocalDate transactionDate); @@ -64,4 +66,28 @@ List findByLoanIdAndToDateLessThanEq Optional findTopByLoanIdAndMinPaymentCriteriaMetFalseOrderByFromDateAsc(Long loanId); + List findByLoanIdAndResetIsNotAndToDateBeforeOrderByPeriodNumberAsc(Long id, Boolean reset, + LocalDate startDate); + + @Modifying + @Query(""" + update WorkingCapitalLoanDelinquencyRangeSchedule p + set p.reset = false + where p.loan.id = :loanId + and p.reset = true + and p.toDate < :actionStartDate + """) + int clearResetBeforeActionStartDate(@Param("loanId") Long loanId, @Param("actionStartDate") LocalDate actionStartDate); + + @Modifying + @Query(""" + update WorkingCapitalLoanDelinquencyRangeSchedule p + set p.reset = false + where p.loan.id = :loanId + and p.reset = true + and p.toDate < :actionStartDate + and p.toDate >= :lastActiveResetStartDate + """) + int clearResetBeforeActionStartDateFromLastActiveReset(@Param("loanId") Long loanId, + @Param("actionStartDate") LocalDate actionStartDate, @Param("lastActiveResetStartDate") LocalDate lastActiveResetStartDate); } diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyActionWriteServiceImpl.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyActionWriteServiceImpl.java index 3beede89040..72909a2b1db 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyActionWriteServiceImpl.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyActionWriteServiceImpl.java @@ -25,6 +25,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction; import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoan; import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyAction; @@ -40,10 +41,14 @@ @RequiredArgsConstructor public class WorkingCapitalLoanDelinquencyActionWriteServiceImpl implements WorkingCapitalLoanDelinquencyActionWriteService { + private static final String RESET_RESOURCE_NAME_FOR_PERMISSIONS = "WC_DELINQUENCY_RESET"; + private static final String UNDO_RESET_RESOURCE_NAME_FOR_PERMISSIONS = "WC_DELINQUENCY_UNDO_RESET"; + private final WorkingCapitalLoanRepository loanRepository; private final WorkingCapitalLoanDelinquencyActionRepository actionRepository; private final WorkingCapitalLoanDelinquencyActionParseAndValidator validator; private final WorkingCapitalLoanDelinquencyRangeScheduleService rangeScheduleService; + private final PlatformSecurityContext context; @Transactional @Override @@ -68,6 +73,15 @@ public CommandProcessingResult createDelinquencyAction(final Long workingCapital final WorkingCapitalLoanDelinquencyAction activePause = validator.findActivePauseForResume(existing, DateUtils.getBusinessLocalDate()); rangeScheduleService.resumeActivePause(workingCapitalLoan, activePause, action); + } else if (DelinquencyAction.RESET.equals(action.getAction())) { + context.authenticatedUser().validateHasCreatePermission(RESET_RESOURCE_NAME_FOR_PERMISSIONS); + rangeScheduleService.resetPeriods(workingCapitalLoan, action); + } else if (DelinquencyAction.UNDO_RESET.equals(action.getAction())) { + context.authenticatedUser().validateHasCreatePermission(UNDO_RESET_RESOURCE_NAME_FOR_PERMISSIONS); + List byWorkingCapitalLoanIdOrderById = actionRepository + .findByWorkingCapitalLoanIdOrderById(workingCapitalLoanId); + rangeScheduleService.undoResetPeriods(workingCapitalLoan, action, byWorkingCapitalLoanIdOrderById); + rangeScheduleService.reprocessDelinquencySchedule(workingCapitalLoan); } return new CommandProcessingResultBuilder() // diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationService.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationService.java index b5e4296c363..1ab6424f887 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationService.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationService.java @@ -20,7 +20,9 @@ package org.apache.fineract.portfolio.workingcapitalloan.service; import java.time.LocalDate; +import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange; import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoan; +import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyRangeSchedule; public interface WorkingCapitalLoanDelinquencyClassificationService { @@ -28,4 +30,6 @@ public interface WorkingCapitalLoanDelinquencyClassificationService { void classifyDelinquency(WorkingCapitalLoan loan, LocalDate businessDate); + void applyDelinquencyTagForRange(WorkingCapitalLoan loan, WorkingCapitalLoanDelinquencyRangeSchedule range, + DelinquencyRange currentRange, LocalDate businessDate); } diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationServiceImpl.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationServiceImpl.java index 120db0d0a79..9a088ac6cb4 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationServiceImpl.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyClassificationServiceImpl.java @@ -85,7 +85,7 @@ public void classifyDelinquency(WorkingCapitalLoan loan, LocalDate businessDate) .findByLoanIdOrderByPeriodNumberAsc(loan.getId()); for (WorkingCapitalLoanDelinquencyRangeSchedule range : delinquencyRangeScheduleList) { - if (range.getToDate().isBefore(businessDate)) { + if (!Objects.equals(range.getReset(), true) && range.getToDate().isBefore(businessDate)) { long rangeDelinquentDays = range.getOutstandingAmount().compareTo(BigDecimal.ZERO) > 0 ? DateUtils.getDifferenceInDays(range.getToDate(), businessDate) : 0L; @@ -137,6 +137,7 @@ public Optional findDelinquencyRangeByDays(final DelinquencyBu * @param businessDate * the date on which the tagging operation is performed */ + @Override public void applyDelinquencyTagForRange(final WorkingCapitalLoan loan, final WorkingCapitalLoanDelinquencyRangeSchedule range, final DelinquencyRange currentRange, final LocalDate businessDate) { List updatedList = new ArrayList<>(); diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleService.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleService.java index de0153f46be..db3481eec4d 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleService.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleService.java @@ -58,4 +58,8 @@ void resumeActivePause(WorkingCapitalLoan loan, WorkingCapitalLoanDelinquencyAct */ void reprocessDelinquencySchedule(WorkingCapitalLoan loan); + void resetPeriods(WorkingCapitalLoan workingCapitalLoan, WorkingCapitalLoanDelinquencyAction action); + + void undoResetPeriods(WorkingCapitalLoan workingCapitalLoan, WorkingCapitalLoanDelinquencyAction action, + List byWorkingCapitalLoanIdOrderById); } diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleServiceImpl.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleServiceImpl.java index 0a1f6360a6d..521f479ea3a 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleServiceImpl.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanDelinquencyRangeScheduleServiceImpl.java @@ -168,7 +168,7 @@ private List resetAllPeriodsForRepro if (period.getBaseExpectedAmount() != null) { period.setExpectedAmount(period.getBaseExpectedAmount()); } - period.setPaidAmount(BigDecimal.ZERO); + period.setPaidAmount(period.getReset() ? null : BigDecimal.ZERO); period.setOutstandingAmount(period.getExpectedAmount()); period.setMinPaymentCriteriaMet(null); period.setDelinquentAmount(null); @@ -187,8 +187,8 @@ private void allocateRepayment(final WorkingCapitalLoan loan, final LocalDate tr for (WorkingCapitalLoanDelinquencyRangeSchedule period : pastOpenPeriods) { BigDecimal payAmount = MathUtil.min(transactionAmount, period.getOutstandingAmount(), true); transactionAmount = transactionAmount.subtract(payAmount); - period.setPaidAmount(period.getPaidAmount().add(payAmount)); - period.setOutstandingAmount(period.getOutstandingAmount().subtract(payAmount)); + period.setPaidAmount(MathUtil.nullToZero(period.getPaidAmount()).add(payAmount)); + period.setOutstandingAmount(MathUtil.nullToZero(period.getOutstandingAmount()).subtract(payAmount)); if (period.getOutstandingAmount().compareTo(BigDecimal.ZERO) <= 0) { period.setMinPaymentCriteriaMet(true); period.setDelinquentAmount(BigDecimal.ZERO); @@ -201,12 +201,12 @@ private void allocateRepayment(final WorkingCapitalLoan loan, final LocalDate tr break; } } - if (currentPeriod.isPresent()) { + if (currentPeriod.isPresent() && !currentPeriod.get().getReset()) { WorkingCapitalLoanDelinquencyRangeSchedule period = currentPeriod.get(); - BigDecimal newPaidAmount = period.getPaidAmount().add(transactionAmount); + BigDecimal newPaidAmount = MathUtil.nullToZero(period.getPaidAmount()).add(transactionAmount); period.setPaidAmount(newPaidAmount); - period.setOutstandingAmount(period.getExpectedAmount().subtract(newPaidAmount).max(BigDecimal.ZERO)); - if (newPaidAmount.compareTo(period.getExpectedAmount()) >= 0) { + period.setOutstandingAmount(MathUtil.nullToZero(period.getExpectedAmount()).subtract(newPaidAmount).max(BigDecimal.ZERO)); + if (newPaidAmount.compareTo(MathUtil.nullToZero(period.getExpectedAmount())) >= 0) { period.setMinPaymentCriteriaMet(true); period.setDelinquentAmount(BigDecimal.ZERO); period.setDelinquentDays(0L); @@ -222,6 +222,9 @@ public void evaluateExpiredPeriods(WorkingCapitalLoan loan, LocalDate businessDa List unevaluatedPeriods = loanDelinquencyRangeScheduleRepository .findByLoanIdAndToDateLessThanEqualAndMinPaymentCriteriaMetIsNull(loan.getId(), businessDate); for (WorkingCapitalLoanDelinquencyRangeSchedule period : unevaluatedPeriods) { + if (period.getReset()) { + continue; + } capPeriodToRemainingBalance(period, loan); boolean criteriaMet = period.getPaidAmount().compareTo(period.getExpectedAmount()) >= 0; period.setMinPaymentCriteriaMet(criteriaMet); @@ -294,6 +297,40 @@ public void resumeActivePause(final WorkingCapitalLoan loan, final WorkingCapita recalculateDelinquencyAfterPauseResume(loan, businessDate); } + @Override + public void resetPeriods(WorkingCapitalLoan loan, WorkingCapitalLoanDelinquencyAction action) { + LocalDate resetDate = action.getStartDate(); + + final List periods = loanDelinquencyRangeScheduleRepository + .findByLoanIdAndResetIsNotAndToDateBeforeOrderByPeriodNumberAsc(loan.getId(), true, action.getStartDate()); + periods.forEach(p1 -> resetPeriod(p1, resetDate)); + } + + private void resetPeriod(WorkingCapitalLoanDelinquencyRangeSchedule period, LocalDate resetDate) { + period.reset(); + delinquencyClassificationService.applyDelinquencyTagForRange(period.getLoan(), period, null, resetDate); + } + + @Override + public void undoResetPeriods(WorkingCapitalLoan loan, WorkingCapitalLoanDelinquencyAction action, + List byWorkingCapitalLoanIdOrderById) { + + List activeResets = byWorkingCapitalLoanIdOrderById.stream() + .filter(a -> DelinquencyAction.RESET.equals(a.getAction()) && a.getEndDate() == null).toList(); + if (!activeResets.isEmpty()) { + activeResets.getLast().setEndDate(action.getStartDate()); + } + LocalDate lastActiveResetStartDate = activeResets.size() >= 2 ? activeResets.get(activeResets.size() - 2).getStartDate() : null; + + if (lastActiveResetStartDate == null) { + loanDelinquencyRangeScheduleRepository.clearResetBeforeActionStartDate(loan.getId(), action.getStartDate()); + } else { + loanDelinquencyRangeScheduleRepository.clearResetBeforeActionStartDateFromLastActiveReset(loan.getId(), action.getStartDate(), + lastActiveResetStartDate); + } + reprocessDelinquencySchedule(loan); + } + private void shrinkPeriodsForPause(final WorkingCapitalLoan loan, final LocalDate pauseStart, final LocalDate originalPauseEnd, final LocalDate newPauseEnd) { final long daysToRemove = WorkingCapitalLoanDelinquencyPauseUtils.calculateDaysRemovedOnResume(pauseStart, newPauseEnd, diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/validator/WorkingCapitalLoanDelinquencyActionParseAndValidator.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/validator/WorkingCapitalLoanDelinquencyActionParseAndValidator.java index ac4b9375ba6..369f1d8afa6 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/validator/WorkingCapitalLoanDelinquencyActionParseAndValidator.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/validator/WorkingCapitalLoanDelinquencyActionParseAndValidator.java @@ -76,6 +76,10 @@ public WorkingCapitalLoanDelinquencyAction validateAndParse(final JsonCommand co validateReschedule(parsedAction, workingCapitalLoan, dataValidator); } else if (DelinquencyAction.RESUME.equals(parsedAction.getAction())) { validateResume(parsedAction, existing, dataValidator); + } else if (DelinquencyAction.RESET.equals(parsedAction.getAction())) { + validateReset(parsedAction, dataValidator); + } else if (DelinquencyAction.UNDO_RESET.equals(parsedAction.getAction())) { + validateUndoReset(parsedAction, dataValidator); } throwExceptionIfValidationWarningsExist(dataValidator); @@ -120,6 +124,22 @@ private void validateResume(final WorkingCapitalLoanDelinquencyAction action, fi } } + private void validateReset(WorkingCapitalLoanDelinquencyAction action, DataValidatorBuilder dataValidator) { + final LocalDate businessDate = DateUtils.getBusinessLocalDate(); + dataValidator.reset().parameter(START_DATE).value(action.getStartDate()).ignoreIfNull().isOneOfTheseValues(businessDate); + if (action.getEndDate() == null) { + action.setStartDate(businessDate); + } + } + + private void validateUndoReset(WorkingCapitalLoanDelinquencyAction action, DataValidatorBuilder dataValidator) { + final LocalDate businessDate = DateUtils.getBusinessLocalDate(); + dataValidator.reset().parameter(START_DATE).value(action.getStartDate()).ignoreIfNull().isOneOfTheseValues(businessDate); + if (action.getEndDate() == null) { + action.setStartDate(businessDate); + } + } + private void validateResumeStartDate(final WorkingCapitalLoanDelinquencyAction action, final LocalDate businessDate, final DataValidatorBuilder dataValidator) { dataValidator.reset().parameter(START_DATE).value(action.getStartDate()).notNull(); @@ -179,6 +199,10 @@ private WorkingCapitalLoanDelinquencyAction parseCommand(final JsonCommand comma action.setFrequencyType(extractFrequencyType(json, dataValidator)); } else if (DelinquencyAction.RESUME.equals(action.getAction())) { action.setStartDate(extractDate(json, START_DATE)); + } else if (DelinquencyAction.RESET.equals(action.getAction())) { + action.setStartDate(extractDate(json, START_DATE)); + } else if (DelinquencyAction.UNDO_RESET.equals(action.getAction())) { + action.setStartDate(extractDate(json, START_DATE)); } return action; @@ -196,6 +220,10 @@ private DelinquencyAction extractAction(final JsonElement json, final DataValida return DelinquencyAction.RESCHEDULE; } else if ("resume".equalsIgnoreCase(actionString)) { return DelinquencyAction.RESUME; + } else if ("reset".equalsIgnoreCase(actionString)) { + return DelinquencyAction.RESET; + } else if ("undo_reset".equalsIgnoreCase(actionString)) { + return DelinquencyAction.UNDO_RESET; } failParameterValidation(dataValidator, ACTION, "invalid.action", "Invalid Delinquency Action: " + actionString + ". Supported actions: pause, reschedule, resume"); diff --git a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml index 626ced2a8a7..9bc0fba6d32 100644 --- a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml +++ b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml @@ -75,4 +75,5 @@ + diff --git a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0054_wc_loan_delinquency_reset.xml b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0054_wc_loan_delinquency_reset.xml new file mode 100644 index 00000000000..788d4efc8a1 --- /dev/null +++ b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0054_wc_loan_delinquency_reset.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + SELECT COUNT(*) + FROM m_permission + WHERE code = 'CREATE_WC_DELINQUENCY_RESET' + + + + + + + + + + + + + + + + + From 556f3e2b8e2f3067d1142ba7efb8dbe9af500fa0 Mon Sep 17 00:00:00 2001 From: Peter Kovacs Date: Mon, 20 Jul 2026 13:02:59 +0200 Subject: [PATCH 2/2] FINERACT-2455: Working Capital - Delinquency Reset - E2E tests --- ...ngCapitalDelinquencyRescheduleStepDef.java | 6 +- .../WorkingCapitalDelinquencyReset.feature | 361 ++++++++++++++---- 2 files changed, 285 insertions(+), 82 deletions(-) diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java index 739fb2817ce..7cf55b5b11e 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalDelinquencyRescheduleStepDef.java @@ -126,7 +126,7 @@ public void createWcDelinquencyBucket(final int frequency, final String frequenc frequencyType, minimumPayment, minimumPaymentType); } - @When("Admin creates WC delinquency reset action") + @When("Admin creates a Working Capital delinquency reset") public void createResetAction() { final PostWorkingCapitalLoansDelinquencyActionRequest request = new PostWorkingCapitalLoansDelinquencyActionRequest(); request.setAction("reset"); @@ -135,7 +135,7 @@ public void createResetAction() { executeRescheduleAction(request); } - @When("Admin creates WC delinquency undo reset action") + @When("Admin creates Working Capital delinquency reset undo") public void createUndoResetAction() { final PostWorkingCapitalLoansDelinquencyActionRequest request = new PostWorkingCapitalLoansDelinquencyActionRequest(); request.setAction("undo_reset"); @@ -293,7 +293,7 @@ public void verifySpecificPeriods(final DataTable table) { private void executeRescheduleAction(final PostWorkingCapitalLoansDelinquencyActionRequest request) { final Long loanId = getLoanId(); - log.info("Creating RESCHEDULE action for WC loan {}: {}", loanId, request); + log.debug("Creating RESCHEDULE action for WC loan {}: {}", loanId, request); final PostWorkingCapitalLoansDelinquencyActionResponse result = ok( () -> fineractFeignClient.workingCapitalLoanDelinquencyActions().createDelinquencyAction(loanId, request)); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature index 4976bbe73b9..557a9980092 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalDelinquencyReset.feature @@ -1,18 +1,19 @@ @WorkingCapital -@WorkingCapitalDelinquencyResetActionFeature @WCCOBFeature +@WorkingCapitalDelinquencyResetActionFeature Feature: Working Capital Delinquency Reset Action - @TestRailId:TODO_ADD_1 - Scenario: Verify that Reset Delinquency Action has correct values on the delinquency range schedule and delinquency tags are lifted then verify undo + @TestRailId:C89741 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC1: delinquency reset / reset undo has correct values on the delinquency range schedule and delinquency tags are lifted When Admin sets the business date to "01 January 2026" - When Admin creates a client with random data - When Admin creates a working capital loan with the following data: + And Admin creates a client with random data + And Admin creates a working capital loan with the following data: | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | - When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount - When Admin sets the business date to "01 June 2026" - When Admin runs inline COB job for Working Capital Loan +# --- Initial state --- + And Admin sets the business date to "01 June 2026" + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | @@ -21,7 +22,6 @@ Feature: Working Capital Delinquency Reset Action | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | false | | 6 | 31 May 2026 | 29 June 2026 | 300 | 0 | 300 | | - And Delinquency Tag History for Working Capital loan has lines: | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 5 | 2026-06-01 | | D00 | 1 | 30 | @@ -29,11 +29,12 @@ Feature: Working Capital Delinquency Reset Action | 3 | 2026-06-01 | | D60 | 61 | 90 | | 2 | 2026-06-01 | | D90 | 91 | 120 | | 1 | 2026-06-01 | | D120 | 121 | 150 | - When Admin creates WC delinquency reset action +# --- Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan last delinquency action has the following data: | action | startDate | minimumPayment | minimumPaymentType | frequency | frequencyType | | RESET | 01 June 2026 | | | | | - Then WC loan delinquency range schedule has the following periods: + And WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | @@ -48,11 +49,9 @@ Feature: Working Capital Delinquency Reset Action | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | - When Admin sets the business date to "01 July 2026" - When Admin runs inline COB job for Working Capital Loan - - And Delinquency Tag History for Working Capital loan has lines: + And Admin runs inline COB job for Working Capital Loan by loanId + Then Delinquency Tag History for Working Capital loan has lines: | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 6 | 2026-06-30 | | D00 | 1 | 30 | | 5 | 2026-06-01 | 2026-06-01 | D00 | 1 | 30 | @@ -60,9 +59,8 @@ Feature: Working Capital Delinquency Reset Action | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | - - Then Admin creates WC delinquency undo reset action - +# --- Delinquency reset undo --- + When Admin creates Working Capital delinquency reset undo Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | @@ -72,7 +70,6 @@ Feature: Working Capital Delinquency Reset Action | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | false | | 6 | 31 May 2026 | 29 June 2026 | 300 | 0 | 300 | false | | 7 | 30 June 2026 | 29 July 2026 | 300 | 0 | 300 | | - And Delinquency Tag History for Working Capital loan has lines: | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 5 | 2026-07-01 | | D30 | 31 | 60 | @@ -86,8 +83,10 @@ Feature: Working Capital Delinquency Reset Action | 3 | 2026-06-01 | 2026-06-01 | D60 | 61 | 90 | | 2 | 2026-06-01 | 2026-06-01 | D90 | 91 | 120 | | 1 | 2026-06-01 | 2026-06-01 | D120 | 121 | 150 | - Then Admin closes the Working Capital loan with a full repayment on "01 July 2026" - Then WC loan delinquency range schedule has the following periods: +# --- Close loan --- + When Admin closes the Working Capital loan with a full repayment on "01 July 2026" + Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + And WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | 300 | 300 | 0 | true | | 2 | 31 January 2026 | 01 March 2026 | 300 | 300 | 0 | true | @@ -97,19 +96,18 @@ Feature: Working Capital Delinquency Reset Action | 6 | 31 May 2026 | 29 June 2026 | 300 | 300 | 0 | true | | 7 | 30 June 2026 | 29 July 2026 | 300 | 8200 | 0 | true | - @TestRailId:TODO_ADD_2 - Scenario: Verify multiple Reset Delinquency Action and undo reset + @TestRailId:C89742 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC2: multiple delinquency reset / reset undo When Admin sets the business date to "01 January 2026" - When Admin creates a client with random data - When Admin creates a working capital loan with the following data: + And Admin creates a client with random data + And Admin creates a working capital loan with the following data: | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | - When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount - - When Admin sets the business date to "31 January 2026" - When Admin runs inline COB job for Working Capital Loan - +# --- Initial state --- + And Admin sets the business date to "31 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | @@ -117,23 +115,20 @@ Feature: Working Capital Delinquency Reset Action And Delinquency Tag History for Working Capital loan has lines: | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 1 | 2026-01-31 | | D00 | 1 | 30 | - - When Admin creates WC delinquency reset action - +# --- Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan last delinquency action has the following data: | action | startDate | minimumPayment | minimumPaymentType | frequency | frequencyType | | RESET | 31 January 2026 | | | | | - Then WC loan delinquency range schedule has the following periods: + And WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | And Delinquency Tag History for Working Capital loan has lines: | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | - When Admin sets the business date to "2 March 2026" - When Admin runs inline COB job for Working Capital Loan - + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | @@ -143,9 +138,8 @@ Feature: Working Capital Delinquency Reset Action | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 2 | 2026-03-02 | | D00 | 1 | 30 | | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | - - When Admin creates WC delinquency reset action - +# --- 2nd Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan delinquency actions have the following data: | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | | RESET | 31 January 2026 | | | | | | @@ -159,95 +153,91 @@ Feature: Working Capital Delinquency Reset Action | periodNumber | addedOnDate | liftedOnDate | classification | minimumAgeDays | maximumAgeDays | | 2 | 2026-03-02 | 2026-03-02 | D00 | 1 | 30 | | 1 | 2026-01-31 | 2026-01-31 | D00 | 1 | 30 | - When Admin sets the business date to "2 April 2026" - When Admin runs inline COB job for Working Capital Loan - + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | - - Then Admin creates WC delinquency undo reset action +# --- Delinquency reset undo --- + When Admin creates Working Capital delinquency reset undo Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | - - When Admin creates WC delinquency reset action - +# --- 3rd Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | +# --- Close loan --- Then Admin closes the Working Capital loan with a full repayment on "02 April 2026" - Then WC loan delinquency range schedule has the following periods: + Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + And WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 10000 | 0 | true | - @TestRailId:TODO_ADD_3 - Scenario: Verify multiple Reset Delinquency Action and undo reset for 2nd and 4th reset + @TestRailId:C89743 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC3: multiple delinquency reset - and undo reset for 2nd and 4th reset When Admin sets the business date to "01 January 2026" - When Admin creates a client with random data - When Admin creates a working capital loan with the following data: + And Admin creates a client with random data + And Admin creates a working capital loan with the following data: | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | | WCLP | 01 January 2026 | 01 January 2026 | 10000 | 10000 | 1 | 0.0 | - When Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" + And Admin successfully approves the working capital loan on "01 January 2026" with "10000" amount and expected disbursement date on "01 January 2026" And Admin successfully disburse the Working Capital loan on "01 January 2026" with "10000" EUR transaction amount - - When Admin sets the business date to "31 January 2026" - When Admin runs inline COB job for Working Capital Loan +# --- Initial state --- + And Admin sets the business date to "31 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | 300 | 0 | 300 | false | | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | - When Admin creates WC delinquency reset action +# --- Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | | - When Admin sets the business date to "02 March 2026" - When Admin runs inline COB job for Working Capital Loan + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | 300 | 0 | 300 | false | | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | | - - When Admin creates WC delinquency reset action - - When Admin sets the business date to "02 April 2026" - When Admin runs inline COB job for Working Capital Loan +# --- 2nd Delinquency reset --- + When Admin creates a Working Capital delinquency reset + And Admin sets the business date to "02 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | 300 | 0 | 300 | false | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | - - Then Admin creates WC delinquency undo reset action - When Admin creates WC delinquency reset action - +# --- Delinquency reset undo --- + When Admin creates Working Capital delinquency reset undo +# --- Delinquency reset --- + And Admin creates a Working Capital delinquency reset Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | | - - When Admin sets the business date to "02 May 2026" - When Admin runs inline COB job for Working Capital Loan + And Admin runs inline COB job for Working Capital Loan by loanId Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | @@ -255,8 +245,8 @@ Feature: Working Capital Delinquency Reset Action | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | - - When Admin creates WC delinquency reset action +# --- 3rd Delinquency reset --- + When Admin creates a Working Capital delinquency reset Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | @@ -264,9 +254,8 @@ Feature: Working Capital Delinquency Reset Action | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | | | | | | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | - - Then Admin creates WC delinquency undo reset action - +# --- 2nd Delinquency reset undo --- + When Admin creates Working Capital delinquency reset undo Then WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | @@ -274,11 +263,225 @@ Feature: Working Capital Delinquency Reset Action | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 0 | 300 | false | | 5 | 01 May 2026 | 30 May 2026 | 300 | 0 | 300 | | - Then Admin closes the Working Capital loan with a full repayment on "02 May 2026" - Then WC loan delinquency range schedule has the following periods: + # --- Close loan --- + When Admin closes the Working Capital loan with a full repayment on "02 May 2026" + Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + And WC loan delinquency range schedule has the following periods: | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | | 1 | 01 January 2026 | 30 January 2026 | | | | | | 2 | 31 January 2026 | 01 March 2026 | | | | | | 3 | 02 March 2026 | 31 March 2026 | | | | | | 4 | 01 April 2026 | 30 April 2026 | 300 | 300 | 0 | true | | 5 | 01 May 2026 | 30 May 2026 | 300 | 9700 | 0 | true | + + @TestRailId:C89744 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC4: 2 installments overdue and backdated payment + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates WC Delinquency Bucket with frequency 30 DAYS and minimumPayment 25 PERCENTAGE + And Admin creates a new Working Capital Loan Product with delinquency bucket + And Admin creates a working capital loan using created product with the following data: + | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | 01 January 2026 | 01 January 2026 | 800 | 10000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "800" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "800" EUR transaction amount + # --- Repayments --- + When Admin sets the business date to "15 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 January 2026" with 200.0 transaction amount on Working Capital loan + When Admin sets the business date to "15 February 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 February 2026" with 100.0 transaction amount on Working Capital loan + When Admin sets the business date to "03 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + # --- Delinquency reset --- + When Admin sets the business date to "15 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin creates a Working Capital delinquency reset + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 200 | 0 | 200 | | + # --- Backdated repayment --- + When Admin sets the business date to "04 May 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "01 March 2026" with 100.0 transaction amount on Working Capital loan + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 200 | 0 | 200 | false | + | 5 | 01 May 2026 | 30 May 2026 | 200 | 0 | 200 | | + And WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 15 April 2026 | | | | | | +# --- Close loan --- + Then Admin closes the Working Capital loan with a full repayment on "04 May 2026" + And Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C89745 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC5: overpaid and overdue + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates WC Delinquency Bucket with frequency 30 DAYS and minimumPayment 25 PERCENTAGE + And Admin creates a new Working Capital Loan Product with delinquency bucket + And Admin creates a working capital loan using created product with the following data: + | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | 01 January 2026 | 01 January 2026 | 800 | 10000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "800" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "800" EUR transaction amount +# --- Repayments --- + When Admin sets the business date to "15 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 January 2026" with 300.0 transaction amount on Working Capital loan + When Admin sets the business date to "15 February 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 February 2026" with 50.0 transaction amount on Working Capital loan + When Admin sets the business date to "03 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId +# --- Delinquency reset --- + When Admin sets the business date to "15 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin creates a Working Capital delinquency reset + When Admin sets the business date to "04 May 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 200 | 0 | 200 | false | + | 5 | 01 May 2026 | 30 May 2026 | 200 | 0 | 200 | | + And WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 15 April 2026 | | | | | | + # --- Close loan --- + Then Admin closes the Working Capital loan with a full repayment on "04 May 2026" + And Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C89746 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC6: backdated payment + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates WC Delinquency Bucket with frequency 30 DAYS and minimumPayment 25 PERCENTAGE + And Admin creates a new Working Capital Loan Product with delinquency bucket + And Admin creates a working capital loan using created product with the following data: + | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | 01 January 2026 | 01 January 2026 | 800 | 10000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "800" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "800" EUR transaction amount + # --- Repayments --- + When Admin sets the business date to "15 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 January 2026" with 200.0 transaction amount on Working Capital loan + When Admin sets the business date to "15 February 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 February 2026" with 100.0 transaction amount on Working Capital loan + When Admin sets the business date to "03 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + # --- Backdated repayment --- + When Admin sets the business date to "15 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "02 January 2026" with 100.0 transaction amount on Working Capital loan +# --- Delinquency reset --- + And Admin creates a Working Capital delinquency reset + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | 200 | 0 | 200 | | + And WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 15 April 2026 | | | | | | + # --- Close loan --- + Then Admin closes the Working Capital loan with a full repayment on "15 April 2026" + And Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C89747 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC7: multiple delinquency reset + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates WC Delinquency Bucket with frequency 30 DAYS and minimumPayment 25 PERCENTAGE + And Admin creates a new Working Capital Loan Product with delinquency bucket + And Admin creates a working capital loan using created product with the following data: + | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | 01 January 2026 | 01 January 2026 | 800 | 10000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "800" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "800" EUR transaction amount +# --- Repayments --- + When Admin sets the business date to "15 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 January 2026" with 200.0 transaction amount on Working Capital loan + When Admin sets the business date to "15 February 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 February 2026" with 100.0 transaction amount on Working Capital loan + When Admin sets the business date to "03 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId +# --- Delinquency reset --- + When Admin sets the business date to "15 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin creates a Working Capital delinquency reset +# --- Delinquency reset --- + When Admin sets the business date to "04 May 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin creates a Working Capital delinquency reset + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 31 March 2026 | | | | | + | 4 | 01 April 2026 | 30 April 2026 | | | | | + | 5 | 01 May 2026 | 30 May 2026 | 200 | 0 | 200 | | + And WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | RESET | 15 April 2026 | | | | | | + | RESET | 04 May 2026 | | | | | | + # --- Close loan --- + Then Admin closes the Working Capital loan with a full repayment on "04 May 2026" + And Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C89748 + Scenario: Verify Working Capital delinquency reset / delinquency reset undo - UC8: delinquency pause and reset + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates WC Delinquency Bucket with frequency 30 DAYS and minimumPayment 25 PERCENTAGE + And Admin creates a new Working Capital Loan Product with delinquency bucket + And Admin creates a working capital loan using created product with the following data: + | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | 01 January 2026 | 01 January 2026 | 800 | 10000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "800" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "800" EUR transaction amount +# --- Repayments --- + When Admin sets the business date to "15 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 January 2026" with 200.0 transaction amount on Working Capital loan + When Admin sets the business date to "15 February 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Customer makes repayment on "15 February 2026" with 100.0 transaction amount on Working Capital loan + When Admin sets the business date to "03 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId +# --- Delinquency pause --- + When Admin sets the business date to "20 March 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin initiate a Working Capital loan delinquency pause with startDate "20 March 2026" and endDate "29 March 2026" +# --- Delinquency reset --- + When Admin sets the business date to "11 April 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Admin creates a Working Capital delinquency reset + Then WC loan delinquency range schedule has the following periods: + | periodNumber | fromDate | toDate | expectedAmount | paidAmount | outstandingAmount | minPaymentCriteriaMet | + | 1 | 01 January 2026 | 30 January 2026 | | | | | + | 2 | 31 January 2026 | 01 March 2026 | | | | | + | 3 | 02 March 2026 | 10 April 2026 | | | | | + | 4 | 11 April 2026 | 10 May 2026 | 200 | 0 | 200 | | + And WC loan delinquency actions have the following data: + | action | startDate | endDate | minimumPayment | minimumPaymentType | frequency | frequencyType | + | PAUSE | 20 March 2026 | 29 March 2026 | | | | | + | RESET | 11 April 2026 | | | | | | + # --- Close loan --- + Then Admin closes the Working Capital loan with a full repayment on "11 April 2026" + And Working Capital loan status will be "CLOSED_OBLIGATIONS_MET"