Skip to content

Commit 3f429b2

Browse files
FINERACT-2048: Fix StandingInstructionDataValidatorTest and DUES validation
1 parent a98c143 commit 3f429b2

File tree

2 files changed

+505
-24
lines changed

2 files changed

+505
-24
lines changed

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

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,10 @@ public void validateForCreate(final JsonCommand command) {
117117

118118
final BigDecimal transferAmount = this.fromApiJsonHelper
119119
.extractBigDecimalWithLocaleNamed(StandingInstructionApiConstants.amountParamName, element);
120-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount();
120+
121+
if (transferAmount != null) {
122+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount();
123+
}
121124

122125
final Integer transferType = this.fromApiJsonHelper.extractIntegerNamed(transferTypeParamName, element, Locale.getDefault());
123126
baseDataValidator.reset().parameter(transferTypeParamName).value(transferType).notNull().inMinMaxRange(1, 3);
@@ -132,40 +135,56 @@ public void validateForCreate(final JsonCommand command) {
132135
baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType)
133136
.notNull().inMinMaxRange(1, 2);
134137

138+
if (isAmountRequired(standingInstructionType)) {
139+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
140+
}
141+
135142
final Integer recurrenceType = this.fromApiJsonHelper.extractIntegerNamed(StandingInstructionApiConstants.recurrenceTypeParamName,
136143
element, Locale.getDefault());
137-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceTypeParamName).value(recurrenceType).notNull()
138-
.inMinMaxRange(1, 2);
144+
145+
if (isRecurrenceRequired(standingInstructionType)) {
146+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceTypeParamName).value(recurrenceType).notNull()
147+
.inMinMaxRange(1, 2);
148+
}
149+
139150
boolean isPeriodic = false;
140151
if (recurrenceType != null) {
141152
isPeriodic = AccountTransferRecurrenceType.fromInt(recurrenceType).isPeriodicRecurrence();
142153
}
143154

144155
final Integer recurrenceFrequency = this.fromApiJsonHelper
145156
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceFrequencyParamName, element, Locale.getDefault());
146-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency)
147-
.inMinMaxRange(0, 3);
157+
158+
if (isRecurrenceRequired(standingInstructionType)) {
159+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency)
160+
.inMinMaxRange(1, 3);
161+
}
148162

149163
if (recurrenceFrequency != null) {
150164
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(recurrenceFrequency);
151-
if (frequencyType.isMonthly() || frequencyType.isYearly()) {
165+
if (frequencyType != null && (frequencyType.isMonthly() || frequencyType.isYearly())) {
152166
final MonthDay monthDay = this.fromApiJsonHelper
153167
.extractMonthDayNamed(StandingInstructionApiConstants.recurrenceOnMonthDayParamName, element);
154-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay)
155-
.notNull();
168+
169+
if (isRecurrenceRequired(standingInstructionType)) {
170+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay)
171+
.notNull();
172+
}
156173
}
157174
}
158175

159176
final Integer recurrenceInterval = this.fromApiJsonHelper
160177
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault());
161178
if (isPeriodic) {
162-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
163-
.notNull();
164-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency)
165-
.notNull();
179+
if (isRecurrenceRequired(standingInstructionType)) {
180+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
181+
.notNull();
182+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency)
183+
.notNull();
184+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
185+
.integerGreaterThanZero();
186+
}
166187
}
167-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
168-
.integerGreaterThanZero();
169188

