You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by al...@apache.org on 2026/02/20 20:39:47 UTC

(fineract) branch develop updated: FINERACT 2289: New command processing - Working Days

This is an automated email from the ASF dual-hosted git repository.

aleks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 701cfae60b FINERACT 2289: New command processing - Working Days
701cfae60b is described below

commit 701cfae60bc70de68e41b9b4345e0c393ec3d19a
Author: yuwatidora <yu...@gmail.com>
AuthorDate: Thu Feb 19 21:17:21 2026 -0500

    FINERACT 2289: New command processing - Working Days
    
    command base test fix
---
 docker-compose-mysql.yml                           | 34 ++++++++++++
 .../workingdays/domain/WorkingDays.java            | 60 ++++-----------------
 .../domain/WorkingDaysEnumerations.java            |  4 +-
 .../infrastructure/core/config/SecurityConfig.java |  7 +++
 .../workingdays/api/WorkingDaysApiResource.java    | 42 +++++++--------
 .../WorkingDaysUpdateCommand.java}                 | 15 +++---
 .../workingdays/data/WorkingDayValidator.java      |  1 +
 .../workingdays/data/WorkingDaysData.java          | 36 +++----------
 .../WorkingDaysUpdateRequest.java}                 | 30 +++++++++--
 .../data/WorkingDaysUpdateRequestValidator.java    | 62 ++++++++++++++++++++++
 .../WorkingDaysUpdateResponse.java}                | 26 +++++++--
 .../handler/UpdateWorkingDaysCommandHandler.java   | 41 ++++++++------
 .../WorkingDaysReadPlatformServiceImpl.java        | 12 +++--
 .../service/WorkingDaysWritePlatformService.java   |  8 +--
 ...gDaysWritePlatformServiceJpaRepositoryImpl.java | 53 +++++++++++++-----
 .../OrganisationWorkingDaysConfiguration.java      |  6 +--
 16 files changed, 277 insertions(+), 160 deletions(-)

diff --git a/docker-compose-mysql.yml b/docker-compose-mysql.yml
new file mode 100644
index 0000000000..5f0521724a
--- /dev/null
+++ b/docker-compose-mysql.yml
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+services:
+  mysql:
+    container_name: mysql
+    image: mysql:8
+    volumes:
+      - ${PWD}/config/docker/mysql/conf.d/server_collation.cnf:/etc/mysql/conf.d/server_collation.cnf:ro
+      - ${PWD}/config/docker/mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:Z,ro
+    restart: always
+    env_file:
+      - ${PWD}/config/docker/env/mysql.env
+    healthcheck:
+      test: [ "CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized" ]
+      timeout: 10s
+      retries: 10
+    ports:
+      - "3306:3306"
diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDays.java b/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDays.java
index 8fbe7125b5..b55b591c73 100644
--- a/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDays.java
+++ b/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDays.java
@@ -21,16 +21,21 @@ package org.apache.fineract.organisation.workingdays.domain;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.Table;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import lombok.experimental.FieldNameConstants;
 import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
-import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants;
 
+@Builder
 @Getter
