Skip to content

Commit c45fb3d

Browse files
FINERACT-2455: Working Capital product near breach configuration
1 parent 9efda67 commit c45fb3d

54 files changed

Lines changed: 1684 additions & 67 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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
@@ -162,6 +162,7 @@
162162
import org.apache.fineract.client.feign.services.WorkingCapitalLoanProductsApi;
163163
import org.apache.fineract.client.feign.services.WorkingCapitalLoanTransactionsApi;
164164
import org.apache.fineract.client.feign.services.WorkingCapitalLoansApi;
165+
import org.apache.fineract.client.feign.services.WorkingCapitalNearBreachApi;
165166
import org.apache.fineract.client.feign.services.WorkingDaysApi;
166167

167168
/**
@@ -787,6 +788,10 @@ public WorkingCapitalBreachApi workingCapitalBreaches() {
787788
return create(WorkingCapitalBreachApi.class);
788789
}
789790

791+
public WorkingCapitalNearBreachApi workingCapitalNearBreaches() {
792+
return create(WorkingCapitalNearBreachApi.class);
793+
}
794+
790795
public WorkingDaysApi workingDays() {
791796
return create(WorkingDaysApi.class);
792797
}

fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,30 @@ public CommandWrapperBuilder deleteWorkingCapitalBreach(final Long breachId) {
790790
return this;
791791
}
792792

793+
public CommandWrapperBuilder createWorkingCapitalNearBreach() {
794+
this.actionName = "CREATE";
795+
this.entityName = "WORKINGCAPITALNEARBREACH";
796+
this.entityId = null;
797+
this.href = "/working-capital/near-breach";
798+
return this;
799+
}
800+
801+
public CommandWrapperBuilder updateWorkingCapitalNearBreach(final Long breachId) {
802+
this.actionName = "UPDATE";
803+
this.entityName = "WORKINGCAPITALNEARBREACH";
804+
this.entityId = breachId;
805+
this.href = "/working-capital/near-breach/" + breachId;
806+
return this;
807+
}
808+
809+
public CommandWrapperBuilder deleteWorkingCapitalNearBreach(final Long breachId) {
810+
this.actionName = "DELETE";
811+
this.entityName = "WORKINGCAPITALNEARBREACH";
812+
this.entityId = breachId;
813+
this.href = "/working-capital/near-breach/" + breachId;
814+
return this;
815+
}
816+
793817
public CommandWrapperBuilder createWorkingCapitalLoanApplication() {
794818
this.actionName = ACTION_CREATE;
795819
this.entityName = ENTITY_WORKINGCAPITALLOAN;

fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,11 @@ public static ApiGlobalErrorResponse notImplemented(final String globalisationMe
152152
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage,
153153
final String parameterName, final Object... defaultUserMessageArgs) {
154154
final List<ApiParameterError> errors = new ArrayList<>();
155-
errors.add(ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage, parameterName, defaultUserMessageArgs));
155+
final String developerMessage = "The request caused a data integrity issue to be fired by the database.";
156+
errors.add(ApiParameterError.parameterError(globalisationMessageCode, developerMessage, defaultUserMessage, parameterName,
157+
defaultUserMessageArgs));
156158

157-
return create(SC_FORBIDDEN, globalisationMessageCode, "The request caused a data integrity issue to be fired by the database.",
158-
defaultUserMessage, errors);
159+
return create(SC_FORBIDDEN, globalisationMessageCode, developerMessage, defaultUserMessage, errors);
159160
}
160161

161162
public static ApiGlobalErrorResponse notFound(final String globalisationMessageCode, final String defaultUserMessage,

fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiParameterError.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ public static ApiParameterError resourceIdentifierNotFound(final String globalis
6767
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs, "id", null);
6868
}
6969

70+
public static ApiParameterError parameterError(final String globalisationMessageCode, final String developerMessage,
71+
final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) {
72+
return new ApiParameterError(globalisationMessageCode, developerMessage, defaultUserMessage, defaultUserMessageArgs, parameterName,
73+
null);
74+
}
75+
7076
public static ApiParameterError parameterError(final String globalisationMessageCode, final String defaultUserMessage,
7177
final String parameterName, final Object... defaultUserMessageArgs) {
7278
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs, parameterName, null);
@@ -77,6 +83,29 @@ public static ApiParameterError parameterErrorWithValue(final String globalisati
7783
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs, parameterName, value);
7884
}
7985

86+
private ApiParameterError(final String globalisationMessageCode, final String developerMessage, final String defaultUserMessage,
87+
final Object[] defaultUserMessageArgs, String parameterName, String value) {
88+
this.userMessageGlobalisationCode = globalisationMessageCode;
89+
this.developerMessage = developerMessage;
90+
this.defaultUserMessage = defaultUserMessage;
91+
this.parameterName = parameterName;
92+
this.value = value;
93+
94+
final List<ApiErrorMessageArg> messageArgs = new ArrayList<>();
95+
if (defaultUserMessageArgs != null) {
96+
for (final Object object : defaultUserMessageArgs) {
97+
if (object instanceof LocalDate) {
98+
final DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter();
99+
final String formattedDate = dateFormatter.format((LocalDate) object);
100+
messageArgs.add(ApiErrorMessageArg.from(formattedDate));
101+
} else {
102+
messageArgs.add(ApiErrorMessageArg.from(object));
103+
}
104+
}
105+
}
106+
this.args = messageArgs;
107+
}
108+
80109
private ApiParameterError(final String globalisationMessageCode, final String defaultUserMessage, final Object[] defaultUserMessageArgs,
81110
String parameterName, String value) {
82111
this.userMessageGlobalisationCode = globalisationMessageCode;

fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,31 @@ public DataValidatorBuilder positiveAmount() {
383383
return this;
384384
}
385385

386+
public DataValidatorBuilder percentage() {
387+
if (this.value == null && this.ignoreNullValue) {
388+
return this;
389+
}
390+
391+
if (this.value != null) {
392+
final BigDecimal number = new BigDecimal(this.value.toString());
393+
if (number.compareTo(BigDecimal.ZERO) <= 0) {
394+
String validationErrorCode = "validation.msg." + this.resource + "." + this.parameter + ".not.greater.than.zero";
395+
String defaultEnglishMessage = "The parameter `" + this.parameter + "` must be greater than 0.";
396+
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode, defaultEnglishMessage, this.parameter,
397+
number, 0);
398+
this.dataValidationErrors.add(error);
399+
}
400+
if (number.compareTo(BigDecimal.valueOf(100.0)) > 0) {
401+
String validationErrorCode = "validation.msg." + this.resource + "." + this.parameter + ".greater.than.one.hundred";
402+
String defaultEnglishMessage = "The parameter `" + this.parameter + "` must be not greater than 100.";
403+
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode, defaultEnglishMessage, this.parameter,
404+
number, 0);
405+
this.dataValidationErrors.add(error);
406+
}
407+
}
408+
return this;
409+
}
410+
386411
/*
387412
* should be used with .notNull() before it
388413
*/
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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.infrastructure.core.service;
20+
21+
public final class FrequencyTypeUtil {
22+
23+
private FrequencyTypeUtil() {}
24+
25+
public static int compareFrequencies(final Integer frequency1, final String frequencyType1, final Integer frequency2,
26+
final String frequencyType2) {
27+
if (frequencyType1.equals(frequencyType2)) {
28+
return frequency1.compareTo(frequency2);
29+
}
30+
return frequencyToDays(frequency1, frequencyType1).compareTo(frequencyToDays(frequency2, frequencyType2));
31+
}
32+
33+
private static Integer frequencyToDays(final Integer frequency, final String frequencyType) {
34+
return switch (frequencyType) {
35+
case "DAYS" -> frequency;
36+
case "WEEKS" -> frequency * 7;
37+
case "MONTHS" -> frequency * 30;
38+
case "YEARS" -> frequency * 365;
39+
default -> 0;
40+
};
41+
}
42+
}

