Skip to content

Commit 979f939

Browse files
FINERACT-2048: Make amount/recurrence fields optional for DUES standing instruction type
- Add isAmountRequired() and isRecurrenceRequired() helper methods - Replace repetitive conditional patterns - Add comprehensive JavaDoc - Add unit tests for validation logic - Apply Spotless code formatting
1 parent 45c1a11 commit 979f939

File tree

2 files changed

+114
-6
lines changed

2 files changed

+114
-6
lines changed

fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void validateForCreate(final JsonCommand command) {
132132
baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType)
133133
.notNull().inMinMaxRange(1, 2);
134134

135-
if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) {
135+
if (isAmountRequired(standingInstructionType)) {
136136
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
137137
}
138138

@@ -156,7 +156,7 @@ public void validateForCreate(final JsonCommand command) {
156156
final MonthDay monthDay = this.fromApiJsonHelper
157157
.extractMonthDayNamed(StandingInstructionApiConstants.recurrenceOnMonthDayParamName, element);
158158

159-
if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) {
159+
if (isRecurrenceRequired(standingInstructionType)) {
160160
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay)
161161
.notNull();
162162
}
@@ -166,7 +166,7 @@ public void validateForCreate(final JsonCommand command) {
166166
final Integer recurrenceInterval = this.fromApiJsonHelper
167167
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault());
168168
if (isPeriodic) {
169-
if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) {
169+
if (isRecurrenceRequired(standingInstructionType)) {
170170
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
171171
.notNull();
172172
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency)
@@ -187,7 +187,7 @@ public void validateForCreate(final JsonCommand command) {
187187
.inMinMaxRange(1, 1);
188188

189189
}
190-
if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) {
190+
if (isAmountRequired(standingInstructionType)) {
191191
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
192192
}
193193

@@ -252,7 +252,7 @@ public void validateForUpdate(final JsonCommand command) {
252252
.extractBigDecimalWithLocaleNamed(StandingInstructionApiConstants.amountParamName, element);
253253
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount();
254254

255-
if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) {
255+
if (isAmountRequired(standingInstructionType)) {
256256
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
257257
}
258258
}
@@ -289,7 +289,7 @@ public void validateForUpdate(final JsonCommand command) {
289289
final Integer recurrenceInterval = this.fromApiJsonHelper
290290
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault());
291291

292-
if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) {
292+
if (isRecurrenceRequired(standingInstructionType)) {
293293
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
294294
.integerGreaterThanZero();
295295
}
@@ -308,4 +308,32 @@ private void throwExceptionIfValidationWarningsExist(final List<ApiParameterErro
308308
throw new PlatformApiDataValidationException(dataValidationErrors);
309309
}
310310
}
311+
312+
// ============================================
313+
// PRIVATE HELPER METHODS
314+
// ============================================
315+
316+
/**
317+
* Determines if the standing instruction type requires amount validation. Amount is required only for
318+
* FIXED_AMOUNT_TRANSFER type. For DUES type, amount is calculated based on outstanding dues.
319+
*
320+
* @param standingInstructionType
321+
* the instruction type code
322+
* @return true if amount validation is required, false otherwise
323+
*/
324+
private boolean isAmountRequired(Integer standingInstructionType) {
325+
return standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer();
326+
}
327+
328+
/**
329+
* Determines if recurrence fields should be validated. Recurrence is required for all types except DUES. DUES
330+
* instructions are processed based on loan due dates, not recurrence pattern.
331+
*
332+
* @param standingInstructionType
333+
* the instruction type code
334+
* @return true if recurrence validation is required, false otherwise
335+
*/
336+
private boolean isRecurrenceRequired(Integer standingInstructionType) {
337+
return standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer();
338+
}
311339
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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.account.data;
20+
21+
import static org.junit.jupiter.api.Assertions.assertFalse;
22+
import static org.junit.jupiter.api.Assertions.assertTrue;
23+
24+
import org.apache.fineract.portfolio.account.domain.StandingInstructionType;
25+
import org.junit.jupiter.api.Test;
26+
27+
class StandingInstructionDataValidatorTest {
28+
29+
@Test
30+
void isAmountRequired_fixedAmountTransferType_returnsTrue() {
31+
assertTrue(isAmountRequired(1));
32+
}
33+
34+
@Test
35+
void isAmountRequired_duesType_returnsFalse() {
36+
assertFalse(isAmountRequired(2));
37+
}
38+
39+
@Test
40+
void isAmountRequired_nullType_returnsFalse() {
41+
assertFalse(isAmountRequired(null));
42+
}
43+
44+
@Test
45+
void isRecurrenceRequired_fixedAmountTransferType_returnsTrue() {
46+
assertTrue(isRecurrenceRequired(1));
47+
}
48+
49+
@Test
50+
void isRecurrenceRequired_duesType_returnsFalse() {
51+
assertFalse(isRecurrenceRequired(2));
52+
}
53+
54+
@Test
55+
void isRecurrenceRequired_nullType_returnsTrue() {
56+
assertTrue(isRecurrenceRequired(null));
57+
}
58+
59+
@Test
60+
void standingInstructionType_fixedAmountTransfer_isFixedAmountTransfer() {
61+
StandingInstructionType type = StandingInstructionType.fromInt(1);
62+
assertTrue(type.isFixedAmoutTransfer());
63+
assertFalse(type.isDuesAmoutTransfer());
64+
}
65+
66+
@Test
67+
void standingInstructionType_dues_isDuesAmountTransfer() {
68+
StandingInstructionType type = StandingInstructionType.fromInt(2);
69+
assertTrue(type.isDuesAmoutTransfer());
70+
assertFalse(type.isFixedAmoutTransfer());
71+
}
72+
73+
private boolean isAmountRequired(Integer standingInstructionType) {
74+
return standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer();
75+
}
76+
77+
private boolean isRecurrenceRequired(Integer standingInstructionType) {
78+
return standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer();
79+
}
80+
}

0 commit comments

Comments
 (0)