+@Setter
 @Entity
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
 @Table(name = "m_working_days")
 public class WorkingDays extends AbstractPersistableCustom<Long> {
 
@@ -47,51 +52,4 @@ public class WorkingDays extends AbstractPersistableCustom<Long> {
     @Column(name = "extend_term_holiday_repayment", nullable = false)
     private Boolean extendTermForRepaymentsOnHolidays;
 
-    protected WorkingDays() {
-
-    }
-
-    public WorkingDays(final String recurrence, final Integer repaymentReschedulingType, final Boolean extendTermForDailyRepayments,
-            final Boolean extendTermForRepaymentsOnHolidays) {
-        this.recurrence = recurrence;
-        this.repaymentReschedulingType = repaymentReschedulingType;
-        this.extendTermForDailyRepayments = extendTermForDailyRepayments;
-        this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
-    }
-
-    public Map<String, Object> update(final JsonCommand command) {
-        final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
-
-        final String recurrenceParamName = "recurrence";
-        if (command.isChangeInStringParameterNamed(recurrenceParamName, this.recurrence)) {
-            final String newValue = command.stringValueOfParameterNamed(recurrenceParamName);
-            actualChanges.put(recurrenceParamName, newValue);
-            this.recurrence = newValue;
-        }
-
-        final String repaymentRescheduleTypeParamName = "repaymentRescheduleType";
-        if (command.isChangeInIntegerParameterNamed(repaymentRescheduleTypeParamName, this.repaymentReschedulingType)) {
-            final Integer newValue = command.integerValueOfParameterNamed(repaymentRescheduleTypeParamName);
-            actualChanges.put(repaymentRescheduleTypeParamName, WorkingDaysEnumerations.workingDaysStatusType(newValue));
-            this.repaymentReschedulingType = RepaymentRescheduleType.fromInt(newValue).getValue();
-        }
-
-        if (command.isChangeInBooleanParameterNamed(WorkingDaysApiConstants.extendTermForDailyRepayments,
-                this.extendTermForDailyRepayments)) {
-            final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(WorkingDaysApiConstants.extendTermForDailyRepayments);
-            actualChanges.put(WorkingDaysApiConstants.extendTermForDailyRepayments, newValue);
-            this.extendTermForDailyRepayments = newValue;
-        }
-
-        if (command.isChangeInBooleanParameterNamed(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays,
-                this.extendTermForRepaymentsOnHolidays)) {
-            final Boolean newValue = command
-                    .booleanPrimitiveValueOfParameterNamed(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays);
-            actualChanges.put(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays, newValue);
-            this.extendTermForRepaymentsOnHolidays = newValue;
-        }
-
-        return actualChanges;
-    }
-
 }
diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDaysEnumerations.java b/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDaysEnumerations.java
index e3f9606285..c2caf64484 100644
--- a/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDaysEnumerations.java
+++ b/fineract-core/src/main/java/org/apache/fineract/organisation/workingdays/domain/WorkingDaysEnumerations.java
@@ -41,8 +41,8 @@ public final class WorkingDaysEnumerations {
             case SAME_DAY:
                 optionData = new EnumOptionData(RepaymentRescheduleType.SAME_DAY.getValue().longValue(),
                         RepaymentRescheduleType.SAME_DAY.getCode(), "same day");
-
             break;
+
             case MOVE_TO_NEXT_WORKING_DAY:
                 optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getValue().longValue(),
                         RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getCode(), "move to next working day");
@@ -52,10 +52,12 @@ public final class WorkingDaysEnumerations {
                 optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY.getValue().longValue(),
                         RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY.getCode(), "move to next repayment meeting day");
             break;
+
             case MOVE_TO_PREVIOUS_WORKING_DAY:
                 optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY.getValue().longValue(),
                         RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY.getCode(), "move to previous working day");
             break;
