Skip to content

Commit 58137df

Browse files
committed
FINERACT-2455: working capital delinquency managament range schedule
1 parent 767fb6a commit 58137df

15 files changed

Lines changed: 1044 additions & 2 deletions

File tree

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/FineractFeignClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
import org.apache.fineract.client.feign.services.UserGeneratedDocumentsApi;
155155
import org.apache.fineract.client.feign.services.UsersApi;
156156
import org.apache.fineract.client.feign.services.WorkingCapitalLoanCobCatchUpApi;
157+
import org.apache.fineract.client.feign.services.WorkingCapitalLoanDelinquencyRangeScheduleApi;
157158
import org.apache.fineract.client.feign.services.WorkingCapitalLoanProductsApi;
158159
import org.apache.fineract.client.feign.services.WorkingCapitalLoanTransactionsApi;
159160
import org.apache.fineract.client.feign.services.WorkingCapitalLoansApi;
@@ -754,6 +755,10 @@ public WorkingCapitalLoanCobCatchUpApi workingCapitalLoanCobCatchUpApi() {
754755
return create(WorkingCapitalLoanCobCatchUpApi.class);
755756
}
756757

758+
public WorkingCapitalLoanDelinquencyRangeScheduleApi workingCapitalLoanDelinquencyRangeSchedule() {
759+
return create(WorkingCapitalLoanDelinquencyRangeScheduleApi.class);
760+
}
761+
757762
public WorkingCapitalLoansApi workingCapitalLoans() {
758763
return create(WorkingCapitalLoansApi.class);
759764
}

