From 63d6cb38ab8dbb8d26fcf0296804656d09c7e617 Mon Sep 17 00:00:00 2001 From: Janos Haber Date: Fri, 25 Aug 2023 12:58:16 +0200 Subject: [PATCH] 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 ++- .../exception/OfficeNotFoundException.java | 5 +++ .../office/mapper/OfficeDataMapper.java | 43 +++++++++++++++++++ .../service/OfficeReadPlatformService.java | 3 ++ .../office/OfficeImportHandler.java | 3 +- .../office/api/OfficeSwaggerMapper.java | 38 ++++++++++++++++ .../office/api/OfficesApiResource.java | 24 +++++++++++ .../office/api/OfficesApiResourceSwagger.java | 19 ++++---- .../OfficeReadPlatformServiceImpl.java | 31 +++++++------ .../OfficeIntegrationTest.java | 22 ++++++++++ .../integrationtests/common/OfficeHelper.java | 27 +++++++++++- 13 files changed, 218 insertions(+), 53 deletions(-) create mode 100644 fineract-core/src/main/java/org/apache/fineract/organisation/office/mapper/OfficeDataMapper.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficeSwaggerMapper.java 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 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 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, JpaSpecificationExecutor { - // no added behaviour + + Optional 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 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 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 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 { @@ -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 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 map = new HashMap(); map.put("name", name); @@ -82,13 +92,28 @@ public class OfficeHelper { new Gson().toJson(map), "resourceId"); } + public Response 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 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); }