Skip to content

Commit 408ae23

Browse files
authored
Merge pull request #5740
FINERACT-2455: Working Capital product near breach configuration
2 parents 86a1323 + cf91c5f commit 408ae23

72 files changed

Lines changed: 3704 additions & 191 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
@@ -791,6 +791,30 @@ public CommandWrapperBuilder deleteWorkingCapitalBreach(final Long breachId) {
791791
return this;
792792
}
793793

794+
public CommandWrapperBuilder createWorkingCapitalNearBreach() {
795+
this.actionName = "CREATE";
796+
this.entityName = "WORKINGCAPITALNEARBREACH";
797+
this.entityId = null;
798+
this.href = "/working-capital/near-breach";
799+
return this;
800+
}
801+
802+
public CommandWrapperBuilder updateWorkingCapitalNearBreach(final Long breachId) {
803+
this.actionName = "UPDATE";
804+
this.entityName = "WORKINGCAPITALNEARBREACH";
805+
this.entityId = breachId;
806+
this.href = "/working-capital/near-breach/" + breachId;
807+
return this;
808+
}
809+
810+
public CommandWrapperBuilder deleteWorkingCapitalNearBreach(final Long breachId) {
811+
this.actionName = "DELETE";
812+
this.entityName = "WORKINGCAPITALNEARBREACH";
813+
this.entityId = breachId;
814+
this.href = "/working-capital/near-breach/" + breachId;
815+
return this;
816+
}
817+
794818
public CommandWrapperBuilder createWorkingCapitalLoanApplication() {
795819
this.actionName = ACTION_CREATE;
796820
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-e2e-tests-core/src/test/java/org/apache/fineract/test/data/workingcapitalproduct/DefaultWorkingCapitalLoanProduct.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ public enum DefaultWorkingCapitalLoanProduct implements WorkingCapitalLoanProduc
2424
WCLP_DISCOUNT, //
2525
WCLP_DISALLOW_ATTRIBUTES_OVERRIDE, //
2626
WCLP_DISCOUNT_DISALLOW_ATTRIBUTES_OVERRIDE, //
27-
WCLP_FOR_UPDATE; //
27+
WCLP_FOR_UPDATE, //
28+
WCLP_DELINQUENCY_RESCHEDULE, //
29+
WCLP_BREACH, //
30+
WCLP_BREACH_NEAR_BREACH, //
31+
WCLP_BREACH_DISALLOW_ATTRIBUTES_OVERRIDE, //
32+
WCLP_BREACH_NEAR_BREACH_DISALLOW_ATTRIBUTES_OVERRIDE; //
2833

2934
@Override
3035
public String getName() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
20+
package org.apache.fineract.test.data.workingcapitalproduct;
21+
22+
import lombok.Getter;
23+
import lombok.RequiredArgsConstructor;
24+
25+
@Getter
26+
@RequiredArgsConstructor
27+
public enum WorkingCapitalBreachCalculationType {
28+
29+
FLAT(0L, "FLAT", "Flat"), //
30+
PERCENTAGE(1L, "PERCENTAGE", "Percentage"); //
31+
32+
private final Long id;
33+
private final String code;
34+
private final String value;
35+
}

0 commit comments

Comments
 (0)