170189
final String name = this.fromApiJsonHelper.extractStringNamed(StandingInstructionApiConstants.nameParamName, element);
171190
baseDataValidator.reset().parameter(StandingInstructionApiConstants.nameParamName).value(name).notNull();
@@ -178,7 +197,7 @@ public void validateForCreate(final JsonCommand command) {
178197
.inMinMaxRange(1, 1);
179198

180199
}
181-
if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) {
200+
if (isAmountRequired(standingInstructionType)) {
182201
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
183202
}
184203

@@ -230,10 +249,22 @@ public void validateForUpdate(final JsonCommand command) {
230249
baseDataValidator.reset().parameter(StandingInstructionApiConstants.validTillParamName).value(validTill).notNull();
231250
}
232251

252+
Integer standingInstructionType = null;
253+
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.instructionTypeParamName, element)) {
254+
standingInstructionType = this.fromApiJsonHelper.extractIntegerNamed(StandingInstructionApiConstants.instructionTypeParamName,
255+
element, Locale.getDefault());
256+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType)
257+
.notNull().inMinMaxRange(1, 2);
258+
}
259+
233260
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.amountParamName, element)) {
234261
final BigDecimal transferAmount = this.fromApiJsonHelper
235262
.extractBigDecimalWithLocaleNamed(StandingInstructionApiConstants.amountParamName, element);
236263
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount();
264+
265+
if (isAmountRequired(standingInstructionType)) {
266+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull();
267+
}
237268
}
238269

239270
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.statusParamName, element)) {
@@ -250,13 +281,6 @@ public void validateForUpdate(final JsonCommand command) {
250281
.inMinMaxRange(1, 4);
251282
}
252283

253-
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.instructionTypeParamName, element)) {
254-
final Integer standingInstructionType = this.fromApiJsonHelper
255-
.extractIntegerNamed(StandingInstructionApiConstants.instructionTypeParamName, element, Locale.getDefault());
256-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType)
257-
.notNull().inMinMaxRange(1, 2);
258-
}
259-
260284
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.recurrenceTypeParamName, element)) {
261285
final Integer recurrenceType = this.fromApiJsonHelper
262286
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceTypeParamName, element, Locale.getDefault());
@@ -274,8 +298,11 @@ public void validateForUpdate(final JsonCommand command) {
274298
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.recurrenceIntervalParamName, element)) {
275299
final Integer recurrenceInterval = this.fromApiJsonHelper
276300
.extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault());
277-
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
278-
.integerGreaterThanZero();
301+
302+
if (isRecurrenceRequired(standingInstructionType)) {
303+
baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval)
304+
.integerGreaterThanZero();
305+
}
279306
}
280307

281308
if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.nameParamName, element)) {
@@ -291,4 +318,40 @@ private void throwExceptionIfValidationWarningsExist(final List<ApiParameterErro
291318
throw new PlatformApiDataValidationException(dataValidationErrors);
292319
}
293320
}
321+
322+
// ============================================
323+
// PRIVATE HELPER METHODS
324+
// ============================================
325+
326+
/**
327+
* Determines if the standing instruction type requires amount validation. Amount is required only for
328+
* FIXED_AMOUNT_TRANSFER type. For DUES type, amount is calculated based on outstanding dues.
329+
*
330+
* @param standingInstructionType
331+
* the instruction type code
332+
* @return true if amount validation is required, false otherwise
333+
*/
334+
private boolean isAmountRequired(Integer standingInstructionType) {
335+
if (standingInstructionType == null) {
336+
return false;
337+
}
338+
StandingInstructionType type = StandingInstructionType.fromInt(standingInstructionType);
339+
return type != null && type.isFixedAmoutTransfer();
340+
}
341+
342+
/**
343+
* Determines if recurrence fields should be validated. Recurrence is required for all types except DUES. DUES
344+
* instructions are processed based on loan due dates, not recurrence pattern.
345+
*
346+
* @param standingInstructionType
347+
* the instruction type code
348+
* @return true if recurrence validation is required, false otherwise
349+
*/
350+
private boolean isRecurrenceRequired(Integer standingInstructionType) {
351+
if (standingInstructionType == null) {
352+
return true;
353+
}
354+
StandingInstructionType type = StandingInstructionType.fromInt(standingInstructionType);
355+
return type != null && !type.isDuesAmoutTransfer();
356+
}
294357
}

0 commit comments

Comments
 (0)