+
             case MOVE_TO_NEXT_MEETING_DAY:
                 optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_NEXT_MEETING_DAY.getValue().longValue(),
                         RepaymentRescheduleType.MOVE_TO_NEXT_MEETING_DAY.getCode(), "move to next meeting day");
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index 6168cfc631..2aa14cb57e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -328,6 +328,13 @@ public class SecurityConfig {
                     .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_MIX_REPORT")
                     .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/mixreport/*"))
                     .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_MIX_REPORT")
+                    // working days
+                    .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/workingdays"))
+                    .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_WORKING_DAYS")
+                    .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/workingdays/template"))
+                    .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_WORKING_DAYS")
+                    .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/workingdays"))
+                    .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_WORKING_DAYS")
 
                     .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated()
                     .requestMatchers(API_MATCHER.matcher("/api/*/twofactor")).fullyAuthenticated()
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/api/WorkingDaysApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/api/WorkingDaysApiResource.java
index 1ec2298d25..d58dd0bfa9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/api/WorkingDaysApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/api/WorkingDaysApiResource.java
@@ -19,26 +19,23 @@
 package org.apache.fineract.organisation.workingdays.api;
 
 import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.PUT;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.core.MediaType;
+import java.time.Instant;
+import java.util.function.Supplier;
 import lombok.RequiredArgsConstructor;
-import org.apache.fineract.commands.domain.CommandWrapper;
-import org.apache.fineract.commands.service.CommandWrapperBuilder;
-import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
-import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.command.core.CommandPipeline;
+import org.apache.fineract.organisation.workingdays.command.WorkingDaysUpdateCommand;
 import org.apache.fineract.organisation.workingdays.data.WorkingDaysData;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequest;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequestValidator;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateResponse;
 import org.apache.fineract.organisation.workingdays.service.WorkingDaysReadPlatformService;
 import org.springframework.stereotype.Component;
 
@@ -51,17 +48,15 @@ import org.springframework.stereotype.Component;
 @RequiredArgsConstructor
 public class WorkingDaysApiResource {
 
-    private final DefaultToApiJsonSerializer<WorkingDaysData> toApiJsonSerializer;
     private final WorkingDaysReadPlatformService workingDaysReadPlatformService;
-    private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
-    private final PlatformSecurityContext context;
+    private final WorkingDaysUpdateRequestValidator workingDaysUpdateRequestValidator;
+    private final CommandPipeline commandPipeline;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_JSON })
     @Operation(summary = "List Working days", description = "Example Requests:\n" + "\n" + "workingdays")
     public WorkingDaysData retrieveAll() {
-        this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
         return this.workingDaysReadPlatformService.retrieve();
     }
 