fineract-core/src/main/java/org/apache/fineract/portfolio/common/service/Validator.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.apache.fineract.portfolio.common.service;
2020

21+
import java.math.BigDecimal;
2122
import java.util.ArrayList;
2223
import java.util.List;
2324
import java.util.function.Consumer;
@@ -55,4 +56,21 @@ private static List<ApiParameterError> getApiParameterErrors(String resource, Co
5556
baseDataValidator.accept(dataValidatorBuilder);
5657
return dataValidationErrors;
5758
}
59+
60+
public static boolean isChanged(final Object newValue, final Object currentValue) {
61+
if (newValue == null) {
62+
return currentValue != null;
63+
}
64+
return !newValue.equals(currentValue);
65+
}
66+
67+
public static boolean isBigDecimalChanged(final BigDecimal newValue, final BigDecimal currentValue) {
68+
if (newValue == null) {
69+
return currentValue != null;
70+
}
71+
if (currentValue == null) {
72+
return true;
73+
}
74+
return newValue.compareTo(currentValue) != 0;
75+
}
5876
}

fineract-core/src/test/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilderDateFormatTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void validDateTimeFormatPatternShouldRejectInvalidPatterns(final String pattern)
4545
final List<ApiParameterError> errors = new ArrayList<>();
4646
new DataValidatorBuilder(errors).resource(RESOURCE).parameter(PARAMETER).value(pattern).validDateTimeFormatPattern();
4747
assertThat(errors).hasSize(1);
48-
assertThat(errors.get(0).getParameterName()).isEqualTo(PARAMETER);
48+
assertThat(errors.get(0).getParameterName()).isEqualTo(pattern);
4949
assertThat(errors.get(0).getDeveloperMessage()).contains("invalid date/time pattern");
5050
}
5151

