FINERACT-2243: New command processing - payment type (#5506)

This commit is contained in:
Aleksandar Vidakovic
2026-02-18 08:19:29 -06:00
committed by GitHub
parent 020754bad4
commit 3a842ecb9a
69 changed files with 727 additions and 758 deletions
@@ -29,7 +29,6 @@ import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.infrastructure.accountnumberformat.service.AccountNumberFormatConstants;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
import org.apache.fineract.portfolio.paymenttype.api.PaymentTypeApiResourceConstants;
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
import org.apache.fineract.portfolio.self.pockets.api.PocketApiConstants;
import org.apache.fineract.useradministration.api.PasswordPreferencesApiConstants;
@@ -2946,30 +2945,6 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createPaymentType() {
this.actionName = "CREATE";
this.entityName = PaymentTypeApiResourceConstants.ENTITY_NAME;
this.entityId = null;
this.href = "/" + PaymentTypeApiResourceConstants.RESOURCE_NAME;
return this;
}
public CommandWrapperBuilder updatePaymentType(final Long paymentTypeId) {
this.actionName = "UPDATE";
this.entityName = PaymentTypeApiResourceConstants.ENTITY_NAME;
this.entityId = paymentTypeId;
this.href = "/" + PaymentTypeApiResourceConstants.RESOURCE_NAME + paymentTypeId;
return this;
}
public CommandWrapperBuilder deletePaymentType(final Long paymentTypeId) {
this.actionName = "DELETE";
this.entityName = "PAYMENTTYPE";
this.entityId = paymentTypeId;
this.href = "/" + PaymentTypeApiResourceConstants.RESOURCE_NAME + paymentTypeId;
return this;
}
public CommandWrapperBuilder updateExternalServiceProperties(final String externalServiceName) {
this.actionName = "UPDATE";
this.entityName = "EXTERNALSERVICES";
@@ -19,11 +19,6 @@
package org.apache.fineract.portfolio.paymenttype.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -36,17 +31,21 @@ import jakarta.ws.rs.Produces;
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.command.core.CommandPipeline;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.paymenttype.command.PaymentTypeCreateCommand;
import org.apache.fineract.portfolio.paymenttype.command.PaymentTypeDeleteCommand;
import org.apache.fineract.portfolio.paymenttype.command.PaymentTypeUpdateCommand;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.paymenttype.data.request.PaymentTypeRequest;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateResponse;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService;
import org.springframework.stereotype.Component;
@Path("/v1/paymenttypes")
@@ -55,19 +54,15 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
public class PaymentTypeApiResource {
private final PlatformSecurityContext securityContext;
private final PaymentTypeReadService readPlatformService;
private final CommandPipeline commandPipeline;
private final DefaultToApiJsonSerializer<PaymentTypeData> jsonSerializer;
private final PaymentTypeReadPlatformService readPlatformService;
private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
private final PaymentTypeRepositoryWrapper paymentTypeRepositoryWrapper;
@GET
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Retrieve all Payment Types", description = "Retrieve list of payment types")
public List<PaymentTypeData> getAllPaymentTypes(
@QueryParam("onlyWithCode") @Parameter(description = "onlyWithCode") final boolean onlyWithCode) {
securityContext.authenticatedUser().validateHasReadPermission(PaymentTypeApiResourceConstants.ENTITY_NAME);
public List<PaymentTypeData> getAllPaymentTypes(@QueryParam("onlyWithCode") final boolean onlyWithCode) {
return onlyWithCode ? readPlatformService.retrieveAllPaymentTypesWithCode() : readPlatformService.retrieveAllPaymentTypes();
}
@@ -76,27 +71,22 @@ public class PaymentTypeApiResource {
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Retrieve a Payment Type", description = "Retrieves a payment type")
public PaymentTypeData retrieveOnePaymentType(
@PathParam("paymentTypeId") @Parameter(description = "paymentTypeId") final Long paymentTypeId) {
securityContext.authenticatedUser().validateHasReadPermission(PaymentTypeApiResourceConstants.ENTITY_NAME);
paymentTypeRepositoryWrapper.findOneWithNotFoundDetection(paymentTypeId);
public PaymentTypeData retrieveOnePaymentType(@PathParam("paymentTypeId") final Long paymentTypeId) {
return readPlatformService.retrieveOne(paymentTypeId);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create a Payment Type", description = "Creates a new Payment type\n\n" + "Mandatory Fields: name\n\n"
+ "Optional Fields: Description, isCashPayment,Position")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = PaymentTypeRequest.class)))
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PaymentTypeApiResourceSwagger.PostPaymentTypesResponse.class)))
public CommandProcessingResult createPaymentType(@Parameter(hidden = true) PaymentTypeRequest paymentTypeRequest) {
@Operation(summary = "Create a Payment Type", description = "Creates a new Payment type")
public PaymentTypeCreateResponse createPaymentType(PaymentTypeCreateRequest request) {
final var command = new PaymentTypeCreateCommand();
final CommandWrapper commandRequest = new CommandWrapperBuilder().createPaymentType()
.withJson(jsonSerializer.serialize(paymentTypeRequest)).build();
command.setPayload(request);
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
return result;
final Supplier<PaymentTypeCreateResponse> response = commandPipeline.send(command);
return response.get();
}
@PUT
@@ -104,17 +94,18 @@ public class PaymentTypeApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update a Payment Type", description = "Updates a Payment Type")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = PaymentTypeApiResourceSwagger.PutPaymentTypesPaymentTypeIdRequest.class)))
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PaymentTypeApiResourceSwagger.PutPaymentTypesPaymentTypeIdResponse.class)))
public CommandProcessingResult updatePaymentType(
@PathParam("paymentTypeId") @Parameter(description = "paymentTypeId") final Long paymentTypeId,
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
public PaymentTypeUpdateResponse updatePaymentType(@PathParam("paymentTypeId") final Long paymentTypeId,
final PaymentTypeUpdateRequest request) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updatePaymentType(paymentTypeId).withJson(apiRequestBodyAsJson)
.build();
request.setId(paymentTypeId);
final CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
return result;
final var command = new PaymentTypeUpdateCommand();
command.setPayload(request);
final Supplier<PaymentTypeUpdateResponse> response = commandPipeline.send(command);
return response.get();
}
@DELETE
@@ -122,15 +113,14 @@ public class PaymentTypeApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete a Payment Type", description = "Deletes payment type")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PaymentTypeApiResourceSwagger.DeletePaymentTypesPaymentTypeIdResponse.class)))
public CommandProcessingResult deleteCode(
@PathParam("paymentTypeId") @Parameter(description = "paymentTypeId") final Long paymentTypeId) {
public PaymentTypeDeleteResponse deleteCode(@PathParam("paymentTypeId") final Long paymentTypeId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deletePaymentType(paymentTypeId).build();
final var command = new PaymentTypeDeleteCommand();
final CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
command.setPayload(PaymentTypeDeleteRequest.builder().id(paymentTypeId).build());
return result;
final Supplier<PaymentTypeDeleteResponse> response = commandPipeline.send(command);
return response.get();
}
}
@@ -1,43 +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.paymenttype.api;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public final class PaymentTypeApiResourceConstants {
private PaymentTypeApiResourceConstants() {
}
public static final String RESOURCE_NAME = "paymenttype";
public static final String ENTITY_NAME = "PAYMENTTYPE";
public static final String ID = "id";
public static final String NAME = "name";
public static final String DESCRIPTION = "description";
public static final String ISCASHPAYMENT = "isCashPayment";
public static final String POSITION = "position";
public static final String CODE_NAME = "code_name";
public static final String IS_SYSTEM_DEFINED = "system_defined";
static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(ID, NAME, DESCRIPTION, ISCASHPAYMENT));
}
@@ -1,96 +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.paymenttype.api;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Created by Chirag Gupta on 01/01/18.
*/
public final class PaymentTypeApiResourceSwagger {
private PaymentTypeApiResourceSwagger() {}
@Schema(description = "GetPaymentTypesResponse")
public static final class GetPaymentTypesResponse {
private GetPaymentTypesResponse() {}
@Schema(example = "24")
public Long id;
@Schema(example = "PTC")
public String name;
@Schema(example = "Cash")
public String description;
@Schema(example = "true")
public Boolean isCashPayment;
@Schema(example = "0")
public Integer position;
@Schema(example = "REPAYMENT_REFUND")
public String codeName;
@Schema(example = "false")
public Boolean isSystemDefined;
}
@Schema(description = "PostPaymentTypesResponse")
public static final class PostPaymentTypesResponse {
private PostPaymentTypesResponse() {}
@Schema(example = "1")
public Long resourceId;
}
@Schema(description = "PutPaymentTypesPaymentTypeIdRequest")
public static final class PutPaymentTypesPaymentTypeIdRequest {
private PutPaymentTypesPaymentTypeIdRequest() {}
@Schema(example = "mPay")
public String name;
@Schema(example = "not a cash payment type")
public String description;
@Schema(example = "false")
public Boolean isCashPayment;
@Schema(example = "3")
public Integer position;
@Schema(example = "REPAYMENT_REFUND")
public String codeName;
@Schema(example = "false")
public Boolean isSystemDefined;
}
@Schema(description = "PutPaymentTypesPaymentTypeIdResponse")
public static final class PutPaymentTypesPaymentTypeIdResponse {
private PutPaymentTypesPaymentTypeIdResponse() {}
@Schema(example = "13")
public Long resourceId;
}
@Schema(description = "DeletePaymentTypesPaymentTypeIdResponse")
public static final class DeletePaymentTypesPaymentTypeIdResponse {
private DeletePaymentTypesPaymentTypeIdResponse() {}
@Schema(example = "13")
public Long resourceId;
}
}
@@ -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.paymenttype.command;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.fineract.command.core.Command;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateRequest;
@Data
@EqualsAndHashCode(callSuper = true)
public class PaymentTypeCreateCommand extends Command<PaymentTypeCreateRequest> {}
@@ -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.paymenttype.command;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.fineract.command.core.Command;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteRequest;
@Data
@EqualsAndHashCode(callSuper = true)
public class PaymentTypeDeleteCommand extends Command<PaymentTypeDeleteRequest> {}
@@ -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.paymenttype.command;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.fineract.command.core.Command;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateRequest;
@Data
@EqualsAndHashCode(callSuper = true)
public class PaymentTypeUpdateCommand extends Command<PaymentTypeUpdateRequest> {}
@@ -0,0 +1,56 @@
/**
* 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.paymenttype.data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeCreateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotBlank(message = "{org.apache.fineract.portfolio.paymenttype.name.not-blank}")
private String name;
@Size(max = 500, message = "{org.apache.fineract.portfolio.paymenttype.description.size}")
private String description;
private Boolean isCashPayment;
@PositiveOrZero(message = "{org.apache.fineract.portfolio.paymenttype.position.positive-or-zero}")
private Long position;
// @JsonProperty("code_name") // TODO: fix this, for backwards compatibility only... leave this for Jackson config
@Size(max = 100, message = "{org.apache.fineract.portfolio.paymenttype.code-name.size}")
private String codeName;
// @JsonProperty("system_defined") // TODO: fix this, for backwards compatibility only... leave this for Jackson
// config
@Builder.Default
@NotNull(message = "{org.apache.fineract.portfolio.is-system-defined.not-null}")
private Boolean isSystemDefined = false;
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.paymenttype.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeCreateResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long resourceId;
}
@@ -18,41 +18,27 @@
*/
package org.apache.fineract.portfolio.paymenttype.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ToString
@Getter
@Setter
@EqualsAndHashCode
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeData implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String description;
private Boolean isCashPayment;
private Integer position;
private Long position;
private String codeName;
private Boolean isSystemDefined;
public static PaymentTypeData instance(final Long id, final String name, final String description, final Boolean isCashPayment,
final Integer position) {
String codeName = null;
Boolean isSystemDefined = false;
return new PaymentTypeData(id, name, description, isCashPayment, position, codeName, isSystemDefined);
}
public static PaymentTypeData instance(final Long id, final String name) {
String description = null;
Boolean isCashPayment = null;
Integer position = null;
String codeName = null;
Boolean isSystemDefined = false;
return new PaymentTypeData(id, name, description, isCashPayment, position, codeName, isSystemDefined);
}
}
@@ -1,176 +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.paymenttype.data;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.paymenttype.api.PaymentTypeApiResourceConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class PaymentTypeDataValidator {
private final FromJsonHelper fromApiJsonHelper;
private static final Set<String> CREATE_PAYMENT_TYPE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(PaymentTypeApiResourceConstants.NAME, PaymentTypeApiResourceConstants.DESCRIPTION,
PaymentTypeApiResourceConstants.ISCASHPAYMENT, PaymentTypeApiResourceConstants.POSITION,
PaymentTypeApiResourceConstants.CODE_NAME, PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED));
private static final Set<String> UPDATE_PAYMENT_TYPE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(PaymentTypeApiResourceConstants.NAME, PaymentTypeApiResourceConstants.DESCRIPTION,
PaymentTypeApiResourceConstants.ISCASHPAYMENT, PaymentTypeApiResourceConstants.POSITION,
PaymentTypeApiResourceConstants.CODE_NAME, PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED));
@Autowired
public PaymentTypeDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, CREATE_PAYMENT_TYPE_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(PaymentTypeApiResourceConstants.ENTITY_NAME);
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.NAME, element)) {
final String name = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.NAME, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.NAME).value(name).notBlank();
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.DESCRIPTION, element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.DESCRIPTION, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.DESCRIPTION).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.ISCASHPAYMENT, element)) {
final Boolean isCashPayment = this.fromApiJsonHelper.extractBooleanNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT,
element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.ISCASHPAYMENT).value(isCashPayment)
.validateForBooleanValue();
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.POSITION, element)) {
final Long position = this.fromApiJsonHelper.extractLongNamed(PaymentTypeApiResourceConstants.POSITION, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.POSITION).value(position).ignoreIfNull()
.integerZeroOrGreater();
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.CODE_NAME, element)) {
final String codeName = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.CODE_NAME, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.CODE_NAME).value(codeName).ignoreIfNull()
.notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED, element)) {
final Boolean isSystemDefined = this.fromApiJsonHelper.extractBooleanNamed(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED,
element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED).value(isSystemDefined)
.validateForBooleanValue();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, UPDATE_PAYMENT_TYPE_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(PaymentTypeApiResourceConstants.ENTITY_NAME);
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.NAME, element)) {
final String name = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.NAME, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.NAME).value(name);
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.DESCRIPTION, element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.DESCRIPTION, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.DESCRIPTION).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.ISCASHPAYMENT, element)) {
final Boolean isCashPayment = this.fromApiJsonHelper.extractBooleanNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT,
element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.ISCASHPAYMENT).value(isCashPayment)
.validateForBooleanValue();
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.POSITION, element)) {
final Long position = this.fromApiJsonHelper.extractLongNamed(PaymentTypeApiResourceConstants.POSITION, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.POSITION).value(position).ignoreIfNull()
.integerZeroOrGreater();
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.CODE_NAME, element)) {
final String codeName = this.fromApiJsonHelper.extractStringNamed(PaymentTypeApiResourceConstants.CODE_NAME, element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.CODE_NAME).value(codeName).ignoreIfNull()
.notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED, element)) {
final Boolean isSystemDefined = this.fromApiJsonHelper.extractBooleanNamed(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED,
element);
baseDataValidator.reset().parameter(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED).value(isSystemDefined)
.validateForBooleanValue();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
}
@@ -16,15 +16,23 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.paymenttype.data.request;
package org.apache.fineract.portfolio.paymenttype.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
public record PaymentTypeRequest(String name, String description, Boolean isCashPayment, Integer position, String codeName,
Boolean isSystemDefined) implements Serializable {
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeDeleteRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.paymenttype.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeDeleteResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long resourceId;
}
@@ -0,0 +1,60 @@
/**
* 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.paymenttype.data;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeUpdateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Hidden
@NotNull(message = "{org.apache.fineract.portfolio.paymenttype.id.not-null}")
private Long id;
@NotBlank(message = "{org.apache.fineract.portfolio.paymenttype.name.not-blank}")
private String name;
@Size(max = 500, message = "{org.apache.fineract.portfolio.paymenttype.description.size}")
private String description;
private Boolean isCashPayment;
@PositiveOrZero(message = "{org.apache.fineract.portfolio.paymenttype.position.positive-or-zero}")
private Long position;
// @JsonProperty("code_name") // TODO: fix this, for backwards compatibility only... leave this for Jackson config
@Size(max = 100, message = "{org.apache.fineract.portfolio.paymenttype.code-name.size}")
private String codeName;
// @JsonProperty("system_defined") // TODO: fix this, for backwards compatibility only... leave this for Jackson
// config
@Builder.Default
@NotNull(message = "{org.apache.fineract.portfolio.is-system-defined.not-null}")
private Boolean isSystemDefined = false;
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.paymenttype.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentTypeUpdateResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long resourceId;
}
@@ -21,20 +21,17 @@ package org.apache.fineract.portfolio.paymenttype.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.paymenttype.api.PaymentTypeApiResourceConstants;
@Getter
@Setter
@Entity
@Table(name = "m_payment_type")
@NoArgsConstructor
@AllArgsConstructor
public class PaymentType extends AbstractPersistableCustom<Long> {
@@ -55,38 +52,4 @@ public class PaymentType extends AbstractPersistableCustom<Long> {
@Column(name = "is_system_defined")
private Boolean isSystemDefined;
protected PaymentType() {}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(3);
if (command.isChangeInStringParameterNamed(PaymentTypeApiResourceConstants.NAME, this.name)) {
final String newValue = command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.NAME);
actualChanges.put(PaymentTypeApiResourceConstants.NAME, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(PaymentTypeApiResourceConstants.DESCRIPTION, this.description)) {
final String newDescription = command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.DESCRIPTION);
actualChanges.put(PaymentTypeApiResourceConstants.DESCRIPTION, newDescription);
this.description = StringUtils.defaultIfEmpty(newDescription, null);
}
if (command.isChangeInBooleanParameterNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT, this.isCashPayment)) {
final Boolean newCashPaymentType = command.booleanObjectValueOfParameterNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT);
actualChanges.put(PaymentTypeApiResourceConstants.ISCASHPAYMENT, newCashPaymentType);
this.isCashPayment = newCashPaymentType.booleanValue();
}
if (command.isChangeInLongParameterNamed(PaymentTypeApiResourceConstants.POSITION, this.position)) {
final Long newPosition = command.longValueOfParameterNamed(PaymentTypeApiResourceConstants.POSITION);
actualChanges.put(PaymentTypeApiResourceConstants.POSITION, newPosition);
this.position = newPosition;
}
return actualChanges;
}
}
@@ -18,27 +18,19 @@
*/
package org.apache.fineract.portfolio.paymenttype.domain;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.portfolio.paymenttype.exception.PaymentTypeNotFoundException;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
// TODO: get rid of this, unnecessarily hides real repository; don't use this outside of payment domain!
@Deprecated(forRemoval = true)
public class PaymentTypeRepositoryWrapper {
private final PaymentTypeRepository repository;
public List<PaymentType> findAll() {
return this.repository.findAllByOrderByPositionAsc();
}
public List<PaymentType> findAllWithCodeName() {
return this.repository.findAllByCodeNameIsNotNullOrderByPositionAsc();
}
public PaymentType findOneWithNotFoundDetection(final Long id) {
return this.repository.findById(id).orElseThrow(() -> new PaymentTypeNotFoundException(id));
}
}
@@ -18,29 +18,33 @@
*/
package org.apache.fineract.portfolio.paymenttype.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 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.paymenttype.data.PaymentTypeCreateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateResponse;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeWriteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "PAYMENTTYPE", action = "DELETE")
public class DeletePaymentTypeCommandHandler implements NewCommandSourceHandler {
@Slf4j
@Component
@RequiredArgsConstructor
public class PaymentTypeCreateCommandHandler implements CommandHandler<PaymentTypeCreateRequest, PaymentTypeCreateResponse> {
private final PaymentTypeWriteService paymentTypeWriteService;
@Autowired
public DeletePaymentTypeCommandHandler(final PaymentTypeWriteService paymentTypeWriteService) {
this.paymentTypeWriteService = paymentTypeWriteService;
@Retry(name = "commandPaymentTypeCreate", fallbackMethod = "fallback")
@Override
@Transactional
public PaymentTypeCreateResponse handle(Command<PaymentTypeCreateRequest> command) {
return paymentTypeWriteService.createPaymentType(command.getPayload());
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.paymentTypeWriteService.deletePaymentType(command.entityId());
public PaymentTypeCreateResponse fallback(Command<PaymentTypeCreateRequest> command, Throwable t) {
return CommandHandler.super.fallback(command, t);
}
}
@@ -18,29 +18,33 @@
*/
package org.apache.fineract.portfolio.paymenttype.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 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.paymenttype.data.PaymentTypeDeleteRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteResponse;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeWriteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "PAYMENTTYPE", action = "CREATE")
public class CreatePaymentTypeCommandHandler implements NewCommandSourceHandler {
@Slf4j
@Component
@RequiredArgsConstructor
public class PaymentTypeDeleteCommandHandler implements CommandHandler<PaymentTypeDeleteRequest, PaymentTypeDeleteResponse> {
private final PaymentTypeWriteService paymentTypeWriteService;
@Autowired
public CreatePaymentTypeCommandHandler(final PaymentTypeWriteService paymentTypeWriteService) {
this.paymentTypeWriteService = paymentTypeWriteService;
@Retry(name = "commandPaymentTypeDelete", fallbackMethod = "fallback")
@Override
@Transactional
public PaymentTypeDeleteResponse handle(Command<PaymentTypeDeleteRequest> command) {
return paymentTypeWriteService.deletePaymentType(command.getPayload());
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.paymentTypeWriteService.createPaymentType(command);
public PaymentTypeDeleteResponse fallback(Command<PaymentTypeDeleteRequest> command, Throwable t) {
return CommandHandler.super.fallback(command, t);
}
}
@@ -18,29 +18,33 @@
*/
package org.apache.fineract.portfolio.paymenttype.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 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.paymenttype.data.PaymentTypeUpdateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateResponse;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeWriteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "PAYMENTTYPE", action = "UPDATE")
public class UpdatePaymentTypeCommandHandler implements NewCommandSourceHandler {
@Slf4j
@Component
@RequiredArgsConstructor
public class PaymentTypeUpdateCommandHandler implements CommandHandler<PaymentTypeUpdateRequest, PaymentTypeUpdateResponse> {
private final PaymentTypeWriteService paymentTypeWriteService;
@Autowired
public UpdatePaymentTypeCommandHandler(final PaymentTypeWriteService paymentTypeWriteService) {
this.paymentTypeWriteService = paymentTypeWriteService;
@Retry(name = "commandPaymentTypeUpdate", fallbackMethod = "fallback")
@Override
@Transactional
public PaymentTypeUpdateResponse handle(Command<PaymentTypeUpdateRequest> command) {
return paymentTypeWriteService.updatePaymentType(command.getPayload());
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.paymentTypeWriteService.updatePaymentType(command.entityId(), command);
public PaymentTypeUpdateResponse fallback(Command<PaymentTypeUpdateRequest> command, Throwable t) {
return CommandHandler.super.fallback(command, t);
}
}
@@ -0,0 +1,32 @@
/**
* 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.paymenttype.mapper;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateRequest;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentType;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(config = MapstructMapperConfig.class)
public interface PaymentTypeCreateRequestMapper {
@Mapping(ignore = true, target = "id")
PaymentType map(PaymentTypeCreateRequest source);
}
@@ -21,7 +21,7 @@ package org.apache.fineract.portfolio.paymenttype.service;
import java.util.List;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
public interface PaymentTypeReadPlatformService {
public interface PaymentTypeReadService {
List<PaymentTypeData> retrieveAllPaymentTypes();
@@ -20,47 +20,44 @@ package org.apache.fineract.portfolio.paymenttype.service;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentType;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository;
import org.apache.fineract.portfolio.paymenttype.exception.PaymentTypeNotFoundException;
import org.apache.fineract.portfolio.paymenttype.mapper.PaymentTypeMapper;
import org.springframework.cache.annotation.Cacheable;
@RequiredArgsConstructor
public class PaymentTypeReadPlatformServiceImpl implements PaymentTypeReadPlatformService {
public class PaymentTypeReadServiceImpl implements PaymentTypeReadService {
private final PlatformSecurityContext context;
private final PaymentTypeRepository repository;
private final PaymentTypeMapper paymentTypeMapper;
private final PaymentTypeRepositoryWrapper paymentTypeRepository;
@Override
@Cacheable(value = "payment_types", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public List<PaymentTypeData> retrieveAllPaymentTypes() {
// TODO Auto-generated method stub
this.context.authenticatedUser();
var paymentType = repository.findAllByOrderByPositionAsc();
List<PaymentType> paymentType = this.paymentTypeRepository.findAll();
return this.paymentTypeMapper.map(paymentType);
return paymentTypeMapper.map(paymentType);
}
@Override
@Cacheable(value = "paymentTypesWithCode", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public List<PaymentTypeData> retrieveAllPaymentTypesWithCode() {
// TODO Auto-generated method stub
this.context.authenticatedUser();
var paymentType = repository.findAllByCodeNameIsNotNullOrderByPositionAsc();
List<PaymentType> paymentType = this.paymentTypeRepository.findAllWithCodeName();
return this.paymentTypeMapper.map(paymentType);
return paymentTypeMapper.map(paymentType);
}
@Override
public PaymentTypeData retrieveOne(Long paymentTypeId) {
// TODO Auto-generated method stub
this.context.authenticatedUser();
final var paymentType = repository.findById(paymentTypeId).orElseThrow(() -> new PaymentTypeNotFoundException(paymentTypeId));
final PaymentType paymentType = this.paymentTypeRepository.findOneWithNotFoundDetection(paymentTypeId);
return this.paymentTypeMapper.map(paymentType);
return paymentTypeMapper.map(paymentType);
}
/*
* // TODO: do proper jakarta validation to fineract api error mapping private void
* throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) { if
* (!dataValidationErrors.isEmpty()) { // throw new PlatformApiDataValidationException(dataValidationErrors); } }
*/
}
@@ -18,14 +18,18 @@
*/
package org.apache.fineract.portfolio.paymenttype.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateResponse;
public interface PaymentTypeWriteService {
CommandProcessingResult createPaymentType(JsonCommand command);
PaymentTypeCreateResponse createPaymentType(PaymentTypeCreateRequest request);
CommandProcessingResult updatePaymentType(Long id, JsonCommand command);
PaymentTypeUpdateResponse updatePaymentType(PaymentTypeUpdateRequest request);
CommandProcessingResult deletePaymentType(Long id);
PaymentTypeDeleteResponse deletePaymentType(PaymentTypeDeleteRequest request);
}
@@ -18,18 +18,21 @@
*/
package org.apache.fineract.portfolio.paymenttype.service;
import java.util.Map;
import jakarta.validation.Valid;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
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.commons.lang3.Strings;
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.portfolio.paymenttype.api.PaymentTypeApiResourceConstants;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDataValidator;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentType;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeCreateResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDeleteResponse;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateRequest;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeUpdateResponse;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
import org.apache.fineract.portfolio.paymenttype.exception.PaymentTypeNotFoundException;
import org.apache.fineract.portfolio.paymenttype.mapper.PaymentTypeCreateRequestMapper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.jpa.JpaSystemException;
@@ -38,55 +41,67 @@ import org.springframework.orm.jpa.JpaSystemException;
public class PaymentTypeWriteServiceImpl implements PaymentTypeWriteService {
private final PaymentTypeRepository repository;
private final PaymentTypeRepositoryWrapper repositoryWrapper;
private final PaymentTypeDataValidator fromApiJsonDeserializer;
private final PaymentTypeCreateRequestMapper createRequestMapper;
@Override
@CacheEvict(value = "payment_types", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public CommandProcessingResult createPaymentType(JsonCommand command) {
this.fromApiJsonDeserializer.validateForCreate(command.json());
String name = command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.NAME);
String description = command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.DESCRIPTION);
Boolean isCashPayment = command.booleanObjectValueOfParameterNamed(PaymentTypeApiResourceConstants.ISCASHPAYMENT);
Long position = command.longValueOfParameterNamed(PaymentTypeApiResourceConstants.POSITION);
String codeName = command.stringValueOfParameterNamed(PaymentTypeApiResourceConstants.CODE_NAME);
Boolean isSystemDefined = command.booleanObjectValueOfParameterNamed(PaymentTypeApiResourceConstants.IS_SYSTEM_DEFINED);
if (isSystemDefined == null) {
isSystemDefined = false;
}
public PaymentTypeCreateResponse createPaymentType(@Valid PaymentTypeCreateRequest request) {
final var paymentType = createRequestMapper.map(request);
PaymentType newPaymentType = new PaymentType(name, description, isCashPayment, position, codeName, isSystemDefined);
this.repository.saveAndFlush(newPaymentType);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(newPaymentType.getId()).build();
repository.saveAndFlush(paymentType);
return PaymentTypeCreateResponse.builder().resourceId(paymentType.getId()).build();
}
@Override
@CacheEvict(value = "payment_types", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public CommandProcessingResult updatePaymentType(Long paymentTypeId, JsonCommand command) {
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final PaymentType paymentType = this.repositoryWrapper.findOneWithNotFoundDetection(paymentTypeId);
final Map<String, Object> changes = paymentType.update(command);
if (!changes.isEmpty()) {
this.repository.save(paymentType);
}
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(command.entityId()).build();
}
@Override
@CacheEvict(value = "payment_types", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public CommandProcessingResult deletePaymentType(Long paymentTypeId) {
final PaymentType paymentType = this.repositoryWrapper.findOneWithNotFoundDetection(paymentTypeId);
@SuppressWarnings("AvoidHidingCauseException")
public PaymentTypeUpdateResponse updatePaymentType(@Valid PaymentTypeUpdateRequest request) {
try {
this.repository.delete(paymentType);
this.repository.flush();
final var paymentType = repository.findById(request.getId())
.orElseThrow(() -> new PaymentTypeNotFoundException(request.getId()));
if (!Strings.CS.equals(request.getName(), paymentType.getName())) {
paymentType.setName(request.getName());
}
if (!Strings.CS.equals(request.getDescription(), paymentType.getDescription())) {
paymentType.setDescription(request.getDescription());
}
if (!Strings.CS.equals(request.getCodeName(), paymentType.getCodeName())) {
paymentType.setCodeName(request.getCodeName());
}
if (!Objects.equals(request.getPosition(), paymentType.getPosition())) {
paymentType.setPosition(request.getPosition());
}
if (!Objects.equals(request.getIsCashPayment(), paymentType.getIsCashPayment())) {
paymentType.setIsCashPayment(request.getIsCashPayment());
}
if (!Objects.equals(request.getIsSystemDefined(), paymentType.getIsSystemDefined())) {
paymentType.setIsSystemDefined(request.getIsSystemDefined());
}
repository.saveAndFlush(paymentType);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
throw new PaymentTypeNotFoundException(request.getId());
}
return PaymentTypeUpdateResponse.builder().resourceId(request.getId()).build();
}
@Override
@CacheEvict(value = "payment_types", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('payment_types')")
public PaymentTypeDeleteResponse deletePaymentType(@Valid PaymentTypeDeleteRequest request) {
final var paymentType = repository.findById(request.getId()).orElseThrow(() -> new PaymentTypeNotFoundException(request.getId()));
try {
repository.delete(paymentType);
repository.flush();
} catch (final JpaSystemException | DataIntegrityViolationException e) {
final Throwable throwable = e.getMostSpecificCause();
handleDataIntegrityIssues(throwable, e);
}
return new CommandProcessingResultBuilder().withEntityId(paymentType.getId()).build();
return PaymentTypeDeleteResponse.builder().resourceId(paymentType.getId()).build();
}
private void handleDataIntegrityIssues(final Throwable realCause, final Exception dve) {
@@ -18,13 +18,11 @@
*/
package org.apache.fineract.portfolio.paymenttype.starter;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeDataValidator;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
import org.apache.fineract.portfolio.paymenttype.mapper.PaymentTypeCreateRequestMapper;
import org.apache.fineract.portfolio.paymenttype.mapper.PaymentTypeMapper;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformServiceImpl;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadServiceImpl;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeWriteService;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeWriteServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -35,16 +33,14 @@ import org.springframework.context.annotation.Configuration;
public class PaymentTypeConfiguration {
@Bean
@ConditionalOnMissingBean(PaymentTypeReadPlatformService.class)
PaymentTypeReadPlatformService paymentTypeReadPlatformService(PlatformSecurityContext context, PaymentTypeMapper paymentTypeMapper,
PaymentTypeRepositoryWrapper paymentTypeRepositoryWrapper) {
return new PaymentTypeReadPlatformServiceImpl(context, paymentTypeMapper, paymentTypeRepositoryWrapper);
@ConditionalOnMissingBean(PaymentTypeReadService.class)
PaymentTypeReadService paymentTypeReadPlatformService(PaymentTypeRepository repository, PaymentTypeMapper mapper) {
return new PaymentTypeReadServiceImpl(repository, mapper);
}
@Bean
@ConditionalOnMissingBean(PaymentTypeWriteService.class)
PaymentTypeWriteService paymentTypeWriteService(PaymentTypeRepository repository, PaymentTypeRepositoryWrapper repositoryWrapper,
PaymentTypeDataValidator fromApiJsonDeserializer) {
return new PaymentTypeWriteServiceImpl(repository, repositoryWrapper, fromApiJsonDeserializer);
PaymentTypeWriteService paymentTypeWriteService(PaymentTypeRepository repository, PaymentTypeCreateRequestMapper createRequestMapper) {
return new PaymentTypeWriteServiceImpl(repository, createRequestMapper);
}
}