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 7637af6d93b..d7c1ea9b4ef 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 @@ -327,6 +327,15 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .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") + // client address (template before wildcard for specificity) + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/client/addresses/template")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_ADDRESS") + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/client/*/addresses")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_ADDRESS") + .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/client/*/addresses")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_ADDRESS") + .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/client/*/addresses")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_ADDRESS") // interest rate chart slabs (before charts for specificity) .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/interestratecharts/*/chartslabs")) .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_CHARTSLAB") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressCreateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressCreateCommand.java new file mode 100644 index 00000000000..e93b03d00f2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressCreateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.portfolio.address.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ClientAddressCreateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressUpdateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressUpdateCommand.java new file mode 100644 index 00000000000..ab61effe13c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/command/ClientAddressUpdateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.portfolio.address.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.client.data.ClientAddressUpdateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ClientAddressUpdateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResourcesSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressCreateResponse.java similarity index 50% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResourcesSwagger.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressCreateResponse.java index 2bb2d1832af..be96078bee0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResourcesSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressCreateResponse.java @@ -16,33 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.client.api; +package org.apache.fineract.portfolio.address.data; -import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serial; +import java.io.Serializable; +import lombok.Builder; +import lombok.Data; -/** - * Created by Chirag Gupta on 01/12/18. - */ -@SuppressWarnings({ "MemberName" }) -final class ClientAddressApiResourcesSwagger { - - private ClientAddressApiResourcesSwagger() {} - - @Schema(description = "PostClientClientIdAddressesResponse") - public static final class PostClientClientIdAddressesResponse { - - private PostClientClientIdAddressesResponse() {} - - @Schema(example = "15") - public Long resourceId; - } - - @Schema(description = "PutClientClientIdAddressesResponse") - public static final class PutClientClientIdAddressesResponse { +@Data +@Builder +public class ClientAddressCreateResponse implements Serializable { - private PutClientClientIdAddressesResponse() {} + @Serial + private static final long serialVersionUID = 1L; - @Schema(example = "67") - public Long resourceId; - } + private Long resourceId; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressUpdateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressUpdateResponse.java new file mode 100644 index 00000000000..5571a112a26 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/data/ClientAddressUpdateResponse.java @@ -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. + */ +package org.apache.fineract.portfolio.address.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ClientAddressUpdateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressCreateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressCreateCommandHandler.java new file mode 100644 index 00000000000..53f8882c8cc --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressCreateCommandHandler.java @@ -0,0 +1,50 @@ +/** + * 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.portfolio.address.handler; + +import io.github.resilience4j.retry.annotation.Retry; +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.portfolio.address.data.ClientAddressCreateResponse; +import org.apache.fineract.portfolio.address.service.ClientAddressWriteService; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ClientAddressCreateCommandHandler implements CommandHandler { + + private final ClientAddressWriteService writePlatformService; + + @Retry(name = "commandClientAddressCreate", fallbackMethod = "fallback") + @Override + @Transactional + public ClientAddressCreateResponse handle(Command command) { + return writePlatformService.createClientAddress(command.getPayload()); + } + + @Override + public ClientAddressCreateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressUpdateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressUpdateCommandHandler.java new file mode 100644 index 00000000000..0511e6d720d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/handler/ClientAddressUpdateCommandHandler.java @@ -0,0 +1,50 @@ +/** + * 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.portfolio.address.handler; + +import io.github.resilience4j.retry.annotation.Retry; +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.portfolio.address.data.ClientAddressUpdateResponse; +import org.apache.fineract.portfolio.address.service.ClientAddressWriteService; +import org.apache.fineract.portfolio.client.data.ClientAddressUpdateRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ClientAddressUpdateCommandHandler implements CommandHandler { + + private final ClientAddressWriteService writePlatformService; + + @Retry(name = "commandClientAddressUpdate", fallbackMethod = "fallback") + @Override + @Transactional + public ClientAddressUpdateResponse handle(Command command) { + return writePlatformService.updateClientAddress(command.getPayload()); + } + + @Override + public ClientAddressUpdateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformServiceImpl.java deleted file mode 100644 index 5c33225add6..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformServiceImpl.java +++ /dev/null @@ -1,250 +0,0 @@ -/** - * 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.portfolio.address.service; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import java.math.BigDecimal; -import java.time.LocalDate; -import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository; -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.service.DateUtils; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.portfolio.address.domain.Address; -import org.apache.fineract.portfolio.address.domain.AddressRepository; -import org.apache.fineract.portfolio.address.exception.AddressNotFoundException; -import org.apache.fineract.portfolio.address.serialization.AddressCommandFromApiJsonDeserializer; -import org.apache.fineract.portfolio.client.domain.Client; -import org.apache.fineract.portfolio.client.domain.ClientAddress; -import org.apache.fineract.portfolio.client.domain.ClientAddressRepository; -import org.apache.fineract.portfolio.client.domain.ClientAddressRepositoryWrapper; -import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class AddressWritePlatformServiceImpl implements AddressWritePlatformService { - - private final PlatformSecurityContext context; - private final CodeValueRepository codeValueRepository; - private final ClientAddressRepository clientAddressRepository; - private final ClientRepositoryWrapper clientRepositoryWrapper; - private final AddressRepository addressRepository; - private final ClientAddressRepositoryWrapper clientAddressRepositoryWrapper; - private final AddressCommandFromApiJsonDeserializer fromApiJsonDeserializer; - - @Override - public CommandProcessingResult addClientAddress(final Long clientId, final Long addressTypeId, final JsonCommand command) { - JsonObject jsonObject = command.parsedJson().getAsJsonObject(); - context.authenticatedUser(); - fromApiJsonDeserializer.validateForCreate(jsonObject.toString(), false); - - final CodeValue addressTypeIdCodeValue = codeValueRepository.getReferenceById(addressTypeId); - final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - - final Address address = createAddress(jsonObject); - addressRepository.save(address); - - final ClientAddress clientAddress = createClientAddress(client, jsonObject, addressTypeIdCodeValue, address); - clientAddressRepository.saveAndFlush(clientAddress); - - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientAddress.getId()).build(); - } - - @Override - public CommandProcessingResult addNewClientAddress(final Client client, final JsonCommand command) { - ClientAddress clientAddress = new ClientAddress(); - final JsonArray addressArray = command.arrayOfParameterNamed("address"); - - if (addressArray != null) { - for (int i = 0; i < addressArray.size(); i++) { - final JsonObject jsonObject = addressArray.get(i).getAsJsonObject(); - - fromApiJsonDeserializer.validateForCreate(jsonObject.toString(), true); - - final long addressTypeId = jsonObject.get("addressTypeId").getAsLong(); - final CodeValue addressTypeIdCodeValue = codeValueRepository.getReferenceById(addressTypeId); - - final Address address = createAddress(jsonObject); - addressRepository.save(address); - - clientAddress = createClientAddress(client, jsonObject, addressTypeIdCodeValue, address); - clientAddressRepository.saveAndFlush(clientAddress); - - } - } - - // This is confusing because only the last client address id is returned - // TODO: clean this up - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientAddress.getId()).build(); - } - - private ClientAddress createClientAddress(Client client, JsonObject jsonObject, CodeValue addressTypeIdCodeValue, Address address) { - boolean clientAddressIsActive = false; - if (jsonObject.get("isActive") != null) { - clientAddressIsActive = jsonObject.get("isActive").getAsBoolean(); - } - return ClientAddress.fromJson(clientAddressIsActive, client, address, addressTypeIdCodeValue); - } - - private Address createAddress(JsonObject jsonObject) { - CodeValue stateIdCodeValue = null; - if (jsonObject.get("stateProvinceId") != null) { - long stateId = jsonObject.get("stateProvinceId").getAsLong(); - stateIdCodeValue = codeValueRepository.getReferenceById(stateId); - } - - CodeValue countryIdCodeValue = null; - if (jsonObject.get("countryId") != null) { - long countryId = jsonObject.get("countryId").getAsLong(); - countryIdCodeValue = codeValueRepository.getReferenceById(countryId); - } - - final Address address = Address.fromJsonObject(jsonObject, stateIdCodeValue, countryIdCodeValue); - address.setCreatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); - address.setUpdatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); - return address; - } - - @Override - public CommandProcessingResult updateClientAddress(final Long clientId, final JsonCommand command) { - this.context.authenticatedUser(); - - long stateId; - - long countryId; - - CodeValue stateIdobj; - - CodeValue countryIdObj; - - boolean is_address_update = false; - - this.fromApiJsonDeserializer.validateForUpdate(command.json()); - - final long addressId = command.longValueOfParameterNamed("addressId"); - - final ClientAddress clientAddressObj = this.clientAddressRepositoryWrapper.findOneByClientIdAndAddressId(clientId, addressId); - - if (clientAddressObj == null) { - throw new AddressNotFoundException(clientId); - } - - final Address addobj = this.addressRepository.getReferenceById(addressId); - - if (!command.stringValueOfParameterNamed("addressLine1").isEmpty()) { - - is_address_update = true; - final String addressLine1 = command.stringValueOfParameterNamed("addressLine1"); - addobj.setAddressLine1(addressLine1); - - } - - if (!command.stringValueOfParameterNamed("addressLine2").isEmpty()) { - - is_address_update = true; - final String addressLine2 = command.stringValueOfParameterNamed("addressLine2"); - addobj.setAddressLine2(addressLine2); - - } - - if (!command.stringValueOfParameterNamed("addressLine3").isEmpty()) { - is_address_update = true; - final String addressLine3 = command.stringValueOfParameterNamed("addressLine3"); - addobj.setAddressLine3(addressLine3); - - } - - if (!command.stringValueOfParameterNamed("townVillage").isEmpty()) { - - is_address_update = true; - final String townVillage = command.stringValueOfParameterNamed("townVillage"); - addobj.setTownVillage(townVillage); - } - - if (!command.stringValueOfParameterNamed("city").isEmpty()) { - is_address_update = true; - final String city = command.stringValueOfParameterNamed("city"); - addobj.setCity(city); - } - - if (!command.stringValueOfParameterNamed("countyDistrict").isEmpty()) { - is_address_update = true; - final String countyDistrict = command.stringValueOfParameterNamed("countyDistrict"); - addobj.setCountyDistrict(countyDistrict); - } - - if (command.longValueOfParameterNamed("stateProvinceId") != null) { - if (command.longValueOfParameterNamed("stateProvinceId") != 0) { - is_address_update = true; - stateId = command.longValueOfParameterNamed("stateProvinceId"); - stateIdobj = this.codeValueRepository.getReferenceById(stateId); - addobj.setStateProvince(stateIdobj); - } - - } - if (command.longValueOfParameterNamed("countryId") != null) { - if (command.longValueOfParameterNamed("countryId") != 0) { - is_address_update = true; - countryId = command.longValueOfParameterNamed("countryId"); - countryIdObj = this.codeValueRepository.getReferenceById(countryId); - addobj.setCountry(countryIdObj); - } - - } - - if (!command.stringValueOfParameterNamed("postalCode").isEmpty()) { - is_address_update = true; - final String postalCode = command.stringValueOfParameterNamed("postalCode"); - addobj.setPostalCode(postalCode); - } - - if (command.bigDecimalValueOfParameterNamed("latitude") != null) { - - is_address_update = true; - final BigDecimal latitude = command.bigDecimalValueOfParameterNamed("latitude"); - - addobj.setLatitude(latitude); - } - if (command.bigDecimalValueOfParameterNamed("longitude") != null) { - is_address_update = true; - final BigDecimal longitude = command.bigDecimalValueOfParameterNamed("longitude"); - addobj.setLongitude(longitude); - - } - - if (is_address_update) { - addobj.setUpdatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); - this.addressRepository.save(addobj); - - } - - final Boolean testActive = command.booleanPrimitiveValueOfParameterNamed("isActive"); - if (testActive != null) { - final boolean active = command.booleanPrimitiveValueOfParameterNamed("isActive"); - clientAddressObj.setIs_active(active); - } - - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(clientAddressObj.getId()).build(); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadService.java similarity index 97% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformService.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadService.java index 49cf27eabc7..a710a9aa25f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadService.java @@ -22,7 +22,7 @@ import org.apache.fineract.portfolio.address.data.AddressData; import org.apache.fineract.portfolio.address.filter.ClientAddressSearchParam; -public interface AddressReadPlatformService { +public interface ClientAddressReadService { List retrieveAddressFields(long clientid); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadServiceImpl.java similarity index 80% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadServiceImpl.java index 249d60c1cc6..53a6c781908 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressReadServiceImpl.java @@ -28,29 +28,30 @@ import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; import org.apache.fineract.infrastructure.core.component.FetcherRule; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.address.data.AddressData; import org.apache.fineract.portfolio.address.filter.ClientAddressSearchParam; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Service; -@Service @RequiredArgsConstructor -public class AddressReadPlatformServiceImpl implements AddressReadPlatformService { +public class ClientAddressReadServiceImpl implements ClientAddressReadService { private final JdbcTemplate jdbcTemplate; - private final PlatformSecurityContext context; private final CodeValueReadPlatformService readService; private static final class AddFieldsMapper implements RowMapper { public String schema() { - return "addr.id as id,client.id as client_id,addr.street as street,addr.address_line_1 as address_line_1,addr.address_line_2 as address_line_2," - + "addr.address_line_3 as address_line_3,addr.town_village as town_village, addr.city as city,addr.county_district as county_district," - + "addr.state_province_id as state_province_id, addr.country_id as country_id,addr.postal_code as postal_code,addr.latitude as latitude," - + "addr.longitude as longitude,addr.created_by as created_by,addr.created_on as created_on,addr.updated_by as updated_by," - + "addr.updated_on as updated_on from m_address as addr,m_client client"; + return """ + addr.id as id,client.id as client_id,addr.street as street,\ + addr.address_line_1 as address_line_1,addr.address_line_2 as address_line_2,\ + addr.address_line_3 as address_line_3,addr.town_village as town_village, addr.city as city,\ + addr.county_district as county_district,\ + addr.state_province_id as state_province_id, addr.country_id as country_id,\ + addr.postal_code as postal_code,addr.latitude as latitude,\ + addr.longitude as longitude,addr.created_by as created_by,addr.created_on as created_on,\ + addr.updated_by as updated_by,\ + addr.updated_on as updated_on from m_address as addr,m_client client"""; } @Override @@ -101,13 +102,22 @@ public AddressData mapRow(final ResultSet rs, @SuppressWarnings("unused") final private static final class AddMapper implements RowMapper { public String schema() { - return "cv2.code_value as addressType,ca.client_id as client_id,addr.id as id,ca.address_type_id as addresstyp,ca.is_active as is_active,addr.street as street,addr.address_line_1 as address_line_1,addr.address_line_2 as address_line_2," - + "addr.address_line_3 as address_line_3,addr.town_village as town_village, addr.city as city,addr.county_district as county_district," - + "addr.state_province_id as state_province_id,cv.code_value as state_name, addr.country_id as country_id,c.code_value as country_name,addr.postal_code as postal_code,addr.latitude as latitude," - + "addr.longitude as longitude,addr.created_by as created_by,addr.created_on as created_on,addr.updated_by as updated_by," - + "addr.updated_on as updated_on" + " from m_address addr left join m_code_value cv on addr.state_province_id=cv.id" - + " left join m_code_value c on addr.country_id=c.id" + " join m_client_address ca on addr.id= ca.address_id" - + " join m_code_value cv2 on ca.address_type_id=cv2.id"; + return """ + cv2.code_value as addressType,ca.client_id as client_id,addr.id as id,\ + ca.address_type_id as addresstyp,ca.is_active as is_active,addr.street as street,\ + addr.address_line_1 as address_line_1,addr.address_line_2 as address_line_2,\ + addr.address_line_3 as address_line_3,addr.town_village as town_village, addr.city as city,\ + addr.county_district as county_district,\ + addr.state_province_id as state_province_id,cv.code_value as state_name, \ + addr.country_id as country_id,c.code_value as country_name,addr.postal_code as postal_code,\ + addr.latitude as latitude,\ + addr.longitude as longitude,addr.created_by as created_by,addr.created_on as created_on,\ + addr.updated_by as updated_by,\ + addr.updated_on as updated_on\ + from m_address addr left join m_code_value cv on addr.state_province_id=cv.id\ + left join m_code_value c on addr.country_id=c.id\ + join m_client_address ca on addr.id= ca.address_id\ + join m_code_value cv2 on ca.address_type_id=cv2.id"""; } @@ -172,8 +182,6 @@ public AddressData mapRow(final ResultSet rs, @SuppressWarnings("unused") final @Override public List retrieveAddressFields(final long clientid) { - this.context.authenticatedUser(); - final AddFieldsMapper rm = new AddFieldsMapper(); final String sql = "select " + rm.schema() + " where client.id=?"; @@ -182,7 +190,6 @@ public List retrieveAddressFields(final long clientid) { @Override public List retrieveAllClientAddress(final long clientid) { - this.context.authenticatedUser(); final AddMapper rm = new AddMapper(); final String sql = "select " + rm.schema() + " and ca.client_id=?"; return this.jdbcTemplate.query(sql, rm, new Object[] { clientid }); // NOSONAR @@ -190,8 +197,6 @@ public List retrieveAllClientAddress(final long clientid) { @Override public List retrieveAddressbyType(final long clientid, final long typeid) { - this.context.authenticatedUser(); - final AddMapper rm = new AddMapper(); final String sql = "select " + rm.schema() + " and ca.client_id=? and ca.address_type_id=?"; @@ -200,7 +205,6 @@ public List retrieveAddressbyType(final long clientid, final long t @Override public List retrieveAddressbyTypeAndStatus(final long clientid, final long typeid, final String status) { - this.context.authenticatedUser(); boolean temp = Boolean.parseBoolean(status); final AddMapper rm = new AddMapper(); @@ -211,7 +215,6 @@ public List retrieveAddressbyTypeAndStatus(final long clientid, fin @Override public List retrieveAddressbyStatus(final long clientid, final String status) { - this.context.authenticatedUser(); boolean temp = Boolean.parseBoolean(status); final AddMapper rm = new AddMapper(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteService.java similarity index 58% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformService.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteService.java index 9c5f4d4a197..1289d2ee3f1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteService.java @@ -18,15 +18,18 @@ */ package org.apache.fineract.portfolio.address.service; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import java.util.List; +import org.apache.fineract.portfolio.address.data.ClientAddressCreateResponse; +import org.apache.fineract.portfolio.address.data.ClientAddressUpdateResponse; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; +import org.apache.fineract.portfolio.client.data.ClientAddressUpdateRequest; import org.apache.fineract.portfolio.client.domain.Client; -public interface AddressWritePlatformService { +public interface ClientAddressWriteService { - CommandProcessingResult addClientAddress(Long clientId, Long addressTypeId, JsonCommand command); + ClientAddressCreateResponse createClientAddress(ClientAddressCreateRequest request); - CommandProcessingResult addNewClientAddress(Client client, JsonCommand command); + ClientAddressUpdateResponse updateClientAddress(ClientAddressUpdateRequest request); - CommandProcessingResult updateClientAddress(Long clientId, JsonCommand command); + void addNewClientAddress(Client client, List requests); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteServiceImpl.java new file mode 100644 index 00000000000..78e14c3ea53 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteServiceImpl.java @@ -0,0 +1,194 @@ +/** + * 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.portfolio.address.service; + +import java.time.LocalDate; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.codes.domain.CodeValue; +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.portfolio.address.data.ClientAddressCreateResponse; +import org.apache.fineract.portfolio.address.data.ClientAddressUpdateResponse; +import org.apache.fineract.portfolio.address.domain.Address; +import org.apache.fineract.portfolio.address.domain.AddressRepository; +import org.apache.fineract.portfolio.address.exception.AddressNotFoundException; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; +import org.apache.fineract.portfolio.client.data.ClientAddressUpdateRequest; +import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientAddress; +import org.apache.fineract.portfolio.client.domain.ClientAddressRepository; +import org.apache.fineract.portfolio.client.domain.ClientAddressRepositoryWrapper; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; + +@RequiredArgsConstructor +public class ClientAddressWriteServiceImpl implements ClientAddressWriteService { + + private final CodeValueRepository codeValueRepository; + private final ClientAddressRepository clientAddressRepository; + private final ClientRepositoryWrapper clientRepositoryWrapper; + private final AddressRepository addressRepository; + private final ClientAddressRepositoryWrapper clientAddressRepositoryWrapper; + + @Override + public ClientAddressCreateResponse createClientAddress(ClientAddressCreateRequest request) { + final CodeValue addressTypeIdCodeValue = codeValueRepository.getReferenceById(request.getAddressTypeId()); + final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(request.getClientId()); + + final Address address = createAddressFromRequest(request); + addressRepository.save(address); + + boolean isActive = request.getIsActive() != null && request.getIsActive(); + final ClientAddress clientAddress = ClientAddress.create(isActive, client, address, addressTypeIdCodeValue); + clientAddressRepository.saveAndFlush(clientAddress); + + return ClientAddressCreateResponse.builder().resourceId(clientAddress.getId()).build(); + } + + @Override + public ClientAddressUpdateResponse updateClientAddress(ClientAddressUpdateRequest request) { + final long addressId = request.getAddressId(); + + final ClientAddress clientAddressObj = clientAddressRepositoryWrapper.findOneByClientIdAndAddressId(request.getClientId(), + addressId); + + if (clientAddressObj == null) { + throw new AddressNotFoundException(request.getClientId()); + } + + final Address addObj = addressRepository.getReferenceById(addressId); + + boolean isAddressUpdate = false; + + if (request.getAddressLine1() != null && !request.getAddressLine1().isEmpty()) { + isAddressUpdate = true; + addObj.setAddressLine1(request.getAddressLine1()); + } + + if (request.getAddressLine2() != null && !request.getAddressLine2().isEmpty()) { + isAddressUpdate = true; + addObj.setAddressLine2(request.getAddressLine2()); + } + + if (request.getAddressLine3() != null && !request.getAddressLine3().isEmpty()) { + isAddressUpdate = true; + addObj.setAddressLine3(request.getAddressLine3()); + } + + if (request.getTownVillage() != null && !request.getTownVillage().isEmpty()) { + isAddressUpdate = true; + addObj.setTownVillage(request.getTownVillage()); + } + + if (request.getCity() != null && !request.getCity().isEmpty()) { + isAddressUpdate = true; + addObj.setCity(request.getCity()); + } + + if (request.getCountyDistrict() != null && !request.getCountyDistrict().isEmpty()) { + isAddressUpdate = true; + addObj.setCountyDistrict(request.getCountyDistrict()); + } + + if (request.getStateProvinceId() != null && request.getStateProvinceId() != 0) { + isAddressUpdate = true; + CodeValue stateIdobj = codeValueRepository.getReferenceById(request.getStateProvinceId()); + addObj.setStateProvince(stateIdobj); + } + + if (request.getCountryId() != null && request.getCountryId() != 0) { + isAddressUpdate = true; + CodeValue countryIdObj = codeValueRepository.getReferenceById(request.getCountryId()); + addObj.setCountry(countryIdObj); + } + + if (request.getPostalCode() != null && !request.getPostalCode().isEmpty()) { + isAddressUpdate = true; + addObj.setPostalCode(request.getPostalCode()); + } + + if (request.getLatitude() != null) { + isAddressUpdate = true; + addObj.setLatitude(request.getLatitude()); + } + + if (request.getLongitude() != null) { + isAddressUpdate = true; + addObj.setLongitude(request.getLongitude()); + } + + if (isAddressUpdate) { + addObj.setUpdatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); + addressRepository.save(addObj); + } + + if (request.getIsActive() != null) { + clientAddressObj.setIs_active(request.getIsActive()); + } + + return ClientAddressUpdateResponse.builder().resourceId(clientAddressObj.getId()).build(); + } + + @Override + public void addNewClientAddress(Client client, List requests) { + if (requests != null) { + for (ClientAddressCreateRequest request : requests) { + final CodeValue addressTypeIdCodeValue = codeValueRepository.getReferenceById(request.getAddressTypeId()); + + final Address address = createAddressFromRequest(request); + addressRepository.save(address); + + boolean isActive = request.getIsActive() != null && request.getIsActive(); + ClientAddress clientAddress = ClientAddress.create(isActive, client, address, addressTypeIdCodeValue); + clientAddressRepository.saveAndFlush(clientAddress); + } + } + } + + private Address createAddressFromRequest(ClientAddressCreateRequest request) { + CodeValue stateIdCodeValue = null; + if (request.getStateProvinceId() != null) { + stateIdCodeValue = codeValueRepository.getReferenceById(request.getStateProvinceId()); + } + + CodeValue countryIdCodeValue = null; + if (request.getCountryId() != null) { + countryIdCodeValue = codeValueRepository.getReferenceById(request.getCountryId()); + } + + final Address address = new Address(); + address.setAddressLine1(request.getAddressLine1()); + address.setAddressLine2(request.getAddressLine2()); + address.setAddressLine3(request.getAddressLine3()); + address.setTownVillage(request.getTownVillage()); + address.setCity(request.getCity()); + address.setCountyDistrict(request.getCountyDistrict()); + address.setStateProvince(stateIdCodeValue); + address.setCountry(countryIdCodeValue); + address.setPostalCode(request.getPostalCode()); + address.setLatitude(request.getLatitude()); + address.setLongitude(request.getLongitude()); + address.setCreatedBy(request.getCreatedBy()); + address.setUpdatedBy(request.getUpdatedBy()); + address.setCreatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); + address.setUpdatedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); + return address; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/AddressConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/AddressConfiguration.java new file mode 100644 index 00000000000..32b8f493c75 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/AddressConfiguration.java @@ -0,0 +1,53 @@ +/** + * 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.portfolio.address.starter; + +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository; +import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; +import org.apache.fineract.portfolio.address.domain.AddressRepository; +import org.apache.fineract.portfolio.address.service.ClientAddressReadService; +import org.apache.fineract.portfolio.address.service.ClientAddressReadServiceImpl; +import org.apache.fineract.portfolio.address.service.ClientAddressWriteService; +import org.apache.fineract.portfolio.address.service.ClientAddressWriteServiceImpl; +import org.apache.fineract.portfolio.client.domain.ClientAddressRepository; +import org.apache.fineract.portfolio.client.domain.ClientAddressRepositoryWrapper; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; + +@Configuration +public class AddressConfiguration { + + @Bean + @ConditionalOnMissingBean(ClientAddressWriteService.class) + public ClientAddressWriteService clientAddressWriteService(CodeValueRepository codeValueRepository, + ClientAddressRepository clientAddressRepository, ClientRepositoryWrapper clientRepositoryWrapper, + AddressRepository addressRepository, ClientAddressRepositoryWrapper clientAddressRepositoryWrapper) { + return new ClientAddressWriteServiceImpl(codeValueRepository, clientAddressRepository, clientRepositoryWrapper, addressRepository, + clientAddressRepositoryWrapper); + } + + @Bean + @ConditionalOnMissingBean(ClientAddressReadService.class) + public ClientAddressReadService clientAddressReadService(JdbcTemplate jdbcTemplate, CodeValueReadPlatformService readService) { + return new ClientAddressReadServiceImpl(jdbcTemplate, readService); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResource.java index 6a8de73f91f..b40c1ad3d2e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientAddressApiResource.java @@ -23,7 +23,6 @@ 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.ws.rs.Consumes; import jakarta.ws.rs.GET; @@ -36,62 +35,53 @@ import jakarta.ws.rs.core.MediaType; import java.util.List; 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.portfolio.address.command.ClientAddressCreateCommand; +import org.apache.fineract.portfolio.address.command.ClientAddressUpdateCommand; import org.apache.fineract.portfolio.address.data.AddressData; +import org.apache.fineract.portfolio.address.data.ClientAddressCreateResponse; +import org.apache.fineract.portfolio.address.data.ClientAddressUpdateResponse; import org.apache.fineract.portfolio.address.filter.ClientAddressSearchParam; -import org.apache.fineract.portfolio.address.service.AddressReadPlatformServiceImpl; -import org.apache.fineract.portfolio.client.data.ClientAddressRequest; +import org.apache.fineract.portfolio.address.service.ClientAddressReadService; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; +import org.apache.fineract.portfolio.client.data.ClientAddressUpdateRequest; import org.springframework.stereotype.Component; @Path("/v1/client") @Component @Tag(name = "Clients Address", description = "Address module is an optional module and can be configured into the system by using GlobalConfiguration setting: enable-address. In order to activate Address module, we need to enable the configuration, enable-address by setting its value to true.") @RequiredArgsConstructor +@Consumes({ MediaType.APPLICATION_JSON }) +@Produces({ MediaType.APPLICATION_JSON }) public class ClientAddressApiResource { - private static final String RESOURCE_NAME_FOR_PERMISSIONS = "Address"; - private final PlatformSecurityContext context; - private final AddressReadPlatformServiceImpl readPlatformService; - private final DefaultToApiJsonSerializer toApiJsonSerializer; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final ClientAddressReadService clientAddressReadService; + private final CommandPipeline commandPipeline; @GET @Path("addresses/template") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve client address template", operationId = "retrieveTemplateClientAddress") public AddressData getAddressesTemplate() { - context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - return readPlatformService.retrieveTemplate(); - + return clientAddressReadService.retrieveTemplate(); } @POST @Path("/{clientid}/addresses") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create an address for a Client", operationId = "createClientAddress", description = "Mandatory Fields : \n" + "type and clientId") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientAddressRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientAddressApiResourcesSwagger.PostClientClientIdAddressesResponse.class))) - public CommandProcessingResult addClientAddress(@QueryParam("type") @Parameter(description = "type") final long addressTypeId, + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientAddressCreateRequest.class))) + public ClientAddressCreateResponse addClientAddress(@QueryParam("type") @Parameter(description = "type") final long addressTypeId, @PathParam("clientid") @Parameter(description = "clientId") final long clientid, - @Parameter(hidden = true) ClientAddressRequest clientAddressRequest) { - final CommandWrapper commandRequest = new CommandWrapperBuilder().addClientAddress(clientid, addressTypeId) - .withJson(toApiJsonSerializer.serialize(clientAddressRequest)).build(); - - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + @Parameter(hidden = true) ClientAddressCreateRequest clientAddressRequest) { + clientAddressRequest.setClientId(clientid); + clientAddressRequest.setAddressTypeId(addressTypeId); + final ClientAddressCreateCommand command = new ClientAddressCreateCommand(); + command.setPayload(clientAddressRequest); + return commandPipeline.send(command).get(); } @GET @Path("/{clientid}/addresses") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "List all addresses for a Client", operationId = "retrieveAllClientAddresses", description = """ Example Requests: @@ -102,27 +92,22 @@ public CommandProcessingResult addClientAddress(@QueryParam("type") @Parameter(d public List getAddresses(@QueryParam("status") @Parameter(description = "status") final String status, @QueryParam("type") @Parameter(description = "type") final long addressTypeId, @PathParam("clientid") @Parameter(description = "clientId") final long clientid) { - context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - return readPlatformService.retrieveBySearchParam(new ClientAddressSearchParam(clientid, addressTypeId, status)); + return clientAddressReadService.retrieveBySearchParam(new ClientAddressSearchParam(clientid, addressTypeId, status)); } @PUT @Path("/{clientid}/addresses") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update an address for a Client", operationId = "updateClientAddress", description = """ All the address fields can be updated by using update client address API Mandatory Fields type and addressId""") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientAddressRequest.class))) - - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientAddressApiResourcesSwagger.PutClientClientIdAddressesResponse.class))) - public CommandProcessingResult updateClientAddress(@PathParam("clientid") @Parameter(description = "clientId") final long clientid, - @Parameter(hidden = true) ClientAddressRequest clientAddressRequest) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder().updateClientAddress(clientid) - .withJson(toApiJsonSerializer.serialize(clientAddressRequest)).build(); - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientAddressUpdateRequest.class))) + public ClientAddressUpdateResponse updateClientAddress(@PathParam("clientid") @Parameter(description = "clientId") final long clientid, + @Parameter(hidden = true) ClientAddressUpdateRequest clientAddressRequest) { + clientAddressRequest.setClientId(clientid); + final ClientAddressUpdateCommand command = new ClientAddressUpdateCommand(); + command.setPayload(clientAddressRequest); + return commandPipeline.send(command).get(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java index cf7dacd2ade..5f03eb59283 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java @@ -23,7 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Set; -import org.apache.fineract.portfolio.client.data.ClientAddressRequest; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; /** * Created by Chirag Gupta on 01/13/18. @@ -328,7 +328,7 @@ static final class PostClientsAddressRequest { @Schema(description = "List of PostClientsDatatable") public List datatables; @Schema(description = "Address requests") - public List address; + public List address; @Schema(example = "test@test.com") public String emailAddress; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressCreateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressCreateRequest.java new file mode 100644 index 00000000000..a68ae1e965f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressCreateRequest.java @@ -0,0 +1,58 @@ +/** + * 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.portfolio.client.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ClientAddressCreateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(hidden = true) + private Long clientId; + private String city; + private Long countryId; + private Boolean isActive; + private String postalCode; + private Long addressTypeId; + private String addressLine1; + private String addressLine2; + private String addressLine3; + private String townVillage; + private String countyDistrict; + private Long stateProvinceId; + private BigDecimal latitude; + private BigDecimal longitude; + private String createdBy; + private String createdOn; + private String updatedBy; + private String updatedOn; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressUpdateRequest.java similarity index 86% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressRequest.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressUpdateRequest.java index 5df556aa992..7c9900b37bd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressRequest.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressUpdateRequest.java @@ -18,19 +18,26 @@ */ package org.apache.fineract.portfolio.client.data; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serial; import java.io.Serializable; import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data +@Builder @NoArgsConstructor -public class ClientAddressRequest implements Serializable { +@AllArgsConstructor +public class ClientAddressUpdateRequest implements Serializable { @Serial private static final long serialVersionUID = 1L; + @Schema(hidden = true) + private Long clientId; private String city; private Long countryId; private Boolean isActive; @@ -50,3 +57,4 @@ public class ClientAddressRequest implements Serializable { private String updatedOn; private Long addressId; } + diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientAddress.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientAddress.java index ceb905150a4..5fc8d79fe04 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientAddress.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientAddress.java @@ -56,7 +56,7 @@ public ClientAddress() { } - public static ClientAddress fromJson(final boolean isActive, final Client client, final Address address, final CodeValue address_type) { + public static ClientAddress create(final boolean isActive, final Client client, final Address address, final CodeValue address_type) { return new ClientAddress(client, address, address_type, isActive); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/AddClientAddressCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/AddClientAddressCommandHandler.java deleted file mode 100644 index b79012ed5e2..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/AddClientAddressCommandHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * 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.portfolio.client.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 org.apache.fineract.portfolio.address.service.AddressWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -@CommandType(entity = "ADDRESS", action = "CREATE") -public class AddClientAddressCommandHandler implements NewCommandSourceHandler { - - private final AddressWritePlatformService writePlatformService; - - @Autowired - public AddClientAddressCommandHandler(final AddressWritePlatformService writePlatformService) { - this.writePlatformService = writePlatformService; - } - - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.addClientAddress(command.getClientId(), command.entityId(), command); - - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/UpdateClientAddressCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/UpdateClientAddressCommandHandler.java deleted file mode 100644 index 3523bfecf70..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/handler/UpdateClientAddressCommandHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * 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.portfolio.client.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 org.apache.fineract.portfolio.address.service.AddressWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -@CommandType(entity = "ADDRESS", action = "UPDATE") -public class UpdateClientAddressCommandHandler implements NewCommandSourceHandler { - - private final AddressWritePlatformService writePlatformService; - - @Autowired - public UpdateClientAddressCommandHandler(final AddressWritePlatformService writePlatformService) { - this.writePlatformService = writePlatformService; - } - - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - /* - * return this.writePlatformService.updateClientAddress(command.getClientId(), command.entityId(), - * command.getStatus(), command); - */ - return this.writePlatformService.updateClientAddress(command.getClientId(), command); - - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java index af7d8c7ea93..6a9352059f1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java @@ -39,7 +39,7 @@ import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.service.StaffReadService; import org.apache.fineract.portfolio.address.data.AddressData; -import org.apache.fineract.portfolio.address.service.AddressReadPlatformService; +import org.apache.fineract.portfolio.address.service.ClientAddressReadService; import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.data.ClientFamilyMembersData; @@ -62,7 +62,7 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead // data mappers private final EntityDatatableChecksReadService entityDatatableChecksReadService; - private final AddressReadPlatformService addressReadPlatformService; + private final ClientAddressReadService clientAddressReadService; private final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService; private final ConfigurationDomainService configurationDomainService; @@ -79,7 +79,7 @@ public ClientData retrieveTemplate(final Long officeId, final boolean staffInSel final Boolean isAddressEnabled = configurationDomainService.isAddressEnabled(); if (isAddressEnabled) { - address = this.addressReadPlatformService.retrieveTemplate(); + address = this.clientAddressReadService.retrieveTemplate(); } final ClientFamilyMembersData familyMemberOptions = this.clientFamilyMembersReadPlatformService.retrieveTemplate(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 540ecedebf5..a3d2cfa776c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -61,8 +61,9 @@ import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; import org.apache.fineract.portfolio.account.service.AccountNumberGenerator; -import org.apache.fineract.portfolio.address.service.AddressWritePlatformService; +import org.apache.fineract.portfolio.address.service.ClientAddressWriteService; import org.apache.fineract.portfolio.client.api.ClientApiConstants; +import org.apache.fineract.portfolio.client.data.ClientAddressCreateRequest; import org.apache.fineract.portfolio.client.data.ClientDataValidator; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientEnumerations; @@ -119,7 +120,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final ConfigurationDomainService configurationDomainService; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final FromJsonHelper fromApiJsonHelper; - private final AddressWritePlatformService addressWritePlatformService; + private final ClientAddressWriteService clientAddressWriteService; private final ClientFamilyMembersWritePlatformService clientFamilyMembersWritePlatformService; private final BusinessEventNotifierService businessEventNotifierService; private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; @@ -317,7 +318,12 @@ public CommandProcessingResult createClient(final JsonCommand command) { } if (isAddressEnabled) { - this.addressWritePlatformService.addNewClientAddress(newClient, command); + final com.google.gson.JsonArray addressArray = command.arrayOfParameterNamed("address"); + if (addressArray != null) { + final List addressRequests = new com.google.gson.Gson().fromJson(addressArray, + new com.google.gson.reflect.TypeToken>() {}.getType()); + this.clientAddressWriteService.addNewClientAddress(newClient, addressRequests); + } } if (command.arrayOfParameterNamed("familyMembers") != null) { diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index b3cc9a3550b..96d6945557b 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -662,6 +662,20 @@ resilience4j.retry.instances.commandStaffUpload.enable-exponential-backoff=${FIN resilience4j.retry.instances.commandStaffUpload.exponential-backoff-multiplier=${FINERACT_COMMAND_STAFF_UPLOAD_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} resilience4j.retry.instances.commandStaffUpload.retryExceptions=${FINERACT_COMMAND_STAFF_UPLOAD_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} +# client address + +resilience4j.retry.instances.commandClientAddressCreate.max-attempts=${FINERACT_COMMAND_CLIENT_ADDRESS_CREATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandClientAddressCreate.wait-duration=${FINERACT_COMMAND_CLIENT_ADDRESS_CREATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandClientAddressCreate.enable-exponential-backoff=${FINERACT_COMMAND_CLIENT_ADDRESS_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandClientAddressCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_CLIENT_ADDRESS_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandClientAddressCreate.retryExceptions=${FINERACT_COMMAND_CLIENT_ADDRESS_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandClientAddressUpdate.max-attempts=${FINERACT_COMMAND_CLIENT_ADDRESS_UPDATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandClientAddressUpdate.wait-duration=${FINERACT_COMMAND_CLIENT_ADDRESS_UPDATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandClientAddressUpdate.enable-exponential-backoff=${FINERACT_COMMAND_CLIENT_ADDRESS_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandClientAddressUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_CLIENT_ADDRESS_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandClientAddressUpdate.retryExceptions=${FINERACT_COMMAND_CLIENT_ADDRESS_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + # command fineract.command.enabled=true