fineract-provider/src/main/resources/jpa/static-weaving/module/fineract-provider/persistence.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@
310310
<class>org.apache.fineract.portfolio.workingcapitalloanbreach.domain.WorkingCapitalBreach</class>
311311
<class>org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanTransaction</class>
312312
<class>org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanTransactionAllocation</class>
313+
<class>org.apache.fineract.portfolio.workingcapitalloannearbreach.domain.WorkingCapitalNearBreach</class>
313314
<class>org.apache.fineract.portfolio.workingcapitalloanproduct.domain.WorkingCapitalLoanProduct</class>
314315
<class>org.apache.fineract.portfolio.workingcapitalloanproduct.domain.WorkingCapitalLoanProductConfigurableAttributes</class>
315316
<class>org.apache.fineract.portfolio.workingcapitalloanproduct.domain.WorkingCapitalLoanProductPaymentAllocationRule</class>

fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResourceSwagger.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ private GetWorkingCapitalLoansLoanIdResponse() {}
195195
public BigDecimal discount;
196196
@Schema(description = "Working capital breach)")
197197
public WorkingCapitalLoanProductApiResourceSwagger.GetWorkingCapitalLoanProductsResponse.GetWorkingCapitalLoanBreach breach;
198+
public WorkingCapitalLoanProductApiResourceSwagger.GetWorkingCapitalLoanNearBreach nearBreach;
198199
public WorkingCapitalLoanProductApiResourceSwagger.GetWorkingCapitalLoanProductsResponse.GetDelinquencyBucket delinquencyBucket;
199200
@Schema(example = "3", description = "Number of grace days before delinquency tracking starts")
200201
public Integer delinquencyGraceDays;
@@ -319,6 +320,8 @@ private PostWorkingCapitalLoansRequest() {}
319320
@Schema(example = "1")
320321
public Long breachId;
321322
@Schema(example = "1")
323+
public Long nearBreachId;
324+
@Schema(example = "1")
322325
public Long delinquencyBucketId;
323326
@Schema(example = "3")
324327
public Integer delinquencyGraceDays;
@@ -424,6 +427,8 @@ private PutWorkingCapitalLoansLoanIdRequest() {}
424427
@Schema(example = "1")
425428
public Long breachId;
426429
@Schema(example = "1")
430+
public Long nearBreachId;
431+
@Schema(example = "1")
427432
public Long delinquencyBucketId;
428433
@Schema(example = "3")
429434
public Integer delinquencyGraceDays;

0 commit comments

Comments
 (0)