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

arnold 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 63d6cb38a FINERACT-1760: Update office by external id - [x] Add new 
resource to update - [x] Integration test
63d6cb38a is described below

commit 63d6cb38ab8dbb8d26fcf0296804656d09c7e617
Author: Janos Haber <[email protected]>
AuthorDate: Fri Aug 25 12:58:16 2023 +0200

    FINERACT-1760: Update office by external id
    - [x] Add new resource to update
    - [x] Integration test
---
 .../organisation/office/data/OfficeData.java       | 11 ++++--
 .../organisation/office/domain/Office.java         | 40 ++++++++------------
 .../office/domain/OfficeRepository.java            |  5 ++-
 .../office/exception/OfficeNotFoundException.java  |  5 +++
 .../office/mapper/OfficeDataMapper.java            | 43 ++++++++++++++++++++++
 .../office/service/OfficeReadPlatformService.java  |  3 ++
 .../importhandler/office/OfficeImportHandler.java  |  3 +-
 .../office/api/OfficeSwaggerMapper.java            | 38 +++++++++++++++++++
 .../office/api/OfficesApiResource.java             | 24 ++++++++++++
 .../office/api/OfficesApiResourceSwagger.java      | 19 +++++-----
 .../service/OfficeReadPlatformServiceImpl.java     | 31 +++++++++-------
 .../integrationtests/OfficeIntegrationTest.java    | 22 +++++++++++
 .../integrationtests/common/OfficeHelper.java      | 27 +++++++++++++-
 13 files changed, 218 insertions(+), 53 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/data/OfficeData.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/data/OfficeData.java