@@ -70,15 +65,17 @@ public class WorkingDaysApiResource {
     @Produces({ MediaType.APPLICATION_JSON })
     @Operation(summary = "Update a Working Day", description = "Mandatory Fields\n"
             + "recurrence,repaymentRescheduleType,extendTermForDailyRepayments,locale")
-    @RequestBody(required = true, content = @Content(schema = @Schema(implementation = WorkingDaysApiResourceSwagger.PutWorkingDaysRequest.class)))
-    @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = WorkingDaysApiResourceSwagger.PutWorkingDaysResponse.class)))
-    public String update(@Parameter(hidden = true) final String jsonRequestBody) {
+    public WorkingDaysUpdateResponse update(@Valid WorkingDaysUpdateRequest request) {
 
-        final CommandWrapper commandRequest = new CommandWrapperBuilder().updateWorkingDays().withJson(jsonRequestBody).build();
+        final var command = new WorkingDaysUpdateCommand();
 
-        final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        command.setCommandId(System.currentTimeMillis());
+        command.setCreatedAt(Instant.now());
+        command.setPayload(request);
 
-        return this.toApiJsonSerializer.serialize(result);
+        final Supplier<WorkingDaysUpdateResponse> response = commandPipeline.send(command);
+
+        return response.get();
     }
 
     @GET
@@ -87,10 +84,7 @@ public class WorkingDaysApiResource {
     @Produces({ MediaType.APPLICATION_JSON })
     @Operation(summary = "Working Days Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for working days.\n"
             + "\n" + "Example Request:\n" + "\n" + "workingdays/template")
-    @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = WorkingDaysApiResourceSwagger.GetWorkingDaysTemplateResponse.class)))
     public WorkingDaysData template() {
-        this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
-
         return this.workingDaysReadPlatformService.repaymentRescheduleType();
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/command/WorkingDaysUpdateCommand.java
old mode 100755
new mode 100644
similarity index 68%
copy from fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
copy to fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/command/WorkingDaysUpdateCommand.java
index dcdb3d1e40..d9fb669316
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/command/WorkingDaysUpdateCommand.java
@@ -16,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.organisation.workingdays.service;
+package org.apache.fineract.organisation.workingdays.command;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequest;
 
-public interface WorkingDaysWritePlatformService {
-
-    CommandProcessingResult updateWorkingDays(JsonCommand command);
-}
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WorkingDaysUpdateCommand extends Command<WorkingDaysUpdateRequest> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDayValidator.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDayValidator.java
index 8c3e365c18..97416f3806 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDayValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDayValidator.java
@@ -37,6 +37,7 @@ import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+//Not used
 @Component
 public class WorkingDayValidator {
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysData.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysData.java
index ef2e62ab7b..24d778779e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysData.java
@@ -21,12 +21,18 @@ package org.apache.fineract.organisation.workingdays.data;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Collection;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import lombok.experimental.FieldNameConstants;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 
+@Builder
 @Data
 @NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
 public class WorkingDaysData implements Serializable {
 
     @Serial
@@ -42,37 +48,7 @@ public class WorkingDaysData implements Serializable {
 
     private Boolean extendTermForRepaymentsOnHolidays;
 
-    // template date
     @SuppressWarnings("unused")
     private Collection<EnumOptionData> repaymentRescheduleOptions;
 
-    public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType, Boolean extendTermForDailyRepayments,
-            Boolean extendTermForRepaymentsOnHolidays) {
-        this.id = id;
-        this.recurrence = recurrence;
-        this.repaymentRescheduleType = repaymentRescheduleType;
-        this.repaymentRescheduleOptions = null;
-        this.extendTermForDailyRepayments = extendTermForDailyRepayments;
-        this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
-    }
-
-    public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType,
-            Collection<EnumOptionData> repaymentRescheduleOptions, Boolean extendTermForDailyRepayments,
-            Boolean extendTermForRepaymentsOnHolidays) {
-        this.id = id;
-        this.recurrence = recurrence;
-        this.repaymentRescheduleType = repaymentRescheduleType;
-        this.repaymentRescheduleOptions = repaymentRescheduleOptions;
-        this.extendTermForDailyRepayments = extendTermForDailyRepayments;
-        this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
-    }
-
-    public WorkingDaysData(WorkingDaysData data, Collection<EnumOptionData> repaymentRescheduleOptions) {
-        this.id = data.id;
-        this.recurrence = data.recurrence;
-        this.repaymentRescheduleType = data.repaymentRescheduleType;
-        this.repaymentRescheduleOptions = repaymentRescheduleOptions;
-        this.extendTermForDailyRepayments = data.extendTermForDailyRepayments;
-        this.extendTermForRepaymentsOnHolidays = data.extendTermForRepaymentsOnHolidays;
-    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequest.java
old mode 100755
new mode 100644
similarity index 53%
copy from fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
copy to fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequest.java
index dcdb3d1e40..8eebb989b7
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequest.java
@@ -16,12 +16,32 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.organisation.workingdays.service;
+package org.apache.fineract.organisation.workingdays.data;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.io.Serial;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 
-public interface WorkingDaysWritePlatformService {
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class WorkingDaysUpdateRequest implements Serializable {
+
+    @Serial
+    public static final long serialVersionUID = 1L;
+
+    private String recurrence;
+
+    private Integer repaymentRescheduleType;
+
+    private Boolean extendTermForDailyRepayments;
+
+    private Boolean extendTermForRepaymentsOnHolidays;
 
-    CommandProcessingResult updateWorkingDays(JsonCommand command);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequestValidator.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequestValidator.java
new file mode 100644
index 0000000000..b0a8317834
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateRequestValidator.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.organisation.workingdays.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WorkingDaysUpdateRequestValidator {
+
+    public void validateForUpdate(final WorkingDaysUpdateRequest request) {
+
+        List<ApiParameterError> validationErrors = new ArrayList<>();
+        DataValidatorBuilder validator = new DataValidatorBuilder(validationErrors)
+                .resource(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
+
+        // recurrence (mandatory)
+        String recurrence = request.getRecurrence();
+        validator.reset().parameter(WorkingDaysApiConstants.recurrence).value(recurrence).notNull();
+
+        // repaymentRescheduleType (optional, but must be 1–4 if present)
+        validator.reset().parameter(WorkingDaysApiConstants.repayment_rescheduling_enum).value(request.getRepaymentRescheduleType())
+                .ignoreIfNull().inMinMaxRange(1, 4);
+
+        // extendTermForDailyRepayments (optional but must be boolean if provided)
+        validator.reset().parameter(WorkingDaysApiConstants.extendTermForDailyRepayments).value(request.getExtendTermForDailyRepayments())
+                .ignoreIfNull().validateForBooleanValue();
+
+        // extendTermForRepaymentsOnHolidays (optional but must be boolean if provided)
+        validator.reset().parameter(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays)
+                .value(request.getExtendTermForRepaymentsOnHolidays()).ignoreIfNull().validateForBooleanValue();
+
+        throwExceptionIfValidationWarningsExist(validationErrors);
+    }
+
+    private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> validationErrors) {
+        if (!validationErrors.isEmpty()) {
+            throw new PlatformApiDataValidationException(validationErrors);
+        }
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateResponse.java
old mode 100755
new mode 100644
similarity index 54%
copy from fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
copy to fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateResponse.java
index dcdb3d1e40..725c3e9e77
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/WorkingDaysUpdateResponse.java
@@ -16,12 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.organisation.workingdays.service;
+package org.apache.fineract.organisation.workingdays.data;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 
-public interface WorkingDaysWritePlatformService {
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WorkingDaysUpdateResponse implements Serializable {
 
-    CommandProcessingResult updateWorkingDays(JsonCommand command);
+    @Serial
+    private static final long serialVersionUID = 1L;
+    private Long resourceId;
+    private String recurrence;
+    private Integer repaymentRescheduleType;
+    private Boolean extendTermForDailyRepayments;
+    private Boolean extendTermForRepaymentsOnHolidays;
+    private Map<String, Object> changes;
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/handler/UpdateWorkingDaysCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/handler/UpdateWorkingDaysCommandHandler.java
index 0f1fc6bad1..2528d818f8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/handler/UpdateWorkingDaysCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/handler/UpdateWorkingDaysCommandHandler.java
@@ -18,29 +18,38 @@
  */
 package org.apache.fineract.organisation.workingdays.handler;
 
-import org.apache.fineract.commands.annotation.CommandType;
-import org.apache.fineract.commands.handler.NewCommandSourceHandler;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import java.util.Collections;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.command.core.CommandHandler;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequest;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateResponse;
 import org.apache.fineract.organisation.workingdays.service.WorkingDaysWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
-@Service
-@CommandType(entity = "WORKINGDAYS", action = "UPDATE")
-public class UpdateWorkingDaysCommandHandler implements NewCommandSourceHandler {
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class UpdateWorkingDaysCommandHandler implements CommandHandler<WorkingDaysUpdateRequest, WorkingDaysUpdateResponse> {
 
     private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
 
-    @Autowired
-    public UpdateWorkingDaysCommandHandler(final WorkingDaysWritePlatformService workingDaysWritePlatformService) {
-        this.workingDaysWritePlatformService = workingDaysWritePlatformService;
-    }
-
     @Transactional
     @Override
-    public CommandProcessingResult processCommand(JsonCommand command) {
-        return this.workingDaysWritePlatformService.updateWorkingDays(command);
+    public WorkingDaysUpdateResponse handle(Command<WorkingDaysUpdateRequest> command) {
+        WorkingDaysUpdateRequest request = command.getPayload();
+        Map<String, Object> changes = this.workingDaysWritePlatformService.updateWorkingDays(request);
+        if (changes == null) {
+            changes = Collections.emptyMap();
+        }
+
+        return WorkingDaysUpdateResponse.builder().resourceId((Long) changes.get("resourceId")).changes(changes)
+                .recurrence(request.getRecurrence()).repaymentRescheduleType(request.getRepaymentRescheduleType())
+                .extendTermForDailyRepayments(request.getExtendTermForDailyRepayments())
+                .extendTermForRepaymentsOnHolidays(request.getExtendTermForRepaymentsOnHolidays()).build();
     }
+
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysReadPlatformServiceImpl.java
index 59d6deeaa7..1b4ecbafc2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysReadPlatformServiceImpl.java
@@ -65,7 +65,9 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
             final Boolean extendTermForDailyRepayments = rs.getBoolean("extendTermForDailyRepayments");
             final Boolean extendTermForRepaymentsOnHolidays = rs.getBoolean("extendTermForRepaymentsOnHolidays");
 
-            return new WorkingDaysData(id, recurrence, status, extendTermForDailyRepayments, extendTermForRepaymentsOnHolidays);
+            return WorkingDaysData.builder().id(id).recurrence(recurrence).repaymentRescheduleType(status)
+                    .extendTermForDailyRepayments(extendTermForDailyRepayments)
+                    .extendTermForRepaymentsOnHolidays(extendTermForRepaymentsOnHolidays).build();
         }
     }
 
@@ -77,7 +79,11 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
             final String sql = " select " + rm.schema();
             WorkingDaysData data = this.jdbcTemplate.queryForObject(sql, rm); // NOSONAR
             Collection<EnumOptionData> repaymentRescheduleOptions = repaymentRescheduleTypeOptions();
-            return new WorkingDaysData(data, repaymentRescheduleOptions);
+            return WorkingDaysData.builder().id(data.getId()).recurrence(data.getRecurrence())
+                    .repaymentRescheduleType(data.getRepaymentRescheduleType())
+                    .extendTermForDailyRepayments(data.getExtendTermForDailyRepayments())
+                    .extendTermForRepaymentsOnHolidays(data.getExtendTermForRepaymentsOnHolidays())
+                    .repaymentRescheduleOptions(repaymentRescheduleOptions).build();
         } catch (final EmptyResultDataAccessException e) {
             throw new WorkingDaysNotFoundException(e);
         }
@@ -86,7 +92,7 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
     @Override
     public WorkingDaysData repaymentRescheduleType() {
         Collection<EnumOptionData> repaymentRescheduleOptions = repaymentRescheduleTypeOptions();
-        return new WorkingDaysData(null, null, null, repaymentRescheduleOptions, null, null);
+        return WorkingDaysData.builder().repaymentRescheduleOptions(repaymentRescheduleOptions).build();
     }
 
     private Collection<EnumOptionData> repaymentRescheduleTypeOptions() {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
index dcdb3d1e40..411991cd65 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformService.java
@@ -18,10 +18,12 @@
  */
 package org.apache.fineract.organisation.workingdays.service;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import java.util.Map;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequest;
+import org.springframework.transaction.annotation.Transactional;
 
 public interface WorkingDaysWritePlatformService {
 
-    CommandProcessingResult updateWorkingDays(JsonCommand command);
+    @Transactional
+    Map<String, Object> updateWorkingDays(WorkingDaysUpdateRequest request);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformServiceJpaRepositoryImpl.java
index b0611c28bf..c7e866bd6f 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysWritePlatformServiceJpaRepositoryImpl.java
@@ -19,16 +19,15 @@
 package org.apache.fineract.organisation.workingdays.service;
 
 import java.text.ParseException;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import lombok.RequiredArgsConstructor;
 import net.fortuna.ical4j.model.property.RRule;
 import net.fortuna.ical4j.validate.ValidationException;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
-import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants;
-import org.apache.fineract.organisation.workingdays.data.WorkingDayValidator;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequest;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequestValidator;
 import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
 import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
 import org.springframework.transaction.annotation.Transactional;
@@ -37,25 +36,27 @@ import org.springframework.transaction.annotation.Transactional;
 public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements WorkingDaysWritePlatformService {
 
     private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
-    private final WorkingDayValidator fromApiJsonDeserializer;
+    private final WorkingDaysUpdateRequestValidator validator;
 
     @Transactional
     @Override
-    public CommandProcessingResult updateWorkingDays(JsonCommand command) {
+    public Map<String, Object> updateWorkingDays(WorkingDaysUpdateRequest request) {
         String recurrence = "";
         RRule rrule = null;
         try {
-            this.fromApiJsonDeserializer.validateForUpdate(command.json());
+            this.validator.validateForUpdate(request);
             final WorkingDays workingDays = this.daysRepositoryWrapper.findOne();
 
-            recurrence = command.stringValueOfParameterNamed(WorkingDaysApiConstants.recurrence);
+            recurrence = request.getRecurrence();
             rrule = new RRule(recurrence);
             rrule.validate();
 
-            Map<String, Object> changes = workingDays.update(command);
+            Map<String, Object> changes = update(workingDays, request);
+            // include the current WorkingDays resource id in the changes for response consumption
+            changes.put("resourceId", workingDays.getId());
             this.daysRepositoryWrapper.saveAndFlush(workingDays);
-            return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(workingDays.getId()).with(changes)
-                    .build();
+            return changes;
+
         } catch (final ValidationException e) {
             throw new PlatformDataIntegrityException("error.msg.invalid.recurring.rule",
                     "The Recurring Rule value: " + recurrence + " is not valid.", "recurrence", recurrence, e);
@@ -65,4 +66,32 @@ public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements Working
         }
     }
 
+    public HashMap<String, Object> update(WorkingDays workingDays, WorkingDaysUpdateRequest request) {
+        HashMap<String, Object> changes = new HashMap<>();
+
+        if (!Objects.equals(request.getRecurrence(), workingDays.getRecurrence())) {
+            workingDays.setRecurrence(request.getRecurrence());
+            changes.put("recurrence", request.getRecurrence());
+        }
+
+        Integer repaymentRescheduleType = request.getRepaymentRescheduleType();
+        if (repaymentRescheduleType != null && !Objects.equals(repaymentRescheduleType, workingDays.getRepaymentReschedulingType())) {
+            workingDays.setRepaymentReschedulingType(repaymentRescheduleType);
+            changes.put("repaymentRescheduleType", repaymentRescheduleType);
+        }
+
+        Boolean extendDaily = request.getExtendTermForDailyRepayments();
+        if (extendDaily != null && !Objects.equals(extendDaily, workingDays.getExtendTermForDailyRepayments())) {
+            workingDays.setExtendTermForDailyRepayments(extendDaily);
+            changes.put("extendTermForDailyRepayments", extendDaily);
+        }
+
+        Boolean extendHolidays = request.getExtendTermForRepaymentsOnHolidays();
+        if (extendHolidays != null && !Objects.equals(extendHolidays, workingDays.getExtendTermForRepaymentsOnHolidays())) {
+            workingDays.setExtendTermForRepaymentsOnHolidays(extendHolidays);
+            changes.put("extendTermForRepaymentsOnHolidays", extendHolidays);
+        }
+        return changes;
+    }
+
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/starter/OrganisationWorkingDaysConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/starter/OrganisationWorkingDaysConfiguration.java
index 256909f513..14f0e5c096 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/starter/OrganisationWorkingDaysConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/starter/OrganisationWorkingDaysConfiguration.java
@@ -18,7 +18,7 @@
  */
 package org.apache.fineract.organisation.workingdays.starter;
 
-import org.apache.fineract.organisation.workingdays.data.WorkingDayValidator;
+import org.apache.fineract.organisation.workingdays.data.WorkingDaysUpdateRequestValidator;
 import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
 import org.apache.fineract.organisation.workingdays.service.WorkingDaysReadPlatformService;
 import org.apache.fineract.organisation.workingdays.service.WorkingDaysReadPlatformServiceImpl;
@@ -41,7 +41,7 @@ public class OrganisationWorkingDaysConfiguration {
     @Bean
     @ConditionalOnMissingBean(WorkingDaysWritePlatformService.class)
     public WorkingDaysWritePlatformService workingDaysWritePlatformService(WorkingDaysRepositoryWrapper daysRepositoryWrapper,
-            WorkingDayValidator fromApiJsonDeserializer) {
-        return new WorkingDaysWritePlatformServiceJpaRepositoryImpl(daysRepositoryWrapper, fromApiJsonDeserializer);
+            WorkingDaysUpdateRequestValidator validator) {
+        return new WorkingDaysWritePlatformServiceJpaRepositoryImpl(daysRepositoryWrapper, validator);
     }
 }