fineract-e2e-tests-runner/src/test/resources/features/WorkingCapital_COB.feature

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ Feature: Working Capital COB Job
88
Scenario: Verify WC COB job registration, default business step, and scheduler metadata
99
Then Admin checks that configured business jobs contain "WORKING_CAPITAL_LOAN_CLOSE_OF_BUSINESS"
1010
Then Admin verifies configured business steps for "WORKING_CAPITAL_LOAN_CLOSE_OF_BUSINESS" match:
11-
| stepName | order |
12-
| DUMMY_BUSINESS_STEP | 1 |
11+
| stepName | order |
12+
| DUMMY_BUSINESS_STEP | 1 |
13+
| WC_DELINQUENCY_RANGE_SCHEDULE | 2 |
1314
Then Admin verifies scheduler job "WC_COB" has display name "Working Capital Loan COB"
1415
Then Admin verifies scheduler job "WC_COB" has active status "false"
1516

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.cob.workingcapitalloan.businessstep;
20+
21+
import java.time.LocalDate;
22+
import java.util.Objects;
23+
import lombok.RequiredArgsConstructor;
24+
import lombok.extern.slf4j.Slf4j;
25+
import org.apache.fineract.infrastructure.core.service.DateUtils;
26+
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoan;
27+
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDisbursementDetails;
28+
import org.apache.fineract.portfolio.workingcapitalloan.service.WorkingCapitalLoanDelinquencyRangeScheduleService;
29+
import org.springframework.stereotype.Component;
30+
31+
@Slf4j
32+
@RequiredArgsConstructor
33+
@Component
34+
public class DelinquencyRangeScheduleBusinessStep extends WorkingCapitalLoanCOBBusinessStep {
35+
36+
private final WorkingCapitalLoanDelinquencyRangeScheduleService rangeScheduleService;
37+
38+
@Override
39+
public WorkingCapitalLoan execute(WorkingCapitalLoan input) {
40+
boolean isDisbursed = input.getDisbursementDetails().stream().map(WorkingCapitalLoanDisbursementDetails::getActualDisbursementDate)
41+
.anyMatch(Objects::nonNull);
42+
if (!isDisbursed) {
43+
log.debug("Skipping delinquency range schedule for WC loan {} - not yet disbursed", input.getId());
44+
return input;
45+
}
46+
47+
LocalDate businessDate = DateUtils.getBusinessLocalDate();
48+
49+
if (!rangeScheduleService.hasSchedule(input.getId())) {
50+
rangeScheduleService.generateInitialPeriod(input);
51+
}
52+
53+
rangeScheduleService.generateNextPeriodIfNeeded(input, businessDate);
54+
rangeScheduleService.evaluateExpiredPeriods(input, businessDate);
55+
56+
return input;
57+
}
58+
59+
@Override
60+
public String getEnumStyledName() {
61+
return "WC_DELINQUENCY_RANGE_SCHEDULE";
62+
}
63+
64+
@Override
65+
public String getHumanReadableName() {
66+
return "WC Delinquency Range Schedule";
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.workingcapitalloan.api;
20+
21+
import io.swagger.v3.oas.annotations.Operation;
22+
import io.swagger.v3.oas.annotations.Parameter;
23+
import io.swagger.v3.oas.annotations.media.ArraySchema;
24+
import io.swagger.v3.oas.annotations.media.Content;
25+
import io.swagger.v3.oas.annotations.media.Schema;
26+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
27+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
28+
import io.swagger.v3.oas.annotations.tags.Tag;
29+
import jakarta.ws.rs.Consumes;
30+
import jakarta.ws.rs.GET;
31+
import jakarta.ws.rs.Path;
32+
import jakarta.ws.rs.PathParam;
33+
import jakarta.ws.rs.Produces;
34+
import jakarta.ws.rs.core.MediaType;
35+
import java.util.List;
36+
import lombok.RequiredArgsConstructor;
37+
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
38+
import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanDelinquencyRangeScheduleData;
39+
import org.apache.fineract.portfolio.workingcapitalloan.service.WorkingCapitalLoanDelinquencyRangeScheduleService;
40+
import org.springframework.stereotype.Component;
41+
42+
@Path("/v1/working-capital-loans/{loanId}/delinquency-range-schedule")
43+
@Component
44+
@Tag(name = "Working Capital Loan Delinquency Range Schedule", description = "Manages delinquency range schedule periods for Working Capital loans")
45+
@RequiredArgsConstructor
46+
public class WorkingCapitalLoanDelinquencyRangeScheduleApiResource {
47+
48+
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "WORKINGCAPITALLOAN";
49+
50+
private final PlatformSecurityContext context;
51+
private final WorkingCapitalLoanDelinquencyRangeScheduleService rangeScheduleService;
52+
53+
@GET
54+
@Consumes({ MediaType.APPLICATION_JSON })
55+
@Produces({ MediaType.APPLICATION_JSON })
56+
@Operation(summary = "Retrieve Delinquency Range Schedule", description = "Retrieves the delinquency range schedule periods for a Working Capital loan")
57+
@ApiResponses({
58+
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = WorkingCapitalLoanDelinquencyRangeScheduleData.class)))) })
59+
public List<WorkingCapitalLoanDelinquencyRangeScheduleData> retrieveDelinquencyRangeSchedule(
60+
@PathParam("loanId") @Parameter(description = "loanId") final Long loanId) {
61+
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
62+
return rangeScheduleService.retrieveRangeSchedule(loanId);
63+
}
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.workingcapitalloan.data;
20+
21+
import java.math.BigDecimal;
22+
import java.time.LocalDate;
23+
import lombok.AllArgsConstructor;
24+
import lombok.Getter;
25+
import lombok.Setter;
26+
27+
@AllArgsConstructor
28+
@Getter
29+
@Setter
30+
public class WorkingCapitalLoanDelinquencyRangeScheduleData {
31+
32+
private Long id;
33+
private Long loanId;
34+
private Integer periodNumber;
35+
private LocalDate fromDate;
36+
private LocalDate toDate;
37+
private BigDecimal expectedAmount;
38+
private BigDecimal paidAmount;
39+
private BigDecimal outstandingAmount;
40+
private Boolean minPaymentCriteriaMet;
41+
private Long delinquentDays;
42+
private BigDecimal delinquentAmount;
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.workingcapitalloan.domain;
20+
21+
import jakarta.persistence.Column;
22+
import jakarta.persistence.Entity;
23+
import jakarta.persistence.FetchType;
24+
import jakarta.persistence.JoinColumn;
25+
import jakarta.persistence.ManyToOne;
26+
import jakarta.persistence.Table;
27+
import jakarta.persistence.UniqueConstraint;
28+
import java.math.BigDecimal;
29+
import java.time.LocalDate;
30+
import lombok.Getter;
31+
import lombok.NoArgsConstructor;
32+
import lombok.Setter;
33+
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
34+
35+
@Getter
36+
@Setter
37+
@NoArgsConstructor
38+
@Entity
39+
@Table(name = "m_wc_loan_delinquency_range_schedule", uniqueConstraints = {
40+
@UniqueConstraint(columnNames = { "wc_loan_id", "period_number" }, name = "uc_wc_delinquency_range_schedule_loan_period") })
41+
public class WorkingCapitalLoanDelinquencyRangeSchedule extends AbstractAuditableWithUTCDateTimeCustom<Long> {
42+
43+
@ManyToOne(fetch = FetchType.LAZY)
44+
@JoinColumn(name = "wc_loan_id", nullable = false)
45+
private WorkingCapitalLoan loan;
46+
47+
@Column(name = "period_number", nullable = false)
48+
private Integer periodNumber;
49+
50+
@Column(name = "from_date", nullable = false)
51+
private LocalDate fromDate;
52+
53+
@Column(name = "to_date", nullable = false)
54+
private LocalDate toDate;
55+
56+
@Column(name = "expected_amount", scale = 6, precision = 19)
57+
private BigDecimal expectedAmount;
58+
59+
@Column(name = "paid_amount", scale = 6, precision = 19)
60+
private BigDecimal paidAmount;
61+
62+
@Column(name = "outstanding_amount", scale = 6, precision = 19)
63+
private BigDecimal outstandingAmount;
64+
65+
@Column(name = "min_payment_criteria_met")
66+
private Boolean minPaymentCriteriaMet;
67+
68+
@Column(name = "delinquent_days")
69+
private Long delinquentDays;
70+
71+
@Column(name = "delinquent_amount", scale = 6, precision = 19)
72+
private BigDecimal delinquentAmount;
73+
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.workingcapitalloan.mapper;
20+
21+
import java.util.List;
22+
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
23+
import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanDelinquencyRangeScheduleData;
24+
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyRangeSchedule;
25+
import org.mapstruct.Mapper;
26+
import org.mapstruct.Mapping;
27+
28+
@Mapper(config = MapstructMapperConfig.class)
29+
public interface WorkingCapitalLoanDelinquencyRangeScheduleMapper {
30+
31+
@Mapping(target = "loanId", source = "loan.id")
32+
WorkingCapitalLoanDelinquencyRangeScheduleData toData(WorkingCapitalLoanDelinquencyRangeSchedule entity);
33+
34+
List<WorkingCapitalLoanDelinquencyRangeScheduleData> toDataList(List<WorkingCapitalLoanDelinquencyRangeSchedule> entities);
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.workingcapitalloan.repository;
20+
21+
import java.time.LocalDate;
22+
import java.util.List;
23+
import java.util.Optional;
24+
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyRangeSchedule;
25+
import org.springframework.data.jpa.repository.JpaRepository;
26+
27+
public interface WorkingCapitalLoanDelinquencyRangeScheduleRepository
28+
extends JpaRepository<WorkingCapitalLoanDelinquencyRangeSchedule, Long> {
29+
30+
List<WorkingCapitalLoanDelinquencyRangeSchedule> findByLoanIdOrderByPeriodNumberAsc(Long loanId);
31+
32+
Optional<WorkingCapitalLoanDelinquencyRangeSchedule> findTopByLoanIdOrderByPeriodNumberDesc(Long loanId);
33+
34+
Optional<WorkingCapitalLoanDelinquencyRangeSchedule> findByLoanIdAndFromDateLessThanEqualAndToDateGreaterThanEqual(Long loanId,
35+
LocalDate date, LocalDate date2);
36+
37+
List<WorkingCapitalLoanDelinquencyRangeSchedule> findByLoanIdAndToDateLessThanEqualAndMinPaymentCriteriaMetIsNull(Long loanId,
38+
LocalDate businessDate);
39+
40+
}

0 commit comments

Comments
 (0)