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 d0058cee2e6..6921381c48c 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 @@ -329,6 +329,18 @@ 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") + // field configuration + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/fieldconfiguration/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_ADDRESS") + // 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/api/EntityFieldConfigurationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/api/EntityFieldConfigurationApiResource.java index 745a7f0bf8c..af7243343ab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/api/EntityFieldConfigurationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/api/EntityFieldConfigurationApiResource.java @@ -28,9 +28,8 @@ import jakarta.ws.rs.core.MediaType; import java.util.List; import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.address.data.FieldConfigurationData; -import org.apache.fineract.portfolio.address.service.FieldConfigurationReadPlatformService; +import org.apache.fineract.portfolio.address.service.FieldConfigurationReadService; import org.springframework.stereotype.Component; @Path("/v1/fieldconfiguration/{entity}") @@ -39,18 +38,15 @@ + "wherein various entities and subentities can be related.\n" + "Also it gives the user an ability to enable/disable fields,\n" + "add regular expression for validation") @RequiredArgsConstructor +@Produces({ MediaType.APPLICATION_JSON }) public class EntityFieldConfigurationApiResource { - private static final String RESOURCE_NAME_FOR_PERMISSIONS = "Address"; - private final PlatformSecurityContext context; - private final FieldConfigurationReadPlatformService readPlatformServicefld; + private final FieldConfigurationReadService fieldConfigurationReadService; @GET - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieves the Entity Field Configuration", description = "It retrieves all the Entity Field Configuration") public List getAddresses(@PathParam("entity") @Parameter(description = "entity") final String entityname) { - this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - return this.readPlatformServicefld.retrieveFieldConfiguration(entityname); + return this.fieldConfigurationReadService.retrieveFieldConfiguration(entityname); } } 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/domain/Address.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/domain/Address.java index a3a3026fc41..e481f7c7d5e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/domain/Address.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/domain/Address.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.portfolio.address.domain; -import com.google.gson.JsonObject; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -28,22 +27,23 @@ import jakarta.persistence.Table; import java.math.BigDecimal; import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.Set; +import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.portfolio.client.domain.ClientAddress; @Entity @Table(name = "m_address") +@Data +@NoArgsConstructor public class Address extends AbstractPersistableCustom { /* * @OneToMany(mappedBy = "address", cascade = CascadeType.ALL) private List clientaddress = new * ArrayList<>(); */ - @OneToMany(mappedBy = "address", cascade = CascadeType.ALL) private Set clientaddress; @@ -97,284 +97,4 @@ public class Address extends AbstractPersistableCustom { @Column(name = "updated_on") private LocalDate updatedOn; - private Address(final String street, final String addressLine1, final String addressLine2, final String addressLine3, - final String townVillage, final String city, final String countyDistrict, final CodeValue stateProvince, - final CodeValue country, final String postalCode, final BigDecimal latitude, final BigDecimal longitude, final String createdBy, - final LocalDate createdOn, final String updatedBy, final LocalDate updatedOn) { - this.street = street; - this.addressLine1 = addressLine1; - this.addressLine2 = addressLine2; - this.addressLine3 = addressLine3; - this.townVillage = townVillage; - this.city = city; - this.countyDistrict = countyDistrict; - this.stateProvince = stateProvince; - this.country = country; - this.postalCode = postalCode; - this.latitude = latitude; - this.longitude = longitude; - this.createdBy = createdBy; - // this.createdOn = createdOn; - this.updatedBy = updatedBy; - // this.updatedOn = updatedOn; - - if (createdOn != null) { - this.createdOn = createdOn; - - } - - if (updatedOn != null) { - this.updatedOn = updatedOn; - } - - } - - public Address() { - - } - - public static Address fromJson(final JsonCommand command, final CodeValue stateProvince, final CodeValue country) { - - final String street = command.stringValueOfParameterNamed("street"); - - final String addressLine1 = command.stringValueOfParameterNamed("addressLine1"); - - final String addressLine2 = command.stringValueOfParameterNamed("addressLine2"); - - final String addressLine3 = command.stringValueOfParameterNamed("addressLine3"); - - final String townVillage = command.stringValueOfParameterNamed("townVillage"); - - final String city = command.stringValueOfParameterNamed("city"); - - final String countyDistrict = command.stringValueOfParameterNamed("countyDistrict"); - - final String postalCode = command.stringValueOfParameterNamed("postalCode"); - - final BigDecimal latitude = command.bigDecimalValueOfParameterNamed("latitude"); - - final BigDecimal longitude = command.bigDecimalValueOfParameterNamed("longitude"); - - final String createdBy = command.stringValueOfParameterNamed("createdBy"); - - final LocalDate createdOn = command.localDateValueOfParameterNamed("createdOn"); - - final String updatedBy = command.stringValueOfParameterNamed("updatedBy"); - - final LocalDate updatedOn = command.localDateValueOfParameterNamed("updatedOn"); - - return new Address(street, addressLine1, addressLine2, addressLine3, townVillage, city, countyDistrict, stateProvince, country, - postalCode, latitude, longitude, createdBy, createdOn, updatedBy, updatedOn); - } - - public static Address fromJsonObject(final JsonObject jsonObject, final CodeValue state_province, final CodeValue country) { - String street = ""; - String addressLine1 = ""; - String addressLine2 = ""; - String addressLine3 = ""; - String townVillage = ""; - String city = ""; - String countyDistrict = ""; - String postalCode = ""; - BigDecimal latitude = BigDecimal.ZERO; - BigDecimal longitude = BigDecimal.ZERO; - String createdBy = ""; - String updatedBy = ""; - LocalDate updatedOnDate = null; - LocalDate createdOnDate = null; - - if (jsonObject.has("street")) { - street = jsonObject.get("street").getAsString(); - } - - if (jsonObject.has("addressLine1")) { - addressLine1 = jsonObject.get("addressLine1").getAsString(); - } - if (jsonObject.has("addressLine2")) { - - addressLine2 = jsonObject.get("addressLine2").getAsString(); - } - if (jsonObject.has("addressLine3")) { - addressLine3 = jsonObject.get("addressLine3").getAsString(); - } - if (jsonObject.has("townVillage")) { - townVillage = jsonObject.get("townVillage").getAsString(); - } - if (jsonObject.has("city")) { - city = jsonObject.get("city").getAsString(); - } - if (jsonObject.has("countyDistrict")) { - countyDistrict = jsonObject.get("countyDistrict").getAsString(); - } - if (jsonObject.has("postalCode")) { - - postalCode = jsonObject.get("postalCode").getAsString(); - } - if (jsonObject.has("latitude")) { - - latitude = jsonObject.get("latitude").getAsBigDecimal(); - } - if (jsonObject.has("longitude")) { - - longitude = jsonObject.get("longitude").getAsBigDecimal(); - } - - if (jsonObject.has("createdBy")) { - createdBy = jsonObject.get("createdBy").getAsString(); - } - if (jsonObject.has("createdOn")) { - String createdOn = jsonObject.get("createdOn").getAsString(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - createdOnDate = LocalDate.parse(createdOn, formatter); - - } - if (jsonObject.has("updatedBy")) { - updatedBy = jsonObject.get("updatedBy").getAsString(); - } - if (jsonObject.has("updatedOn")) { - String updatedOn = jsonObject.get("updatedOn").getAsString(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - updatedOnDate = LocalDate.parse(updatedOn, formatter); - } - - return new Address(street, addressLine1, addressLine2, addressLine3, townVillage, city, countyDistrict, state_province, country, - postalCode, latitude, longitude, createdBy, createdOnDate, updatedBy, updatedOnDate); - } - - public Set getClientaddress() { - return this.clientaddress; - } - - public void setClientaddress(Set clientaddress) { - this.clientaddress = clientaddress; - } - - public String getStreet() { - return this.street; - } - - public void setStreet(String street) { - this.street = street; - } - - public String getAddressLine1() { - return this.addressLine1; - } - - public void setAddressLine1(String addressLine1) { - this.addressLine1 = addressLine1; - } - - public String getAddressLine2() { - return this.addressLine2; - } - - public void setAddressLine2(String addressLine2) { - this.addressLine2 = addressLine2; - } - - public String getAddressLine3() { - return this.addressLine3; - } - - public void setAddressLine3(String addressLine3) { - this.addressLine3 = addressLine3; - } - - public String getTownVillage() { - return this.townVillage; - } - - public void setTownVillage(String townVillage) { - this.townVillage = townVillage; - } - - public String getCity() { - return this.city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getCountyDistrict() { - return this.countyDistrict; - } - - public void setCountyDistrict(String countyDistrict) { - this.countyDistrict = countyDistrict; - } - - public CodeValue getStateProvince() { - return this.stateProvince; - } - - public void setStateProvince(CodeValue stateProvince) { - this.stateProvince = stateProvince; - } - - public CodeValue getCountry() { - return this.country; - } - - public void setCountry(CodeValue country) { - this.country = country; - } - - public String getPostalCode() { - return this.postalCode; - } - - public void setPostalCode(String postalCode) { - this.postalCode = postalCode; - } - - public BigDecimal getLatitude() { - return this.latitude; - } - - public void setLatitude(BigDecimal latitude) { - this.latitude = latitude; - } - - public BigDecimal getLongitude() { - return this.longitude; - } - - public void setLongitude(BigDecimal longitude) { - this.longitude = longitude; - } - - public String getCreatedBy() { - return this.createdBy; - } - - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - public LocalDate getCreatedOn() { - return this.createdOn; - } - - public void setCreatedOn(LocalDate createdOn) { - this.createdOn = createdOn; - } - - public String getUpdatedBy() { - return this.updatedBy; - } - - public void setUpdatedBy(String updatedBy) { - this.updatedBy = updatedBy; - } - - public LocalDate getUpdatedOn() { - return this.updatedOn; - } - - public void setUpdatedOn(LocalDate updatedOn) { - this.updatedOn = updatedOn; - } - } 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/serialization/AddressCommandFromApiJsonDeserializer.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/serialization/AddressCommandFromApiJsonDeserializer.java deleted file mode 100644 index f332cf7bfa1..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/serialization/AddressCommandFromApiJsonDeserializer.java +++ /dev/null @@ -1,107 +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.serialization; - -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.portfolio.address.data.FieldConfigurationData; -import org.apache.fineract.portfolio.address.service.FieldConfigurationReadPlatformService; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class AddressCommandFromApiJsonDeserializer { - - private final FromJsonHelper fromApiJsonHelper; - private final FieldConfigurationReadPlatformService readservice; - - public void validateForUpdate(final String json) { - validate(json, false); - } - - public void validateForCreate(final String json, final boolean fromNewClient) { - validate(json, fromNewClient); - } - - public void validate(final String json, final boolean fromNewClient) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("Address"); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - final List configurationData = new ArrayList<>(this.readservice.retrieveFieldConfigurationList("ADDRESS")); - // validate the json fields from the configuration data fields - final List configData = configurationData.stream().filter(FieldConfigurationData::isEnabled).toList(); - - final Set supportedParameters = configData.stream().map(FieldConfigurationData::field).collect(Collectors.toSet()); - - supportedParameters.add("locale"); - supportedParameters.add("dateFormat"); - supportedParameters.add("street"); - supportedParameters.add(fromNewClient ? "addressTypeId" : "addressId"); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - - configData.forEach(fieldConfiguration -> { - final String field = fieldConfiguration.field().equals("addressType") ? "addressTypeId" : fieldConfiguration.field(); - final String fieldValue = this.fromApiJsonHelper.extractStringNamed(field, element); - - if (fieldConfiguration.field().equals("addressType") && fromNewClient) { - baseDataValidator.reset().parameter(field).value(fieldValue).notBlank(); - } else { - if (fieldConfiguration.isMandatory() && fromNewClient) { - baseDataValidator.reset().parameter(field).value(fieldValue).notBlank(); - } - } - - if (!fieldConfiguration.validationRegex().isEmpty()) { - baseDataValidator.reset().parameter(field).value(fieldValue).matchesRegularExpression(fieldConfiguration.validationRegex()); - } - }); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", - dataValidationErrors); - } - } - -} 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 420691f2024..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressWritePlatformServiceImpl.java +++ /dev/null @@ -1,259 +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 61% 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..b9da0e98b97 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,14 @@ */ package org.apache.fineract.portfolio.address.service; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.client.domain.Client; +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; -public interface AddressWritePlatformService { +public interface ClientAddressWriteService { - CommandProcessingResult addClientAddress(Long clientId, Long addressTypeId, JsonCommand command); + ClientAddressCreateResponse createClientAddress(ClientAddressCreateRequest request); - CommandProcessingResult addNewClientAddress(Client client, JsonCommand command); - - CommandProcessingResult updateClientAddress(Long clientId, JsonCommand command); + ClientAddressUpdateResponse updateClientAddress(ClientAddressUpdateRequest request); } 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..1c7281fec45 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/ClientAddressWriteServiceImpl.java @@ -0,0 +1,172 @@ +/** + * 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 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()); + + 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())); + 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(); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadService.java similarity index 95% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformService.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadService.java index 33b96e7bb82..839410f3ec6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadService.java @@ -21,7 +21,7 @@ import java.util.List; import org.apache.fineract.portfolio.address.data.FieldConfigurationData; -public interface FieldConfigurationReadPlatformService { +public interface FieldConfigurationReadService { List retrieveFieldConfiguration(String entity); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadServiceImpl.java similarity index 81% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformServiceImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadServiceImpl.java index 521f647da7b..fdefabcf534 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/FieldConfigurationReadServiceImpl.java @@ -21,24 +21,15 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import lombok.RequiredArgsConstructor; import org.apache.fineract.portfolio.address.data.FieldConfigurationData; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Service; -@Service -public class FieldConfigurationReadPlatformServiceImpl implements FieldConfigurationReadPlatformService { +@RequiredArgsConstructor +public class FieldConfigurationReadServiceImpl implements FieldConfigurationReadService { private final JdbcTemplate jdbcTemplate; - private final PlatformSecurityContext context; - - @Autowired - public FieldConfigurationReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate) { - this.context = context; - this.jdbcTemplate = jdbcTemplate; - } private static final class FieldMapper implements RowMapper { @@ -64,8 +55,6 @@ public FieldConfigurationData mapRow(final ResultSet rs, @SuppressWarnings("unus @Override public List retrieveFieldConfiguration(final String entity) { - this.context.authenticatedUser(); - final FieldMapper rm = new FieldMapper(); final String sql = "select " + rm.schema() + " where fld.entity=?"; @@ -74,8 +63,6 @@ public List retrieveFieldConfiguration(final String enti @Override public List retrieveFieldConfigurationList(final String entity) { - this.context.authenticatedUser(); - final FieldMapper rm = new FieldMapper(); final String sql = "select " + rm.schema() + " where fld.entity=?"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/ClientAddressConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/ClientAddressConfiguration.java new file mode 100644 index 00000000000..45317e4be3a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/starter/ClientAddressConfiguration.java @@ -0,0 +1,61 @@ +/** + * 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.address.service.FieldConfigurationReadService; +import org.apache.fineract.portfolio.address.service.FieldConfigurationReadServiceImpl; +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 ClientAddressConfiguration { + + @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); + } + + @Bean + @ConditionalOnMissingBean(FieldConfigurationReadService.class) + public FieldConfigurationReadService fieldConfigurationReadService(JdbcTemplate jdbcTemplate) { + return new FieldConfigurationReadServiceImpl(jdbcTemplate); + } +} 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 76b383ffee7..a27b2b70d6c 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; @@ -35,61 +34,57 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.util.List; +import java.util.function.Supplier; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.service.CommandWrapperBuilder; -import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.command.core.CommandDispatcher; +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 CommandDispatcher dispatcher; @GET @Path("addresses/template") - @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, + @Operation(summary = "Create an address for a Client", operationId = "createClientAddress", description = """ + Mandatory Fields : + type and clientId""") + @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 var command = new ClientAddressCreateCommand(); + command.setPayload(clientAddressRequest); + final Supplier response = dispatcher.dispatch(command); + return response.get(); } @GET @Path("/{clientid}/addresses") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "List all addresses for a Client", operationId = "retrieveAllClientAddresses", description = """ Example Requests: @@ -100,27 +95,23 @@ 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 var command = new ClientAddressUpdateCommand(); + command.setPayload(clientAddressRequest); + final Supplier response = dispatcher.dispatch(command); + return response.get(); } } 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/ClientAddressUpdateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressUpdateRequest.java new file mode 100644 index 00000000000..e4a527198ef --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientAddressUpdateRequest.java @@ -0,0 +1,59 @@ +/** + * 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 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; + 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; + 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 59ea3118e64..a4f063bf294 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,21 @@ public CommandProcessingResult createClient(final JsonCommand command) { } if (isAddressEnabled) { - this.addressWritePlatformService.addNewClientAddress(newClient, command); + try { + final com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper(); + final com.fasterxml.jackson.databind.JsonNode rootNode = objectMapper.readTree(command.json()); + final com.fasterxml.jackson.databind.JsonNode addressNode = rootNode.get("address"); + if (addressNode != null && addressNode.isArray()) { + final List addressRequests = objectMapper.convertValue(addressNode, + objectMapper.getTypeFactory().constructCollectionType(List.class, ClientAddressCreateRequest.class)); + for (ClientAddressCreateRequest addressRequest : addressRequests) { + addressRequest.setClientId(newClient.getId()); + this.clientAddressWriteService.createClientAddress(addressRequest); + } + } + } catch (com.fasterxml.jackson.core.JsonProcessingException e) { + throw new IllegalStateException("Failed to parse address JSON from client creation request", e); + } } if (command.arrayOfParameterNamed("familyMembers") != null) { diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index e472b38a074..5aebe92b5ca 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} + # meeting resilience4j.retry.instances.commandMeetingCreate.max-attempts=${FINERACT_COMMAND_MEETING_CREATE_RETRY_MAX_ATTEMPTS:3}