From 45c1a1118f5290cd11215b5cf4e591f5fd0c1272 Mon Sep 17 00:00:00 2001 From: Monica Date: Wed, 21 Jan 2026 23:46:21 +0530 Subject: [PATCH 1/2] FINERACT-2048: Make amount/recurrence fields optional for DUES standing instruction type --- .../StandingInstructionDataValidator.java | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java index 552c2fc59e1..822798c8876 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java @@ -132,6 +132,10 @@ public void validateForCreate(final JsonCommand command) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType) .notNull().inMinMaxRange(1, 2); + if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) { + baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull(); + } + final Integer recurrenceType = this.fromApiJsonHelper.extractIntegerNamed(StandingInstructionApiConstants.recurrenceTypeParamName, element, Locale.getDefault()); baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceTypeParamName).value(recurrenceType).notNull() @@ -151,21 +155,26 @@ public void validateForCreate(final JsonCommand command) { if (frequencyType.isMonthly() || frequencyType.isYearly()) { final MonthDay monthDay = this.fromApiJsonHelper .extractMonthDayNamed(StandingInstructionApiConstants.recurrenceOnMonthDayParamName, element); - baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay) - .notNull(); + + if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay) + .notNull(); + } } } final Integer recurrenceInterval = this.fromApiJsonHelper .extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault()); if (isPeriodic) { - baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) - .notNull(); - baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency) - .notNull(); + if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) + .notNull(); + baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency) + .notNull(); + baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) + .integerGreaterThanZero(); + } } - baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) - .integerGreaterThanZero(); final String name = this.fromApiJsonHelper.extractStringNamed(StandingInstructionApiConstants.nameParamName, element); baseDataValidator.reset().parameter(StandingInstructionApiConstants.nameParamName).value(name).notNull(); @@ -230,10 +239,22 @@ public void validateForUpdate(final JsonCommand command) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.validTillParamName).value(validTill).notNull(); } + Integer standingInstructionType = null; + if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.instructionTypeParamName, element)) { + standingInstructionType = this.fromApiJsonHelper.extractIntegerNamed(StandingInstructionApiConstants.instructionTypeParamName, + element, Locale.getDefault()); + baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType) + .notNull().inMinMaxRange(1, 2); + } + if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.amountParamName, element)) { final BigDecimal transferAmount = this.fromApiJsonHelper .extractBigDecimalWithLocaleNamed(StandingInstructionApiConstants.amountParamName, element); baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount(); + + if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) { + baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull(); + } } if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.statusParamName, element)) { @@ -250,13 +271,6 @@ public void validateForUpdate(final JsonCommand command) { .inMinMaxRange(1, 4); } - if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.instructionTypeParamName, element)) { - final Integer standingInstructionType = this.fromApiJsonHelper - .extractIntegerNamed(StandingInstructionApiConstants.instructionTypeParamName, element, Locale.getDefault()); - baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType) - .notNull().inMinMaxRange(1, 2); - } - if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.recurrenceTypeParamName, element)) { final Integer recurrenceType = this.fromApiJsonHelper .extractIntegerNamed(StandingInstructionApiConstants.recurrenceTypeParamName, element, Locale.getDefault()); @@ -274,8 +288,11 @@ public void validateForUpdate(final JsonCommand command) { if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.recurrenceIntervalParamName, element)) { final Integer recurrenceInterval = this.fromApiJsonHelper .extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault()); - baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) - .integerGreaterThanZero(); + + if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) + .integerGreaterThanZero(); + } } if (this.fromApiJsonHelper.parameterExists(StandingInstructionApiConstants.nameParamName, element)) { From 979f939a2711ca0ee715bc03a8a4d35a797474e9 Mon Sep 17 00:00:00 2001 From: Monica Date: Mon, 26 Jan 2026 11:56:04 +0530 Subject: [PATCH 2/2] 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 --- .../StandingInstructionDataValidator.java | 40 ++++++++-- .../StandingInstructionDataValidatorTest.java | 80 +++++++++++++++++++ 2 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 fineract-provider/src/test/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidatorTest.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java index 822798c8876..598883a69e0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/StandingInstructionDataValidator.java @@ -132,7 +132,7 @@ public void validateForCreate(final JsonCommand command) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.instructionTypeParamName).value(standingInstructionType) .notNull().inMinMaxRange(1, 2); - if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) { + if (isAmountRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull(); } @@ -156,7 +156,7 @@ public void validateForCreate(final JsonCommand command) { final MonthDay monthDay = this.fromApiJsonHelper .extractMonthDayNamed(StandingInstructionApiConstants.recurrenceOnMonthDayParamName, element); - if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + if (isRecurrenceRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceOnMonthDayParamName).value(monthDay) .notNull(); } @@ -166,7 +166,7 @@ public void validateForCreate(final JsonCommand command) { final Integer recurrenceInterval = this.fromApiJsonHelper .extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault()); if (isPeriodic) { - if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + if (isRecurrenceRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) .notNull(); baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceFrequencyParamName).value(recurrenceFrequency) @@ -187,7 +187,7 @@ public void validateForCreate(final JsonCommand command) { .inMinMaxRange(1, 1); } - if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) { + if (isAmountRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull(); } @@ -252,7 +252,7 @@ public void validateForUpdate(final JsonCommand command) { .extractBigDecimalWithLocaleNamed(StandingInstructionApiConstants.amountParamName, element); baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).positiveAmount(); - if (standingInstructionType != null && StandingInstructionType.fromInt(standingInstructionType).isFixedAmoutTransfer()) { + if (isAmountRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.amountParamName).value(transferAmount).notNull(); } } @@ -289,7 +289,7 @@ public void validateForUpdate(final JsonCommand command) { final Integer recurrenceInterval = this.fromApiJsonHelper .extractIntegerNamed(StandingInstructionApiConstants.recurrenceIntervalParamName, element, Locale.getDefault()); - if (standingInstructionType == null || !StandingInstructionType.fromInt(standingInstructionType).isDuesAmoutTransfer()) { + if (isRecurrenceRequired(standingInstructionType)) { baseDataValidator.reset().parameter(StandingInstructionApiConstants.recurrenceIntervalParamName).value(recurrenceInterval) .integerGreaterThanZero(); } @@ -308,4 +308,32 @@ private void throwExceptionIfValidationWarningsExist(final List