index f7ad2cdb4..a7d71deba 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/data/OfficeData.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/data/OfficeData.java
@@ -23,6 +23,7 @@ import java.time.LocalDate;
 import java.util.Collection;
 import java.util.List;
 import lombok.Getter;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 
 /**
  * Immutable data object for office data.
@@ -33,7 +34,7 @@ public class OfficeData implements Serializable {
     private final Long id;
     private final String name;
     private final String nameDecorated;
-    private final String externalId;
+    private final ExternalId externalId;
     private final LocalDate openingDate;
     private final String hierarchy;
     private final Long parentId;
@@ -45,7 +46,8 @@ public class OfficeData implements Serializable {
     private String locale;
     private String dateFormat;
 
-    public static OfficeData importInstance(final String name, final Long 
parentId, final LocalDate openingDate, final String externalId) {
+    public static OfficeData importInstance(final String name, final Long 
parentId, final LocalDate openingDate,
+            final ExternalId externalId) {
         return new OfficeData(null, name, null, externalId, openingDate, null, 
parentId, null, null);
     }
 
@@ -72,8 +74,9 @@ public class OfficeData implements Serializable {
                 office.parentId, office.parentName, allowedParents);
     }
 
-    public OfficeData(final Long id, final String name, final String 
nameDecorated, final String externalId, final LocalDate openingDate,
-            final String hierarchy, final Long parentId, final String 
parentName, final Collection<OfficeData> allowedParents) {
+    public OfficeData(final Long id, final String name, final String 
nameDecorated, final ExternalId externalId,
+            final LocalDate openingDate, final String hierarchy, final Long 
parentId, final String parentName,
+            final Collection<OfficeData> allowedParents) {
         this.id = id;
         this.name = name;
         this.nameDecorated = nameDecorated;
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/Office.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/Office.java
index 4f684ce3d..29c61c1f5 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/Office.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/Office.java
@@ -32,15 +32,22 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
+import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
 import 
org.apache.fineract.organisation.office.exception.CannotUpdateOfficeWithParentOfficeSameAsSelf;
 import 
org.apache.fineract.organisation.office.exception.RootOfficeParentCannotBeUpdated;
 
 @Entity
 @Table(name = "m_office", uniqueConstraints = { @UniqueConstraint(columnNames 
= { "name" }, name = "name_org"),
         @UniqueConstraint(columnNames = { "external_id" }, name = 
"externalid_org") })
+@Getter
+@Setter
 public class Office extends AbstractPersistableCustom implements Serializable {
 
     @OneToMany(fetch = FetchType.LAZY)
@@ -60,10 +67,10 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
     @Column(name = "opening_date", nullable = false)
     private LocalDate openingDate;
 
-    @Column(name = "external_id", length = 100)
-    private String externalId;
+    @Column(name = "external_id", length = 100, unique = true)
+    private ExternalId externalId;
 
-    public static Office headOffice(final String name, final LocalDate 
openingDate, final String externalId) {
+    public static Office headOffice(final String name, final LocalDate 
openingDate, final ExternalId externalId) {
         return new Office(null, name, openingDate, externalId);
     }
 
@@ -72,7 +79,7 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
         final String name = command.stringValueOfParameterNamed("name");
         final LocalDate openingDate = 
command.localDateValueOfParameterNamed("openingDate");
         final String externalId = 
command.stringValueOfParameterNamed("externalId");
-        return new Office(parentOffice, name, openingDate, externalId);
+        return new Office(parentOffice, name, openingDate, 
ExternalIdFactory.produce(externalId));
     }
 
     protected Office() {
@@ -82,7 +89,7 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
         this.externalId = null;
     }
 
-    private Office(final Office parent, final String name, final LocalDate 
openingDate, final String externalId) {
+    private Office(final Office parent, final String name, final LocalDate 
openingDate, final ExternalId externalId) {
         this.parent = parent;
         this.openingDate = openingDate;
         if (parent != null) {
@@ -94,11 +101,7 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
         } else {
             this.name = null;
         }
-        if (StringUtils.isNotBlank(externalId)) {
-            this.externalId = externalId.trim();
-        } else {
-            this.externalId = null;
-        }
+        this.externalId = externalId;
     }
 
     private void addChild(final Office office) {
@@ -141,10 +144,11 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
         }
 
         final String externalIdParamName = "externalId";
-        if (command.isChangeInStringParameterNamed(externalIdParamName, 
this.externalId)) {
+        if (command.isChangeInStringParameterNamed(externalIdParamName,
+                
Optional.ofNullable(this.externalId).map(ExternalId::getValue).orElse(null))) {
             final String newValue = 
command.stringValueOfParameterNamed(externalIdParamName);
             actualChanges.put(externalIdParamName, newValue);
-            this.externalId = StringUtils.defaultIfEmpty(newValue, null);
+            this.externalId = 
ExternalIdFactory.produce(StringUtils.defaultIfEmpty(newValue, null));
         }
 
         return actualChanges;
@@ -193,18 +197,6 @@ public class Office extends AbstractPersistableCustom 
implements Serializable {
         return this.hierarchy + id.toString() + ".";
     }
 
-    public String getName() {
-        return this.name;
-    }
-
-    public String getHierarchy() {
-        return this.hierarchy;
-    }
-
-    public Office getParent() {
-        return this.parent;
-    }
-
     public boolean hasParentOf(final Office office) {
         if (this.parent != null) {
             return this.parent.equals(office);
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/OfficeRepository.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/OfficeRepository.java
index 0864019a6..373467ee4 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/OfficeRepository.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/domain/OfficeRepository.java
@@ -18,9 +18,12 @@
  */
 package org.apache.fineract.organisation.office.domain;
 
+import java.util.Optional;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 
 public interface OfficeRepository extends JpaRepository<Office, Long>, 
JpaSpecificationExecutor<Office> {
-    // no added behaviour
+
+    Optional<Office> findByExternalId(ExternalId externalId);
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/exception/OfficeNotFoundException.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/exception/OfficeNotFoundException.java
index c9a712d55..9c9206784 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/exception/OfficeNotFoundException.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/exception/OfficeNotFoundException.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.organisation.office.exception;
 
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import 
org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
 import org.springframework.dao.EmptyResultDataAccessException;
 
@@ -33,4 +34,8 @@ public class OfficeNotFoundException extends 
AbstractPlatformResourceNotFoundExc
     public OfficeNotFoundException(Long id, EmptyResultDataAccessException e) {
         super("error.msg.office.id.invalid", "Office with identifier " + id + 
" does not exist", id, e);
     }
+
+    public OfficeNotFoundException(ExternalId externalId) {
+        super("error.msg.office.external.id.invalid", "Office with external 
identifier " + externalId + " does not exist", externalId);
+    }
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/mapper/OfficeDataMapper.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/mapper/OfficeDataMapper.java
new file mode 100644
index 000000000..e62a2fccc
--- /dev/null
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/mapper/OfficeDataMapper.java
@@ -0,0 +1,43 @@
+/**
+ * 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.office.mapper;
+
+import java.util.Optional;
+import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
+import org.apache.fineract.organisation.office.data.OfficeData;
+import org.apache.fineract.organisation.office.domain.Office;
+import org.mapstruct.Mapper;
+
+@Mapper(config = MapstructMapperConfig.class)
+public interface OfficeDataMapper {
+
+    default OfficeData toOfficeData(Office office) {
+        String hierarchy = office.getHierarchy();
+        String nameDecorated;
+        if (hierarchy == null) {
+            nameDecorated = "";
+        } else {
+            nameDecorated = hierarchy.substring(0, (hierarchy.length() - 
hierarchy.replace(".", "").length() - 1) * 4)
+                    + Optional.ofNullable(office.getName()).orElse("");
+        }
+        return new OfficeData(office.getId(), office.getName(), nameDecorated, 
office.getExternalId(), office.getOpeningDate(),
+                office.getHierarchy(), office.getParent() != null ? 
office.getParent().getId() : null,
+                office.getParent() != null ? office.getParent().getName() : 
null, null);
+    }
+}
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformService.java
 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformService.java
index 7ec66dd4a..8d2aeefa6 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformService.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformService.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.organisation.office.service;
 
 import java.util.Collection;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.office.data.OfficeTransactionData;
@@ -31,6 +32,8 @@ public interface OfficeReadPlatformService {
 
     OfficeData retrieveOffice(Long officeId);
 
+    OfficeData retrieveOfficeWithExternalId(ExternalId externalId);
+
     OfficeData retrieveNewOfficeTemplate();
 
     Collection<OfficeData> retrieveAllowedParents(Long officeId);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/office/OfficeImportHandler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/office/OfficeImportHandler.java
index d5ad86ee9..49d007fe6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/office/OfficeImportHandler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/office/OfficeImportHandler.java
@@ -32,6 +32,7 @@ import 
org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler
 import 
org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils;
 import 
org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer;
 import 
org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.IndexedColors;
@@ -79,7 +80,7 @@ public class OfficeImportHandler implements ImportHandler {
         Long parentId = 
ImportHandlerUtils.readAsLong(OfficeConstants.PARENT_OFFICE_ID_COL, row);
         LocalDate openedDate = 
ImportHandlerUtils.readAsDate(OfficeConstants.OPENED_ON_COL, row);
         String externalId = 
ImportHandlerUtils.readAsString(OfficeConstants.EXTERNAL_ID_COL, row);
-        OfficeData office = OfficeData.importInstance(officeName, parentId, 
openedDate, externalId);
+        OfficeData office = OfficeData.importInstance(officeName, parentId, 
openedDate, ExternalIdFactory.produce(externalId));
         office.setImportFields(row.getRowNum(), locale, dateFormat);
         return office;
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficeSwaggerMapper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficeSwaggerMapper.java
new file mode 100644
index 000000000..f1ca2d58e
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficeSwaggerMapper.java
@@ -0,0 +1,38 @@
+/**
+ * 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.office.api;
+
+import java.util.Map;
+import java.util.Optional;
+import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.mapstruct.Mapper;
+
+@Mapper(config = MapstructMapperConfig.class)
+public interface OfficeSwaggerMapper {
+
+    OfficesApiResourceSwagger.PutOfficesOfficeIdResponse 
toPutOfficesOfficeIdResponse(CommandProcessingResult commandProcessingResult);
+
+    default 
OfficesApiResourceSwagger.PutOfficesOfficeIdResponse.PutOfficesOfficeIdResponseChanges
 toPutOfficesOfficeIdResponseChanges(
+            Map<String, Object> changes) {
+        
OfficesApiResourceSwagger.PutOfficesOfficeIdResponse.PutOfficesOfficeIdResponseChanges
 response = new 
OfficesApiResourceSwagger.PutOfficesOfficeIdResponse.PutOfficesOfficeIdResponseChanges();
+        Optional.ofNullable(changes).map(c -> c.get("name")).ifPresent(c -> 
response.name = String.valueOf(c));
+        return response;
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
index abc176c49..dd16a67b4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.organisation.office.api;
 
+import com.google.gson.Gson;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.media.ArraySchema;
@@ -57,6 +58,8 @@ import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.UploadRequest;
 import 
org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import 
org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.office.data.OfficeData;
@@ -79,6 +82,7 @@ public class OfficesApiResource {
 
     private static final String RESOURCE_NAME_FOR_PERMISSIONS = "OFFICE";
 
+    private final OfficeSwaggerMapper officeSwaggerMapper;
     private final PlatformSecurityContext context;
     private final OfficeReadPlatformService readPlatformService;
     private final DefaultToApiJsonSerializer<OfficeData> toApiJsonSerializer;
@@ -87,6 +91,8 @@ public class OfficesApiResource {
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService 
bulkImportWorkbookPopulatorService;
 
+    private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
+
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_JSON })
@@ -176,6 +182,24 @@ public class OfficesApiResource {
         return toApiJsonSerializer.serialize(result);
     }
 
+    @PUT
+    @Path("/external-id/{externalId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Update Office", description = "")
+    @RequestBody(required = true, content = @Content(schema = 
@Schema(implementation = 
OfficesApiResourceSwagger.PutOfficesOfficeIdRequest.class)))
+    public OfficesApiResourceSwagger.PutOfficesOfficeIdResponse 
updateOfficeWithExternalId(
+            @Parameter(description = "externalId") @PathParam("externalId") 
final String externalId,
+            final OfficesApiResourceSwagger.PutOfficesOfficeIdRequest 
apiRequestBody) {
+        OfficeData office = 
readPlatformService.retrieveOfficeWithExternalId(ExternalIdFactory.produce(externalId));
+        final CommandWrapper commandRequest = new CommandWrapperBuilder() //
+                .updateOffice(office.getId()) //
+                .withJson(gson.toJson(apiRequestBody)) //
+                .build();
+        final CommandProcessingResult result = 
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        return officeSwaggerMapper.toPutOfficesOfficeIdResponse(result);
+    }
+
     @GET
     @Path("downloadtemplate")
     @Produces("application/vnd.ms-excel")
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResourceSwagger.java
 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResourceSwagger.java
index 2f51d54bb..8db531151 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResourceSwagger.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResourceSwagger.java
@@ -112,20 +112,21 @@ final class OfficesApiResourceSwagger {
 
         @Schema(example = "Name is updated")
         public String name;
+
+        @Schema(example = "dd MMMM yyyy")
+        public String dateFormat;
+        @Schema(example = "en")
+        public String locale;
+        @Schema(example = "01 July 2007", type = "date")
+        public String openingDate;
+        @Schema(example = "SYS54-88")
+        public String externalId;
     }
 
     @Schema(description = "PutOfficesOfficeIdResponse")
     public static final class PutOfficesOfficeIdResponse {
 
-        private PutOfficesOfficeIdResponse() {
-
-        }
-
-        static final class PutOfficesOfficeIdResponseChanges {
-
-            private PutOfficesOfficeIdResponseChanges() {
-
-            }
+        public static final class PutOfficesOfficeIdResponseChanges {
 
             @Schema(example = "Name is updated")
             public String name;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
index f549935c8..e606fa323 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
@@ -24,8 +24,11 @@ import java.sql.SQLException;
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.Collection;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -34,9 +37,10 @@ import 
org.apache.fineract.organisation.monetary.data.CurrencyData;
 import 
org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.office.data.OfficeTransactionData;
+import org.apache.fineract.organisation.office.domain.OfficeRepository;
 import 
org.apache.fineract.organisation.office.exception.OfficeNotFoundException;
+import org.apache.fineract.organisation.office.mapper.OfficeDataMapper;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -44,6 +48,7 @@ import org.springframework.jdbc.core.RowMapper;
 import org.springframework.stereotype.Service;
 
 @Service
+@RequiredArgsConstructor
 public class OfficeReadPlatformServiceImpl implements 
OfficeReadPlatformService {
 
     private final JdbcTemplate jdbcTemplate;
@@ -51,18 +56,10 @@ public class OfficeReadPlatformServiceImpl implements 
OfficeReadPlatformService
     private final PlatformSecurityContext context;
     private final CurrencyReadPlatformService currencyReadPlatformService;
     private final ColumnValidator columnValidator;
-    private static final String nameDecoratedBaseOnHierarchy = 
"concat(substring('........................................', 1, 
((LENGTH(o.hierarchy) - LENGTH(REPLACE(o.hierarchy, '.', '')) - 1) * 4)), 
o.name)";
 
-    @Autowired
-    public OfficeReadPlatformServiceImpl(final PlatformSecurityContext context,
-            final CurrencyReadPlatformService currencyReadPlatformService, 
final JdbcTemplate jdbcTemplate,
-            final ColumnValidator columnValidator, 
DatabaseSpecificSQLGenerator sqlGenerator) {
-        this.context = context;
-        this.currencyReadPlatformService = currencyReadPlatformService;
-        this.columnValidator = columnValidator;
-        this.jdbcTemplate = jdbcTemplate;
-        this.sqlGenerator = sqlGenerator;
-    }
+    private final OfficeRepository officeRepository;
+    private final OfficeDataMapper officeDataMapper;
+    private static final String nameDecoratedBaseOnHierarchy = 
"concat(substring('........................................', 1, 
((LENGTH(o.hierarchy) - LENGTH(REPLACE(o.hierarchy, '.', '')) - 1) * 4)), 
o.name)";
 
     private static final class OfficeMapper implements RowMapper<OfficeData> {
 
@@ -84,7 +81,8 @@ public class OfficeReadPlatformServiceImpl implements 
OfficeReadPlatformService
             final Long parentId = JdbcSupport.getLong(rs, "parentId");
             final String parentName = rs.getString("parentName");
 
-            return new OfficeData(id, name, nameDecorated, externalId, 
openingDate, hierarchy, parentId, parentName, null);
+            return new OfficeData(id, name, nameDecorated, 
ExternalIdFactory.produce(externalId), openingDate, hierarchy, parentId,
+                    parentName, null);
         }
     }
 
@@ -210,6 +208,13 @@ public class OfficeReadPlatformServiceImpl implements 
OfficeReadPlatformService
         }
     }
 
+    @Override
+    public OfficeData retrieveOfficeWithExternalId(ExternalId externalId) {
+        this.context.authenticatedUser();
+        return 
officeRepository.findByExternalId(externalId).map(officeDataMapper::toOfficeData)
+                .orElseThrow(() -> new OfficeNotFoundException(externalId));
+    }
+
     @Override
     public OfficeData retrieveNewOfficeTemplate() {
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/OfficeIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/OfficeIntegrationTest.java
index 4ffd31fc4..59636a171 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/OfficeIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/OfficeIntegrationTest.java
@@ -23,12 +23,16 @@ import io.restassured.builder.ResponseSpecBuilder;
 import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
+import java.io.IOException;
+import java.util.UUID;
+import org.apache.fineract.client.models.PutOfficesOfficeIdResponse;
 import org.apache.fineract.integrationtests.common.OfficeDomain;
 import org.apache.fineract.integrationtests.common.OfficeHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import retrofit2.Response;
 
 public class OfficeIntegrationTest {
 
@@ -57,4 +61,22 @@ public class OfficeIntegrationTest {
         Assertions.assertTrue(name.equals(newOffice.getName()));
         Assertions.assertArrayEquals(dateArr, newOffice.getOpeningDate());
     }
+
+    @Test
+    public void testOfficeModificationWithExternalId() throws IOException {
+        OfficeHelper oh = new OfficeHelper(requestSpec, responseSpec);
+        String externalId = UUID.randomUUID().toString();
+        int officeId = oh.createOfficeWithExternalId(externalId, "01 July 
2007");
+        String date = "02 July 2007";
+        String name = Utils.uniqueRandomStringGenerator("New_Office_", 4);
+        String[] dateArr = { "2007", "7", "2" };
+
+        Response<PutOfficesOfficeIdResponse> updateResult = 
oh.updateOfficeUsingExternalId(externalId, name, date);
+        Assertions.assertTrue(updateResult.isSuccessful());
+        Assertions.assertEquals(officeId, updateResult.body().getOfficeId());
+        OfficeDomain newOffice = oh.retrieveOfficeByID(officeId);
+
+        Assertions.assertTrue(name.equals(newOffice.getName()));
+        Assertions.assertArrayEquals(dateArr, newOffice.getOpeningDate());
+    }
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/OfficeHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/OfficeHelper.java
index d92723c28..650a5cb51 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/OfficeHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/OfficeHelper.java
@@ -30,13 +30,17 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
 import org.apache.fineract.client.models.GetOfficesResponse;
+import org.apache.fineract.client.models.PutOfficesOfficeIdRequest;
+import org.apache.fineract.client.models.PutOfficesOfficeIdResponse;
 import org.apache.fineract.client.util.JSON;
+import org.apache.fineract.integrationtests.client.IntegrationTest;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import retrofit2.Response;
 
-public class OfficeHelper {
+public class OfficeHelper extends IntegrationTest {
 
     public static final long HEAD_OFFICE_ID = 1L; // The ID is hardcoded in 
the initial Liquibase migration script
 
@@ -69,6 +73,12 @@ public class OfficeHelper {
                 CommonConstants.RESPONSE_RESOURCE_ID);
     }
 
+    public Integer createOfficeWithExternalId(String externalId, final String 
openingDate) {
+        String json = getAsJSON(externalId, openingDate);
+        return Utils.performServerPost(this.requestSpec, this.responseSpec, 
OFFICE_URL + "?" + Utils.TENANT_IDENTIFIER, json,
+                CommonConstants.RESPONSE_RESOURCE_ID);
+    }
+
     public Integer updateOffice(int id, String name, String openingDate) {
         final HashMap<String, String> map = new HashMap<String, String>();
         map.put("name", name);
@@ -82,13 +92,28 @@ public class OfficeHelper {
                 new Gson().toJson(map), "resourceId");
     }
 
+    public Response<PutOfficesOfficeIdResponse> 
updateOfficeUsingExternalId(String externalId, String name, String openingDate)
+            throws IOException {
+        return fineract().offices
+                .updateOfficeWithExternalId(externalId,
+                        new 
PutOfficesOfficeIdRequest().name(name).openingDate(openingDate).dateFormat("dd 
MMMM yyyy").locale("en"))
+                .execute();
+    }
+
     public static String getAsJSON(final String openingDate) {
+        return getAsJSON(null, openingDate);
+    }
+
+    public static String getAsJSON(String externalId, final String 
openingDate) {
         final HashMap<String, String> map = new HashMap<>();
         map.put("parentId", "1");
         map.put("name", Utils.uniqueRandomStringGenerator("Office_", 4));
         map.put("dateFormat", "dd MMMM yyyy");
         map.put("locale", "en");
         map.put("openingDate", openingDate);
+        if (externalId != null) {
+            map.put("externalId", externalId);
+        }
         LOG.info("map :  {}", map);
         return new Gson().toJson(map);
     }

Reply via email to