From 569acdb854344c09590ee43b8d2e333b2ca0ea18 Mon Sep 17 00:00:00 2001 From: aditinikam Date: Fri, 31 Jul 2026 20:43:26 +0530 Subject: [PATCH] FINERACT-2240: migrate Charges to CommandDispatcher Migrate the charge definition module (/v1/charges) to the typed command-processing infrastructure, removing the legacy JsonCommand write path entirely (CQRS-only), following the conventions established by the Staff and Floating Rate modules. Write path - ChargesApiResource POST/PUT/DELETE build typed Charge{Create,Update, Delete}Command and dispatch through CommandDispatcher, returning typed responses; the update response still carries the `changes` map - add ChargeWriteService(+Impl), typed command handlers and request / response DTOs under portfolio.charge.data - applyChanges() lives in the write service rather than on the entity, so the entity no longer consumes DTOs; Charge.fromJson and Charge.update(JsonCommand) are gone - delete ChargeWritePlatformService(+Impl), the @CommandType handlers, the JSON deserializer and the CommandWrapperBuilder charge methods Validation - the programmatic deserializer is replaced by declarative Jakarta Bean Validation: field constraints on the request DTOs plus the class-level @ValidChargeCreate / @ValidChargeUpdate constraints for the cross-field and chargeAppliesTo-driven rules - ChargeUpdateValidator is repository-backed because the legacy path validated the charge state after the update had been applied; it now validates the merged (post-update) values instead - messages live in fineract-validation ValidationMessages.properties Read path - ChargeReadPlatformService is renamed to ChargeReadService, the inline permission checks are dropped and read authorization moves to SecurityConfig matchers alongside the write ones Published API contract - ChargesApiResourceSwagger is retained for the documented GET and PUT schemas (GetChargesResponse, PutChargesChargeIdRequest/Response) and referenced from the @ApiResponse annotations, so the enum description fields and the typed changes map stay in the spec - feeInterval/feeFrequency remain documented as string on the create and update request DTOs, matching the legacy ChargeRequest contract; the Java fields are Integer and Jackson coerces both forms - the previously undocumented `template` query parameter of GET /charges/{chargeId} is now part of the contract The generated client models follow the typed signatures, so the charge operations in the integration and end-to-end tests are updated to ChargeCreateRequest / ChargeCreateResponse / ChargeUpdateRequest / ChargeUpdateResponse / ChargeDeleteResponse / GetChargesResponse; the template endpoint still returns ChargeData. --- fineract-charge/dependencies.gradle | 2 + .../charge/api/ChargesApiResource.java | 101 ++-- .../charge/api/ChargesApiResourceSwagger.java | 122 +---- .../charge/command/ChargeCreateCommand.java | 28 + .../charge/command/ChargeDeleteCommand.java | 28 + .../charge/command/ChargeUpdateCommand.java | 28 + .../charge/data/ChargeCreateRequest.java | 89 ++++ .../ChargeCreateResponse.java} | 23 +- .../ChargeDeleteRequest.java} | 32 +- .../charge/data/ChargeDeleteResponse.java | 38 ++ .../charge/data/ChargeUpdateRequest.java | 104 ++++ .../charge/data/ChargeUpdateResponse.java | 40 ++ .../portfolio/charge/domain/Charge.java | 343 +----------- .../portfolio/charge/domain/ChargeUtils.java | 55 ++ .../handler/ChargeCreateCommandHandler.java | 51 ++ .../handler/ChargeDeleteCommandHandler.java | 51 ++ .../handler/ChargeUpdateCommandHandler.java | 51 ++ .../CreateChargeDefinitionCommandHandler.java | 42 -- .../DeleteChargeDefinitionCommandHandler.java | 42 -- .../UpdateChargeDefinitionCommandHandler.java | 42 -- ...initionCommandFromApiJsonDeserializer.java | 503 ------------------ ...ormService.java => ChargeReadService.java} | 2 +- .../charge/service/ChargeWriteService.java | 38 ++ .../validation/ChargeCreateValidator.java | 138 +++++ .../charge/validation/ChargeRulesChecker.java | 107 ++++ .../validation/ChargeUpdateValidator.java | 189 +++++++ .../charge/validation/ValidChargeCreate.java | 37 ++ .../charge/validation/ValidChargeUpdate.java | 37 ++ .../validation/ChargeValidationTest.java | 393 ++++++++++++++ .../service/CommandWrapperBuilder.java | 25 - .../WorkingCapitalChargeRequestFactory.java | 6 +- ...anProductAdvancedAccountingTestHelper.java | 8 +- .../test/stepdef/loan/ChargeStepDef.java | 6 +- .../loan/WorkingCapitalChargeStepDef.java | 16 +- .../global/ChargeGlobalInitializerStep.java | 15 +- .../features/WorkingCapitalLoanCharge.feature | 12 +- ...ulkImportWorkbookPopulatorServiceImpl.java | 13 +- .../core/config/SecurityConfig.java | 11 + ...WritePlatformServiceJpaRepositoryImpl.java | 4 +- .../OrganisationMonetaryConfiguration.java | 4 +- ...ceImpl.java => ChargeReadServiceImpl.java} | 2 +- ...WritePlatformServiceJpaRepositoryImpl.java | 291 ---------- .../service/ChargeWriteServiceImpl.java | 491 +++++++++++++++++ .../charge/starter/ChargeConfiguration.java | 26 +- .../client/api/ClientChargesApiResource.java | 6 +- .../api/LoanChargesApiResource.java | 6 +- .../loanaccount/api/LoansApiResource.java | 12 +- .../service/LoanReadPlatformServiceImpl.java | 8 +- .../starter/LoanAccountConfiguration.java | 6 +- .../api/LoanProductsApiResource.java | 8 +- .../LoanProductReadPlatformServiceImpl.java | 6 +- .../starter/LoanProductConfiguration.java | 6 +- .../api/FixedDepositProductsApiResource.java | 10 +- .../RecurringDepositProductsApiResource.java | 10 +- .../api/SavingsAccountChargesApiResource.java | 7 +- .../api/SavingsProductsApiResource.java | 10 +- ...DepositAccountReadPlatformServiceImpl.java | 12 +- ...ccountTemplateReadPlatformServiceImpl.java | 16 +- .../savings/starter/SavingsConfiguration.java | 10 +- .../ShareAccountReadPlatformServiceImpl.java | 10 +- .../start/ShareAccountsConfiguration.java | 11 +- .../ShareProductReadPlatformServiceImpl.java | 10 +- .../starter/ShareProductsConfiguration.java | 6 +- ...iResourceRetrieveApprovalTemplateTest.java | 4 +- .../resources/ValidationMessages.properties | 43 ++ .../WorkingCapitalLoanChargesApiResource.java | 6 +- .../AccrualsOnLoanClosureTest.java | 12 +- .../BaseLoanIntegrationTest.java | 6 +- .../integrationtests/ChargesTest.java | 24 +- .../ClientChargeRoundingTest.java | 16 +- .../ClientLoanIntegrationTest.java | 10 +- ...teRespectiveLoanRepaymentScheduleTest.java | 4 +- .../LoanChargeProgressiveTest.java | 6 +- .../LoanChargeRoundingTest.java | 76 +-- .../LoanChargeSpecificDueDateTest.java | 20 +- .../LoanChargeTaxIntegrationTest.java | 26 +- .../LoanChargesMultipleDebitAccountsTest.java | 60 +-- .../LoanInterestRecalculationCOBTest.java | 6 +- ...nRepaymentScheduleWithDownPaymentTest.java | 10 +- ...pecificDueDateChargeAfterMaturityTest.java | 6 +- ...TransactionAccrualActivityPostingTest.java | 8 +- ...nTransactionInterestPaymentWaiverTest.java | 8 +- .../integrationtests/LoanWaiveChargeTest.java | 12 +- .../ProgressiveLoanUndoDisbursementTest.java | 6 +- .../SavingsAccountChargeRoundingTest.java | 24 +- .../ShareAccountChargeRoundingTest.java | 56 +- .../client/feign/FeignLoanTestBase.java | 10 +- .../feign/helpers/FeignChargesHelper.java | 29 +- .../FeignWorkingCapitalLoanHelper.java | 8 +- .../feign/modules/ChargeRequestBuilders.java | 34 +- .../WorkingCapitalLoanRequestBuilders.java | 6 +- .../common/charges/ChargesHelper.java | 12 +- .../reaging/LoanReAgingIntegrationTest.java | 4 +- .../AccountTransferWithdrawalFeeTest.java | 10 +- 94 files changed, 2547 insertions(+), 1871 deletions(-) create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeCreateCommand.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeDeleteCommand.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeUpdateCommand.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateRequest.java rename fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/{service/ChargeWritePlatformService.java => data/ChargeCreateResponse.java} (64%) rename fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/{request/ChargeRequest.java => data/ChargeDeleteRequest.java} (55%) create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteResponse.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateRequest.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateResponse.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/ChargeUtils.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeCreateCommandHandler.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeDeleteCommandHandler.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeUpdateCommandHandler.java delete mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java delete mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java delete mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java delete mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java rename fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/{ChargeReadPlatformService.java => ChargeReadService.java} (98%) create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteService.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeCreateValidator.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeRulesChecker.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeUpdateValidator.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeCreate.java create mode 100644 fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeUpdate.java create mode 100644 fineract-charge/src/test/java/org/apache/fineract/portfolio/charge/validation/ChargeValidationTest.java rename fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/{ChargeReadPlatformServiceImpl.java => ChargeReadServiceImpl.java} (99%) delete mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteServiceImpl.java diff --git a/fineract-charge/dependencies.gradle b/fineract-charge/dependencies.gradle index 13291535f11..d3eb6ba950c 100644 --- a/fineract-charge/dependencies.gradle +++ b/fineract-charge/dependencies.gradle @@ -25,11 +25,13 @@ dependencies { // implementation dependencies are directly used (compiled against) in src/main (and src/test) // implementation(project(path: ':fineract-core')) + implementation(project(path: ':fineract-command')) implementation(project(path: ':fineract-tax')) implementation( 'org.springframework.boot:spring-boot-starter-web', 'org.springframework.boot:spring-boot-starter-security', + 'org.springframework.boot:spring-boot-starter-validation', 'jakarta.ws.rs:jakarta.ws.rs-api', 'org.glassfish.jersey.media:jersey-media-multipart', diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResource.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResource.java index 1caf2f8abfc..d969ec8b86c 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResource.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResource.java @@ -25,6 +25,7 @@ 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.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -34,26 +35,27 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.UriInfo; 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.command.core.CommandDispatcher; import org.apache.fineract.infrastructure.core.annotation.AlternativeOperationId; -import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; -import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.portfolio.charge.command.ChargeCreateCommand; +import org.apache.fineract.portfolio.charge.command.ChargeDeleteCommand; +import org.apache.fineract.portfolio.charge.command.ChargeUpdateCommand; +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeCreateResponse; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.request.ChargeRequest; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteRequest; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteResponse; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateResponse; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.springframework.stereotype.Component; @Path("/v1/charges") +@Produces({ MediaType.APPLICATION_JSON }) @Component @Tag(name = "Charges", description = """ Its typical for MFIs to add extra costs for their financial products. These are typically Fees or Penalties. @@ -64,16 +66,10 @@ @RequiredArgsConstructor public class ChargesApiResource { - private static final String RESOURCE_NAME_FOR_PERMISSIONS = "CHARGE"; - - private final PlatformSecurityContext context; - private final ChargeReadPlatformService readPlatformService; - private final DefaultToApiJsonSerializer toApiJsonSerializer; - private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final CommandDispatcher dispatcher; + private final ChargeReadService chargeReadService; @GET - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve Charges", operationId = "retrieveAllCharges", description = """ Returns the list of defined charges. @@ -81,13 +77,11 @@ public class ChargesApiResource { charges""") public List retrieveAllCharges() { - context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - return readPlatformService.retrieveAllCharges(); + return chargeReadService.retrieveAllCharges(); } @GET @Path("{chargeId}") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve a Charge", operationId = "retrieveOneCharge", description = """ Returns the details of a defined Charge. @@ -97,14 +91,10 @@ public List retrieveAllCharges() { @AlternativeOperationId("retrieveCharge") @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesResponse.class))) public ChargeData retrieveCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId, - @Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - - ChargeData charge = readPlatformService.retrieveCharge(chargeId); - if (settings.isTemplate()) { - final ChargeData templateData = readPlatformService.retrieveNewChargeDetails(charge.getChargeAppliesTo().getId(), + @QueryParam("template") @Parameter(description = "template") final boolean template) { + ChargeData charge = chargeReadService.retrieveCharge(chargeId); + if (template) { + final ChargeData templateData = chargeReadService.retrieveNewChargeDetails(charge.getChargeAppliesTo().getId(), charge.getChargeTimeType().getId()); charge = ChargeData.withTemplate(charge, templateData); } @@ -113,7 +103,6 @@ public ChargeData retrieveCharge(@PathParam("chargeId") @Parameter(description = @GET @Path("template") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve Charge Template", operationId = "retrieveTemplateCharge", description = """ This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of: @@ -126,43 +115,49 @@ public ChargeData retrieveCharge(@PathParam("chargeId") @Parameter(description = @AlternativeOperationId("retrieveNewChargeDetails") public ChargeData retrieveNewChargeDetails(@QueryParam("chargeAppliesTo") Long chargeAppliesTo, @QueryParam("chargeTimeType") Long chargeTimeType) { - context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); - return readPlatformService.retrieveNewChargeDetails(chargeAppliesTo, chargeTimeType); + return chargeReadService.retrieveNewChargeDetails(chargeAppliesTo, chargeTimeType); } @POST @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create/Define a Charge", operationId = "createCharge", description = "Define a new charge that can later be associated with loans and savings through their respective product definitions or directly on each account instance.") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargeRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PostChargesResponse.class))) - public CommandProcessingResult createCharge(@Parameter(hidden = true) ChargeRequest chargeRequest) { - final CommandWrapper commandRequest = new CommandWrapperBuilder().createCharge() - .withJson(toApiJsonSerializer.serialize(chargeRequest)).build(); - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargeCreateResponse.class))) + public ChargeCreateResponse createCharge(@RequestBody(required = true) @Valid final ChargeCreateRequest chargeRequest) { + final ChargeCreateCommand command = new ChargeCreateCommand(); + command.setPayload(chargeRequest); + + final Supplier response = dispatcher.dispatch(command); + + return response.get(); } @PUT @Path("{chargeId}") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update a Charge", operationId = "updateCharge", description = "Updates the details of a Charge.") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargeRequest.class))) @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PutChargesChargeIdResponse.class))) - public CommandProcessingResult updateCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId, - @Parameter(hidden = true) ChargeRequest chargeRequest) { - final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCharge(chargeId) - .withJson(toApiJsonSerializer.serialize(chargeRequest)).build(); - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + public ChargeUpdateResponse updateCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId, + @RequestBody(required = true) @Valid final ChargeUpdateRequest chargeRequest) { + chargeRequest.setId(chargeId); + + final ChargeUpdateCommand command = new ChargeUpdateCommand(); + command.setPayload(chargeRequest); + + final Supplier response = dispatcher.dispatch(command); + + return response.get(); } @DELETE @Path("{chargeId}") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Delete a Charge", operationId = "deleteCharge", description = "Deletes a Charge.") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.DeleteChargesChargeIdResponse.class))) - public CommandProcessingResult deleteCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId) { - final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCharge(chargeId).build(); - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargeDeleteResponse.class))) + public ChargeDeleteResponse deleteCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId) { + final ChargeDeleteCommand command = new ChargeDeleteCommand(); + command.setPayload(new ChargeDeleteRequest(chargeId)); + + final Supplier response = dispatcher.dispatch(command); + + return response.get(); } } diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResourceSwagger.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResourceSwagger.java index ba361810f09..7d40d74535a 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResourceSwagger.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/api/ChargesApiResourceSwagger.java @@ -20,10 +20,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; -import java.util.Set; /** - * Created by Chirag Gupta on 12/01/17. + * Documentation-only schema classes that preserve the published OpenAPI contract of the /v1/charges endpoints. The + * runtime request/response types are the typed DTOs in org.apache.fineract.portfolio.charge.data. */ final class ChargesApiResourceSwagger { @@ -126,58 +126,6 @@ private GetChargesTaxGroup() {} public GetChargesTaxGroup taxGroup; } - @Schema(description = "PostChargesRequest") - public static final class PostChargesRequest { - - private PostChargesRequest() {} - - @Schema(example = "Loan Service fee") - public String name; - @Schema(example = "1") - public Integer chargeAppliesTo; - @Schema(example = "USD") - public String currencyCode; - @Schema(example = "en") - public String locale; - @Schema(example = "230.56") - public Double amount; - @Schema(example = "1") - public Integer chargeTimeType; - @Schema(example = "1") - public Integer chargeCalculationType; - @Schema(example = "1") - public Integer chargePaymentMode; - @Schema(example = "true") - public boolean active; - @Schema(example = "dd MMMM") - public String monthDayFormat; - @Schema(example = "false") - public boolean penalty; - @Schema(example = "23.43") - public BigDecimal minCap; - @Schema(example = "45.56") - public BigDecimal maxCap; - @Schema(example = "1") - public Long taxGroupId; - @Schema(example = "1") - public Integer freeWithdrawalFrequency; - @Schema(example = "10") - public Integer restartCountFrequency; - @Schema(example = "1") - public Integer countFrequencyType; - @Schema(example = "true") - public boolean enableFreeWithdrawalCharge; - } - - @Schema(description = "PostChargesResponse") - public static final class PostChargesResponse { - - private PostChargesResponse() {} - - @Schema(example = "1") - public Long resourceId; - } - @Schema(description = "PutChargesChargeIdRequest") public static final class PutChargesChargeIdRequest { @@ -240,70 +188,4 @@ private PutChargesChargeIdResponse() {} public Long resourceId; public PutChargesChargeIdRequest changes; } - - @Schema(description = "DeleteChargesChargeIdResponse") - public static final class DeleteChargesChargeIdResponse { - - private DeleteChargesChargeIdResponse() {} - - @Schema(example = "1") - public Long resourceId; - } - - @Schema(description = "GetChargesTemplateResponse") - public static final class GetChargesTemplateResponse { - - private GetChargesTemplateResponse() {} - - static final class GetChargesTemplateLoanChargeCalculationTypeOptions { - - private GetChargesTemplateLoanChargeCalculationTypeOptions() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "chargeCalculationType.flat") - public String code; - @Schema(example = "Flat") - public String description; - } - - static final class GetChargesTemplateLoanChargeTimeTypeOptions { - - private GetChargesTemplateLoanChargeTimeTypeOptions() {} - - @Schema(example = "2") - public Long id; - @Schema(example = "chargeTimeType.specifiedDueDate") - public String code; - @Schema(example = "Specified due date") - public String description; - } - - static final class GetChargesTemplateFeeFrequencyOptions { - - private GetChargesTemplateFeeFrequencyOptions() {} - - @Schema(example = "0") - public Long id; - @Schema(example = "loanTermFrequency.periodFrequencyType.days") - public String code; - @Schema(example = "Days") - public String description; - } - - @Schema(example = "false") - public boolean active; - @Schema(example = "false") - public boolean penalty; - public Set currencyOptions; - public Set chargeCalculationTypeOptions; - public Set chargeAppliesToOptions; - public Set chargeTimeTypeOptions; - public Set chargePaymentModeOptions; - public Set loanChargeCalculationTypeOptions; - public Set loanChargeTimeTypeOptions; - public Set savingsChargeCalculationTypeOptions; - public Set savingsChargeTimeTypeOptions; - public Set feeFrequencyOptions; - } } diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeCreateCommand.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeCreateCommand.java new file mode 100644 index 00000000000..59383de0757 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeCreateCommand.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.charge.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChargeCreateCommand extends Command {} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeDeleteCommand.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeDeleteCommand.java new file mode 100644 index 00000000000..78e1f05fe56 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeDeleteCommand.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.charge.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChargeDeleteCommand extends Command {} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeUpdateCommand.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeUpdateCommand.java new file mode 100644 index 00000000000..8502c471b1a --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/command/ChargeUpdateCommand.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.charge.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChargeUpdateCommand extends Command {} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateRequest.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateRequest.java new file mode 100644 index 00000000000..a4064489be5 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateRequest.java @@ -0,0 +1,89 @@ +/** + * 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.charge.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.MonthDay; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fineract.portfolio.charge.domain.ChargeUtils; +import org.apache.fineract.portfolio.charge.validation.ValidChargeCreate; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ValidChargeCreate +public class ChargeCreateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "{org.apache.fineract.portfolio.charge.charge-applies-to.not-null}") + private Integer chargeAppliesTo; + @NotBlank(message = "{org.apache.fineract.portfolio.charge.name.not-blank}") + @Size(max = 100, message = "{org.apache.fineract.portfolio.charge.name.max}") + private String name; + @NotBlank(message = "{org.apache.fineract.portfolio.charge.currency-code.not-blank}") + @Size(max = 3, message = "{org.apache.fineract.portfolio.charge.currency-code.max}") + private String currencyCode; + private Integer chargeTimeType; + @NotNull(message = "{org.apache.fineract.portfolio.charge.charge-calculation-type.not-null}") + private Integer chargeCalculationType; + @NotNull(message = "{org.apache.fineract.portfolio.charge.amount.not-null}") + @Positive(message = "{org.apache.fineract.portfolio.charge.amount.positive}") + private Double amount; + private Boolean active; + private Boolean penalty; + private Integer chargePaymentMode; + private String monthDayFormat; + private String locale; + private String feeOnMonthDay; + // documented as string to preserve the published API contract (legacy ChargeRequest exposed these as strings) + @Schema(type = "string", example = "1") + @Positive(message = "{org.apache.fineract.portfolio.charge.fee-interval.positive}") + private Integer feeInterval; + @Schema(type = "string", example = "1") + @Min(value = 0, message = "{org.apache.fineract.portfolio.charge.fee-frequency.range}") + @Max(value = 3, message = "{org.apache.fineract.portfolio.charge.fee-frequency.range}") + private Integer feeFrequency; + @Positive(message = "{org.apache.fineract.portfolio.charge.payment-type-id.positive}") + private Long paymentTypeId; + private Boolean enablePaymentType; + @Positive(message = "{org.apache.fineract.portfolio.charge.min-cap.positive}") + private BigDecimal minCap; + @Positive(message = "{org.apache.fineract.portfolio.charge.max-cap.positive}") + private BigDecimal maxCap; + @Positive(message = "{org.apache.fineract.portfolio.charge.tax-group-id.positive}") + private Long taxGroupId; + + public MonthDay feeOnMonthDayAsMonthDay() { + return ChargeUtils.parseMonthDay(this.feeOnMonthDay, this.monthDayFormat, this.locale); + } + +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformService.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateResponse.java similarity index 64% rename from fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformService.java rename to fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateResponse.java index c157173f5a5..1dd706827a3 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformService.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeCreateResponse.java @@ -16,16 +16,23 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.charge.service; +package org.apache.fineract.portfolio.charge.data; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; -public interface ChargeWritePlatformService { +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ChargeCreateResponse implements Serializable { - CommandProcessingResult createCharge(JsonCommand command); + @Serial + private static final long serialVersionUID = 1L; - CommandProcessingResult updateCharge(Long chargeId, JsonCommand command); - - CommandProcessingResult deleteCharge(Long chargeId); + private Long resourceId; } diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/request/ChargeRequest.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteRequest.java similarity index 55% rename from fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/request/ChargeRequest.java rename to fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteRequest.java index 2fde7d37e10..a1d7b386e91 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/request/ChargeRequest.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteRequest.java @@ -16,41 +16,23 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.charge.request; +package org.apache.fineract.portfolio.charge.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.Data; import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; @Data @NoArgsConstructor -@Accessors(chain = true) -public class ChargeRequest implements Serializable { +@AllArgsConstructor +public class ChargeDeleteRequest implements Serializable { @Serial private static final long serialVersionUID = 1L; - private Integer chargeAppliesTo; - private String name; - private String currencyCode; - private Integer chargeTimeType; - private Integer chargeCalculationType; - private Double amount; - private Boolean active; - private Boolean penalty; - private Integer chargePaymentMode; - private String monthDayFormat; - private String locale; - private String feeOnMonthDay; - private String feeInterval; - private String feeFrequency; - private Long paymentTypeId; - private Boolean enablePaymentType; - private BigDecimal minCap; - private BigDecimal maxCap; - private Long taxGroupId; - + @Schema(hidden = true) + private Long id; } diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteResponse.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteResponse.java new file mode 100644 index 00000000000..f7e10843406 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeDeleteResponse.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.charge.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 ChargeDeleteResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateRequest.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateRequest.java new file mode 100644 index 00000000000..9cc5764de58 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateRequest.java @@ -0,0 +1,104 @@ +/** + * 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.charge.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.MonthDay; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fineract.portfolio.charge.domain.ChargeUtils; +import org.apache.fineract.portfolio.charge.validation.ValidChargeUpdate; + +/** + * Payload for updating an existing charge definition. It is intentionally a distinct type from + * {@link ChargeCreateRequest} (and does NOT extend it) so the {@code CommandDispatcher} can route create vs. update by + * payload type. All fields are optional (PATCH semantics): only the values that are provided (non-null) are applied. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ValidChargeUpdate +public class ChargeUpdateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(hidden = true) + private Long id; + private Integer chargeAppliesTo; + @Pattern(regexp = ".*\\S.*", message = "{org.apache.fineract.portfolio.charge.name.not-blank}") + @Size(max = 100, message = "{org.apache.fineract.portfolio.charge.name.max}") + private String name; + @Pattern(regexp = ".*\\S.*", message = "{org.apache.fineract.portfolio.charge.currency-code.not-blank}") + @Size(max = 3, message = "{org.apache.fineract.portfolio.charge.currency-code.max}") + private String currencyCode; + private Integer chargeTimeType; + @Min(value = 1, message = "{org.apache.fineract.portfolio.charge.charge-calculation-type.range}") + @Max(value = 5, message = "{org.apache.fineract.portfolio.charge.charge-calculation-type.range}") + private Integer chargeCalculationType; + @Positive(message = "{org.apache.fineract.portfolio.charge.amount.positive}") + private Double amount; + private Boolean active; + private Boolean penalty; + @Min(value = 0, message = "{org.apache.fineract.portfolio.charge.charge-payment-mode.range}") + @Max(value = 1, message = "{org.apache.fineract.portfolio.charge.charge-payment-mode.range}") + private Integer chargePaymentMode; + private String monthDayFormat; + private String locale; + private String feeOnMonthDay; + // documented as string to preserve the published API contract (legacy ChargeRequest exposed these as strings) + @Schema(type = "string", example = "1") + @Positive(message = "{org.apache.fineract.portfolio.charge.fee-interval.positive}") + private Integer feeInterval; + @Schema(type = "string", example = "1") + @Min(value = 0, message = "{org.apache.fineract.portfolio.charge.fee-frequency.range}") + @Max(value = 3, message = "{org.apache.fineract.portfolio.charge.fee-frequency.range}") + private Integer feeFrequency; + private Boolean enableFreeWithdrawalCharge; + @Positive(message = "{org.apache.fineract.portfolio.charge.free-withdrawal-frequency.positive}") + private Integer freeWithdrawalFrequency; + @Positive(message = "{org.apache.fineract.portfolio.charge.restart-count-frequency.positive}") + private Integer restartCountFrequency; + private Integer countFrequencyType; + @Positive(message = "{org.apache.fineract.portfolio.charge.payment-type-id.positive}") + private Long paymentTypeId; + private Boolean enablePaymentType; + @Positive(message = "{org.apache.fineract.portfolio.charge.min-cap.positive}") + private BigDecimal minCap; + @Positive(message = "{org.apache.fineract.portfolio.charge.max-cap.positive}") + private BigDecimal maxCap; + @Positive(message = "{org.apache.fineract.portfolio.charge.income-account-id.positive}") + private Long incomeAccountId; + @Positive(message = "{org.apache.fineract.portfolio.charge.tax-group-id.positive}") + private Long taxGroupId; + + public MonthDay feeOnMonthDayAsMonthDay() { + return ChargeUtils.parseMonthDay(this.feeOnMonthDay, this.monthDayFormat, this.locale); + } + +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateResponse.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateResponse.java new file mode 100644 index 00000000000..5b65d244a16 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/data/ChargeUpdateResponse.java @@ -0,0 +1,40 @@ +/** + * 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.charge.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ChargeUpdateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; + private Map changes; +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java index 49921eaabd0..ae00708fed9 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/Charge.java @@ -28,16 +28,12 @@ import java.math.BigDecimal; import java.time.MonthDay; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.apache.fineract.accounting.glaccount.data.GLAccountData; import org.apache.fineract.accounting.glaccount.domain.GLAccount; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.data.EnumOptionData; @@ -45,11 +41,9 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.monetary.data.CurrencyData; -import org.apache.fineract.portfolio.charge.api.ChargesApiConstants; import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException; import org.apache.fineract.portfolio.charge.exception.ChargeMustBePenaltyException; -import org.apache.fineract.portfolio.charge.exception.ChargeParameterUpdateNotSupportedException; import org.apache.fineract.portfolio.charge.service.ChargeEnumerations; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData; @@ -68,77 +62,101 @@ public class Charge extends AbstractPersistableCustom { public static final String LOCALE_PARAM_NAME = "locale"; public static final String FEE_FREQUENCY_PARAM_NAME = "feeFrequency"; + @Setter @Getter @Column(name = "name", length = 100) private String name; + @Setter @Getter @Column(name = "amount", scale = 6, precision = 19, nullable = false) private BigDecimal amount; + @Setter @Getter @Column(name = "currency_code", length = 3) private String currencyCode; + @Getter @Column(name = "charge_applies_to_enum", nullable = false) private Integer chargeAppliesTo; + @Setter @Getter @Column(name = "charge_time_enum", nullable = false) private Integer chargeTimeType; + @Setter @Getter @Column(name = "charge_calculation_enum") private Integer chargeCalculation; + @Setter @Getter @Column(name = "charge_payment_mode_enum") private Integer chargePaymentMode; + @Setter + @Getter @Column(name = "fee_on_day") private Integer feeOnDay; + @Setter @Getter @Column(name = "fee_interval") private Integer feeInterval; + @Setter + @Getter @Column(name = "fee_on_month") private Integer feeOnMonth; + @Setter @Column(name = "is_penalty", nullable = false) private boolean penalty; + @Setter @Column(name = "is_active", nullable = false) private boolean active; @Column(name = "is_deleted", nullable = false) private boolean deleted = false; + @Setter @Getter @Column(name = "min_cap", scale = 6, precision = 19) private BigDecimal minCap; + @Setter @Getter @Column(name = "max_cap", scale = 6, precision = 19) private BigDecimal maxCap; + @Setter + @Getter @Column(name = "fee_frequency", nullable = true) private Integer feeFrequency; + @Setter @Column(name = "is_free_withdrawal", nullable = false) private boolean enableFreeWithdrawal; + @Setter + @Getter @Column(name = "free_withdrawal_charge_frequency") private Integer freeWithdrawalFrequency; + @Setter @Getter @Column(name = "restart_frequency") private Integer restartFrequency; + @Setter @Getter @Column(name = "restart_frequency_enum") private Integer restartFrequencyEnum; + @Setter @Column(name = "is_payment_type", nullable = false) private boolean enablePaymentType; @@ -160,56 +178,9 @@ public class Charge extends AbstractPersistableCustom { @JoinColumn(name = "tax_group_id") private TaxGroup taxGroup; - public static Charge fromJson(final JsonCommand command, final GLAccount account, final TaxGroup taxGroup, - final PaymentType paymentType) { - - final String name = command.stringValueOfParameterNamed("name"); - final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount"); - final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); - - final ChargeAppliesTo chargeAppliesTo = ChargeAppliesTo.fromInt(command.integerValueOfParameterNamed("chargeAppliesTo")); - final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.integerValueOfParameterNamed(CHARGE_TIME_PARAM_NAME)); - final ChargeCalculationType chargeCalculationType = ChargeCalculationType - .fromInt(command.integerValueOfParameterNamed(CHARGE_CALCULATION_TYPE_PARAM_NAME)); - final Integer chargePaymentMode = command.integerValueOfParameterNamed("chargePaymentMode"); - - final ChargePaymentMode paymentMode = chargePaymentMode == null - ? (chargeAppliesTo.isWorkingCapitalLoanCharge() ? ChargePaymentMode.REGULAR : null) - : ChargePaymentMode.fromInt(chargePaymentMode); - - final boolean penalty = command.booleanPrimitiveValueOfParameterNamed("penalty"); - final boolean active = command.booleanPrimitiveValueOfParameterNamed("active"); - final MonthDay feeOnMonthDay = command.extractMonthDayNamed(FEE_ON_MONTH_DAY_PARAM_NAME); - final Integer feeInterval = command.integerValueOfParameterNamed(FEE_INTERVAL_PARAM_NAME); - final BigDecimal minCap = command.bigDecimalValueOfParameterNamed("minCap"); - final BigDecimal maxCap = command.bigDecimalValueOfParameterNamed("maxCap"); - final Integer feeFrequency = command.integerValueOfParameterNamed(FEE_FREQUENCY_PARAM_NAME); - - boolean enableFreeWithdrawalCharge = false; - enableFreeWithdrawalCharge = command.booleanPrimitiveValueOfParameterNamed("enableFreeWithdrawalCharge"); - - boolean enablePaymentType = false; - enablePaymentType = command.booleanPrimitiveValueOfParameterNamed("enablePaymentType"); - - Integer freeWithdrawalFrequency = null; - Integer restartCountFrequency = null; - PeriodFrequencyType countFrequencyType = null; - - if (enableFreeWithdrawalCharge) { - freeWithdrawalFrequency = command.integerValueOfParameterNamed("freeWithdrawalFrequency"); - restartCountFrequency = command.integerValueOfParameterNamed("restartCountFrequency"); - - countFrequencyType = PeriodFrequencyType.fromInt(command.integerValueOfParameterNamed("countFrequencyType")); - } - - return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode, - feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, enableFreeWithdrawalCharge, freeWithdrawalFrequency, - restartCountFrequency, countFrequencyType, account, taxGroup, enablePaymentType, paymentType); - } - protected Charge() {} - private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo, + public Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo, final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active, final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final BigDecimal minCap, final BigDecimal maxCap, final Integer feeFrequency, final boolean enableFreeWithdrawalCharge, @@ -361,7 +332,7 @@ public Integer getFrequencyFreeWithdrawalCharge() { return this.freeWithdrawalFrequency; } - private Long getPaymentTypeId() { + public Long getPaymentTypeId() { Long paymentTypeId = null; if (this.paymentType != null) { paymentTypeId = this.paymentType.getId(); @@ -369,266 +340,6 @@ private Long getPaymentTypeId() { return paymentTypeId; } - public Map update(final JsonCommand command) { - final Map actualChanges = new LinkedHashMap<>(7); - - final Locale locale = command.extractLocale(); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges"); - - final String nameParamName = "name"; - if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { - final String newValue = command.stringValueOfParameterNamed(nameParamName); - actualChanges.put(nameParamName, newValue); - this.name = newValue; - } - - final String currencyCodeParamName = "currencyCode"; - if (command.isChangeInStringParameterNamed(currencyCodeParamName, this.currencyCode)) { - final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName); - actualChanges.put(currencyCodeParamName, newValue); - this.currencyCode = newValue; - } - - final String amountParamName = "amount"; - if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName, locale); - actualChanges.put(amountParamName, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.amount = newValue; - } - - if (command.isChangeInIntegerParameterNamed(CHARGE_TIME_PARAM_NAME, this.chargeTimeType)) { - final Integer newValue = command.integerValueOfParameterNamed(CHARGE_TIME_PARAM_NAME); - actualChanges.put(CHARGE_TIME_PARAM_NAME, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.chargeTimeType = ChargeTimeType.fromInt(newValue).getValue(); - - if (isSavingsCharge()) { - if (!isAllowedSavingsChargeTime()) { - baseDataValidator.reset().parameter(CHARGE_TIME_PARAM_NAME).value(this.chargeTimeType) - .failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings"); - } - // if charge time is changed to monthly then validate for - // feeOnMonthDay and feeInterval - if (isMonthlyFee()) { - final MonthDay monthDay = command.extractMonthDayNamed(FEE_ON_MONTH_DAY_PARAM_NAME); - baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY_PARAM_NAME).value(monthDay).notNull(); - - final Integer feeInterval = command.integerValueOfParameterNamed(FEE_INTERVAL_PARAM_NAME); - baseDataValidator.reset().parameter(FEE_INTERVAL_PARAM_NAME).value(feeInterval).notNull().inMinMaxRange(1, 12); - } - } else if (isLoanCharge()) { - if (!isAllowedLoanChargeTime()) { - baseDataValidator.reset().parameter(CHARGE_TIME_PARAM_NAME).value(this.chargeTimeType) - .failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan"); - } - } else if (ChargeAppliesTo.WORKING_CAPITAL_LOAN.getValue().equals(this.chargeAppliesTo)) { - baseDataValidator.reset().parameter(CHARGE_TIME_PARAM_NAME).value(chargeTimeType).notNull() - .isOneOfTheseValues(ChargeTimeType.validWorkingCapitalLoanValues()); - - Object[] validCalculationTypeValues = new Object[] {}; - if (ChargeTimeType.SPECIFIED_DUE_DATE.getValue().equals(chargeTimeType)) { - validCalculationTypeValues = ChargeCalculationType.validValuesForWorkingCapitalLoanSpecifiedDueDate(); - } - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE_PARAM_NAME).value(chargeCalculation).notNull() - .isOneOfTheseValues(validCalculationTypeValues); - - } else if (isClientCharge() && !isAllowedLoanChargeTime()) { - baseDataValidator.reset().parameter(CHARGE_TIME_PARAM_NAME).value(this.chargeTimeType) - .failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.client"); - } - } - - final String freeWithdrawalFrequencyParamName = "freeWithdrawalFrequency"; - if (command.isChangeInIntegerParameterNamed(freeWithdrawalFrequencyParamName, this.freeWithdrawalFrequency)) { - final Integer enableFreeWithdrawalChargeNewValue = command.integerValueOfParameterNamed(freeWithdrawalFrequencyParamName); - actualChanges.put(freeWithdrawalFrequencyParamName, enableFreeWithdrawalChargeNewValue); - this.freeWithdrawalFrequency = enableFreeWithdrawalChargeNewValue; - } - - final String restartCountFrequencyParamName = "restartCountFrequency"; - if (command.isChangeInIntegerParameterNamed(restartCountFrequencyParamName, this.restartFrequency)) { - final Integer restartCountFrequencyNewValue = command.integerValueOfParameterNamed(restartCountFrequencyParamName); - actualChanges.put(restartCountFrequencyParamName, restartCountFrequencyNewValue); - this.restartFrequency = restartCountFrequencyNewValue; - } - - final String countFrequencyTypeParamName = "countFrequencyType"; - if (command.isChangeInIntegerParameterNamed(countFrequencyTypeParamName, this.restartFrequencyEnum)) { - final Integer countFrequencyTypeNewValue = command.integerValueOfParameterNamed(countFrequencyTypeParamName); - actualChanges.put(countFrequencyTypeParamName, countFrequencyTypeNewValue); - this.restartFrequencyEnum = ChargeTimeType.fromInt(countFrequencyTypeNewValue).getValue(); - } - - final String enableFreeWithdrawalChargeParamName = "enableFreeWithdrawalCharge"; - if (command.isChangeInBooleanParameterNamed(enableFreeWithdrawalChargeParamName, this.enableFreeWithdrawal)) { - final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enableFreeWithdrawalChargeParamName); - actualChanges.put(enableFreeWithdrawalChargeParamName, newValue); - this.enableFreeWithdrawal = newValue; - - } - - final String enablePaymentTypeParamName = "enablePaymentType"; - if (command.isChangeInBooleanParameterNamed(enablePaymentTypeParamName, this.enablePaymentType)) { - final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enablePaymentTypeParamName); - actualChanges.put(enablePaymentTypeParamName, newValue); - this.enablePaymentType = newValue; - } - - final String paymentTypeParamName = "paymentTypeId"; - if (command.isChangeInLongParameterNamed(paymentTypeParamName, getPaymentTypeId())) { - final Long newValue = command.longValueOfParameterNamed(paymentTypeParamName); - actualChanges.put(paymentTypeParamName, newValue); - } - - final String chargeAppliesToParamName = "chargeAppliesTo"; - if (command.isChangeInIntegerParameterNamed(chargeAppliesToParamName, this.chargeAppliesTo)) { - /* - * final Integer newValue = command.integerValueOfParameterNamed(chargeAppliesToParamName); - * actualChanges.put(chargeAppliesToParamName, newValue); actualChanges.put("locale", localeAsInput); - * this.chargeAppliesTo = ChargeAppliesTo.fromInt(newValue).getValue(); - */ - - // AA: Do not allow to change chargeAppliesTo. - final String errorMessage = "Update of Charge applies to is not supported"; - throw new ChargeParameterUpdateNotSupportedException("charge.applies.to", errorMessage); - } - - if (command.isChangeInIntegerParameterNamed(CHARGE_CALCULATION_TYPE_PARAM_NAME, this.chargeCalculation)) { - final Integer newValue = command.integerValueOfParameterNamed(CHARGE_CALCULATION_TYPE_PARAM_NAME); - actualChanges.put(CHARGE_CALCULATION_TYPE_PARAM_NAME, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue(); - - if (isSavingsCharge()) { - if (!isAllowedSavingsChargeCalculationType()) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE_PARAM_NAME).value(this.chargeCalculation) - .failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings"); - } - - if (!(ChargeTimeType.fromInt(getChargeTimeType()).isWithdrawalFee() - || ChargeTimeType.fromInt(getChargeTimeType()).isSavingsNoActivityFee()) - && ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE_PARAM_NAME).value(this.chargeCalculation) - .failWithCodeNoParameterAddedToErrorCode( - "charge.calculation.type.percentage.allowed.only.for.withdrawal.or.noactivity"); - } - } else if (isClientCharge()) { - if (!isAllowedClientChargeCalculationType()) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE_PARAM_NAME).value(this.chargeCalculation) - .failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.client"); - } - } - } - - // validate only for loan charge - if (isLoanCharge()) { - final String paymentModeParamName = "chargePaymentMode"; - if (command.isChangeInIntegerParameterNamed(paymentModeParamName, this.chargePaymentMode)) { - final Integer newValue = command.integerValueOfParameterNamed(paymentModeParamName); - actualChanges.put(paymentModeParamName, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.chargePaymentMode = ChargePaymentMode.fromInt(newValue).getValue(); - } - } - - if (command.hasParameter(FEE_ON_MONTH_DAY_PARAM_NAME)) { - final MonthDay monthDay = command.extractMonthDayNamed(FEE_ON_MONTH_DAY_PARAM_NAME); - final String actualValueEntered = command.stringValueOfParameterNamed(FEE_ON_MONTH_DAY_PARAM_NAME); - final Integer dayOfMonthValue = monthDay.getDayOfMonth(); - if (!this.feeOnDay.equals(dayOfMonthValue)) { - actualChanges.put(FEE_ON_MONTH_DAY_PARAM_NAME, actualValueEntered); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.feeOnDay = dayOfMonthValue; - } - - final Integer monthOfYear = monthDay.getMonthValue(); - if (!this.feeOnMonth.equals(monthOfYear)) { - actualChanges.put(FEE_ON_MONTH_DAY_PARAM_NAME, actualValueEntered); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.feeOnMonth = monthOfYear; - } - } - - if (command.isChangeInIntegerParameterNamed(FEE_INTERVAL_PARAM_NAME, this.feeInterval)) { - final Integer newValue = command.integerValueOfParameterNamed(FEE_INTERVAL_PARAM_NAME); - actualChanges.put(FEE_INTERVAL_PARAM_NAME, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.feeInterval = newValue; - } - - if (command.isChangeInIntegerParameterNamed(FEE_FREQUENCY_PARAM_NAME, this.feeFrequency)) { - final Integer newValue = command.integerValueOfParameterNamed(FEE_FREQUENCY_PARAM_NAME); - actualChanges.put(FEE_FREQUENCY_PARAM_NAME, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.feeFrequency = newValue; - } - - if (this.feeFrequency != null) { - baseDataValidator.reset().parameter(FEE_INTERVAL_PARAM_NAME).value(this.feeInterval).notNull(); - } - - final String penaltyParamName = "penalty"; - if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) { - final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(penaltyParamName); - actualChanges.put(penaltyParamName, newValue); - this.penalty = newValue; - } - - final String activeParamName = "active"; - if (command.isChangeInBooleanParameterNamed(activeParamName, this.active)) { - final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(activeParamName); - actualChanges.put(activeParamName, newValue); - this.active = newValue; - } - // allow min and max cap to be only added to PERCENT_OF_AMOUNT for now - if (isPercentageOfApprovedAmount()) { - final String minCapParamName = "minCap"; - if (command.isChangeInBigDecimalParameterNamed(minCapParamName, this.minCap)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minCapParamName); - actualChanges.put(minCapParamName, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.minCap = newValue; - } - final String maxCapParamName = "maxCap"; - if (command.isChangeInBigDecimalParameterNamed(maxCapParamName, this.maxCap)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxCapParamName); - actualChanges.put(maxCapParamName, newValue); - actualChanges.put(LOCALE_PARAM_NAME, locale.getLanguage()); - this.maxCap = newValue; - } - - } - - if (this.penalty && ChargeTimeType.fromInt(this.chargeTimeType).isTimeOfDisbursement()) { - throw new ChargeDueAtDisbursementCannotBePenaltyException(this.name); - } - if (!penalty && ChargeTimeType.fromInt(this.chargeTimeType).isOverdueInstallment()) { - throw new ChargeMustBePenaltyException(name); - } - - if (command.isChangeInLongParameterNamed(ChargesApiConstants.glAccountIdParamName, getIncomeAccountId())) { - final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName); - actualChanges.put(ChargesApiConstants.glAccountIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ChargesApiConstants.taxGroupIdParamName, getTaxGroupId())) { - final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.taxGroupIdParamName); - actualChanges.put(ChargesApiConstants.taxGroupIdParamName, newValue); - if (taxGroup != null) { - baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).failWithCode("modification.not.supported"); - } - } - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - - return actualChanges; - } - /** * Delete is a soft delete. Updates flag on charge so it won't appear in query/report results. * @@ -709,7 +420,7 @@ public Long getIncomeAccountId() { return incomeAccountId; } - private Long getTaxGroupId() { + public Long getTaxGroupId() { Long taxGroupId = null; if (this.taxGroup != null) { taxGroupId = this.taxGroup.getId(); diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/ChargeUtils.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/ChargeUtils.java new file mode 100644 index 00000000000..b05a1be2d32 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/domain/ChargeUtils.java @@ -0,0 +1,55 @@ +/** + * 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.charge.domain; + +import java.time.DateTimeException; +import java.time.MonthDay; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.ResolverStyle; +import java.util.Locale; +import org.apache.commons.lang3.LocaleUtils; +import org.apache.commons.lang3.StringUtils; + +public final class ChargeUtils { + + private ChargeUtils() {} + + /** + * Parses a {@code feeOnMonthDay} value (e.g. "04 March") using the supplied {@code monthDayFormat} (e.g. "dd MMM") + * and locale. Mirrors the lenient, case-insensitive parsing previously performed by the JSON command helper so the + * typed write path keeps identical behaviour. + * + * @return the parsed month/day, or {@code null} when the value is blank or cannot be parsed. Callers that need to + * reject unparseable input do so through Bean Validation, so this never throws. + */ + public static MonthDay parseMonthDay(final String value, final String monthDayFormat, final String locale) { + if (StringUtils.isBlank(value) || StringUtils.isBlank(monthDayFormat)) { + return null; + } + try { + final Locale clientApplicationLocale = StringUtils.isBlank(locale) ? Locale.getDefault() : LocaleUtils.toLocale(locale); + final DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient() + .appendPattern(monthDayFormat).toFormatter(clientApplicationLocale).withResolverStyle(ResolverStyle.STRICT); + return MonthDay.parse(value, formatter); + } catch (final IllegalArgumentException | DateTimeException e) { + return null; + } + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeCreateCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeCreateCommandHandler.java new file mode 100644 index 00000000000..eb92923b7c8 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeCreateCommandHandler.java @@ -0,0 +1,51 @@ +/** + * 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.charge.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.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeCreateResponse; +import org.apache.fineract.portfolio.charge.service.ChargeWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ChargeCreateCommandHandler implements CommandHandler { + + private final ChargeWriteService writeService; + + @Retry(name = "commandChargeCreate", fallbackMethod = "fallback") + @Override + @Transactional + public ChargeCreateResponse handle(Command command) { + return writeService.create(command.getPayload()); + } + + @Override + public ChargeCreateResponse fallback(Command command, Throwable t) { + // NOTE: fallback method needs to be in the same class + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeDeleteCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeDeleteCommandHandler.java new file mode 100644 index 00000000000..d1f02989987 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeDeleteCommandHandler.java @@ -0,0 +1,51 @@ +/** + * 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.charge.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.charge.data.ChargeDeleteRequest; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteResponse; +import org.apache.fineract.portfolio.charge.service.ChargeWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ChargeDeleteCommandHandler implements CommandHandler { + + private final ChargeWriteService writeService; + + @Retry(name = "commandChargeDelete", fallbackMethod = "fallback") + @Override + @Transactional + public ChargeDeleteResponse handle(Command command) { + return writeService.delete(command.getPayload()); + } + + @Override + public ChargeDeleteResponse fallback(Command command, Throwable t) { + // NOTE: fallback method needs to be in the same class + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeUpdateCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeUpdateCommandHandler.java new file mode 100644 index 00000000000..095bbbd469e --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/ChargeUpdateCommandHandler.java @@ -0,0 +1,51 @@ +/** + * 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.charge.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.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateResponse; +import org.apache.fineract.portfolio.charge.service.ChargeWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ChargeUpdateCommandHandler implements CommandHandler { + + private final ChargeWriteService writeService; + + @Retry(name = "commandChargeUpdate", fallbackMethod = "fallback") + @Override + @Transactional + public ChargeUpdateResponse handle(Command command) { + return writeService.update(command.getPayload()); + } + + @Override + public ChargeUpdateResponse fallback(Command command, Throwable t) { + // NOTE: fallback method needs to be in the same class + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java deleted file mode 100644 index c5ee1586eaa..00000000000 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java +++ /dev/null @@ -1,42 +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.charge.handler; - -import lombok.RequiredArgsConstructor; -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.charge.service.ChargeWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@RequiredArgsConstructor -@Service -@CommandType(entity = "CHARGE", action = "CREATE") -public class CreateChargeDefinitionCommandHandler implements NewCommandSourceHandler { - - private final ChargeWritePlatformService clientWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.clientWritePlatformService.createCharge(command); - } -} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java deleted file mode 100644 index e97fb278a39..00000000000 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java +++ /dev/null @@ -1,42 +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.charge.handler; - -import lombok.RequiredArgsConstructor; -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.charge.service.ChargeWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@RequiredArgsConstructor -@Service -@CommandType(entity = "CHARGE", action = "DELETE") -public class DeleteChargeDefinitionCommandHandler implements NewCommandSourceHandler { - - private final ChargeWritePlatformService clientWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.clientWritePlatformService.deleteCharge(command.entityId()); - } -} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java deleted file mode 100644 index 537255b9e95..00000000000 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java +++ /dev/null @@ -1,42 +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.charge.handler; - -import lombok.RequiredArgsConstructor; -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.charge.service.ChargeWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@RequiredArgsConstructor -@Service -@CommandType(entity = "CHARGE", action = "UPDATE") -public class UpdateChargeDefinitionCommandHandler implements NewCommandSourceHandler { - - private final ChargeWritePlatformService clientWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.clientWritePlatformService.updateCharge(command.entityId(), command); - } -} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java deleted file mode 100644 index b95e4da8eb7..00000000000 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java +++ /dev/null @@ -1,503 +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.charge.serialization; - -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.time.MonthDay; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -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.charge.api.ChargesApiConstants; -import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; -import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; -import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; -import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public final class ChargeDefinitionCommandFromApiJsonDeserializer { - - public static final String NAME = "name"; - public static final String AMOUNT = "amount"; - public static final String LOCALE = "locale"; - public static final String CURRENCY_CODE = "currencyCode"; - public static final String PENALTY = "penalty"; - public static final String CHARGE_CALCULATION_TYPE_OPTIONS = "chargeCalculationTypeOptions"; - public static final String CHARGE_CALCULATION_TYPE = "chargeCalculationType"; - public static final String CHARGE_TIME_TYPE = "chargeTimeType"; - public static final String CHARGE_APPLIES_TO = "chargeAppliesTo"; - public static final String CURRENCY_OPTIONS = "currencyOptions"; - public static final String ACTIVE = "active"; - public static final String CHARGE_PAYMENT_MODE = "chargePaymentMode"; - public static final String FEE_ON_MONTH_DAY = "feeOnMonthDay"; - public static final String FEE_INTERVAL = "feeInterval"; - public static final String MONTH_DAY_FORMAT = "monthDayFormat"; - public static final String MIN_CAP = "minCap"; - public static final String MAX_CAP = "maxCap"; - public static final String FEE_FREQUENCY = "feeFrequency"; - public static final String ENABLE_FREE_WITHDRAWAL_CHARGE = "enableFreeWithdrawalCharge"; - public static final String FREE_WITHDRAWAL_FREQUENCY = "freeWithdrawalFrequency"; - public static final String RESTART_COUNT_FREQUENCY = "restartCountFrequency"; - public static final String COUNT_FREQUENCY_TYPE = "countFrequencyType"; - public static final String ENABLE_PAYMENT_TYPE = "enablePaymentType"; - public static final String PAYMENT_TYPE_ID = "paymentTypeId"; - public static final String CHARGE = "charge"; - /** - * The parameters supported for this command. - */ - private static final Set SUPPORTED_PARAMETERS = new HashSet<>(Arrays.asList(NAME, AMOUNT, LOCALE, CURRENCY_CODE, - CURRENCY_OPTIONS, CHARGE_APPLIES_TO, CHARGE_TIME_TYPE, CHARGE_CALCULATION_TYPE, CHARGE_CALCULATION_TYPE_OPTIONS, PENALTY, - ACTIVE, CHARGE_PAYMENT_MODE, FEE_ON_MONTH_DAY, FEE_INTERVAL, MONTH_DAY_FORMAT, MIN_CAP, MAX_CAP, FEE_FREQUENCY, - ENABLE_FREE_WITHDRAWAL_CHARGE, FREE_WITHDRAWAL_FREQUENCY, RESTART_COUNT_FREQUENCY, COUNT_FREQUENCY_TYPE, PAYMENT_TYPE_ID, - ENABLE_PAYMENT_TYPE, ChargesApiConstants.glAccountIdParamName, ChargesApiConstants.taxGroupIdParamName)); - private final FromJsonHelper fromApiJsonHelper; - - @Autowired - public ChargeDefinitionCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromApiJsonHelper = fromApiJsonHelper; - } - - public void validateForCreate(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() { - - }.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element); - baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull(); - if (chargeAppliesTo != null) { - baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).isOneOfTheseValues(ChargeAppliesTo.validValues()); - } - - final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_CALCULATION_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType).notNull(); - - final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(FEE_INTERVAL, element, Locale.getDefault()); - baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).integerGreaterThanZero(); - - final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed(FEE_FREQUENCY, element, Locale.getDefault()); - baseDataValidator.reset().parameter(FEE_FREQUENCY).value(feeFrequency).inMinMaxRange(0, 3); - - if (this.fromApiJsonHelper.parameterExists(ENABLE_FREE_WITHDRAWAL_CHARGE, element)) { - - final Boolean enableFreeWithdrawalCharge = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_FREE_WITHDRAWAL_CHARGE, element); - baseDataValidator.reset().parameter(ENABLE_FREE_WITHDRAWAL_CHARGE).value(enableFreeWithdrawalCharge).notNull(); - - if (enableFreeWithdrawalCharge) { - - final Integer freeWithdrawalFrequency = this.fromApiJsonHelper.extractIntegerNamed(FREE_WITHDRAWAL_FREQUENCY, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(FREE_WITHDRAWAL_FREQUENCY).value(freeWithdrawalFrequency).integerGreaterThanZero(); - - final Integer restartCountFrequency = this.fromApiJsonHelper.extractIntegerNamed(RESTART_COUNT_FREQUENCY, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(RESTART_COUNT_FREQUENCY).value(restartCountFrequency).integerGreaterThanZero(); - - final Integer countFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(COUNT_FREQUENCY_TYPE, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(COUNT_FREQUENCY_TYPE).value(countFrequencyType); - - } - } - - if (this.fromApiJsonHelper.parameterExists(ENABLE_PAYMENT_TYPE, element)) { - - final boolean enablePaymentType = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_PAYMENT_TYPE, element); - baseDataValidator.reset().parameter(ENABLE_PAYMENT_TYPE).value(enablePaymentType).notNull(); - - if (enablePaymentType) { - final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerNamed(PAYMENT_TYPE_ID, element, Locale.getDefault()); - baseDataValidator.reset().parameter(PAYMENT_TYPE_ID).value(paymentTypeId).integerGreaterThanZero(); - } - } - - if (feeFrequency != null) { - baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).notNull(); - } - - final ChargeAppliesTo appliesTo = ChargeAppliesTo.fromInt(chargeAppliesTo); - if (appliesTo.isLoanCharge()) { - // loan applicable validation - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull(); - if (chargeTimeType != null) { - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType) - .isOneOfTheseValues(ChargeTimeType.validLoanValues()); - } - - final Integer chargePaymentMode = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_PAYMENT_MODE, element); - baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode).notNull() - .isOneOfTheseValues(ChargePaymentMode.validValues()); - if (chargePaymentMode != null) { - baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode) - .isOneOfTheseValues(ChargePaymentMode.validValues()); - } - - if (chargeCalculationType != null) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForLoan()); - } - - if (chargeTimeType != null && chargeCalculationType != null) { - performChargeTimeNCalculationTypeValidation(baseDataValidator, chargeTimeType, chargeCalculationType); - } - - } else if (appliesTo.isSavingsCharge()) { - // savings applicable validation - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull(); - if (chargeTimeType != null) { - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType) - .isOneOfTheseValues(ChargeTimeType.validSavingsValues()); - } - - final ChargeTimeType ctt = ChargeTimeType.fromInt(chargeTimeType); - - if (ctt.isWeeklyFee()) { - final String monthDay = this.fromApiJsonHelper.extractStringNamed(FEE_ON_MONTH_DAY, element); - baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).mustBeBlankWhenParameterProvidedIs(CHARGE_TIME_TYPE, - chargeTimeType); - } - - if (ctt.isMonthlyFee()) { - final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element); - baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull(); - - baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).notNull().inMinMaxRange(1, 12); - } - - if (ctt.isAnnualFee()) { - final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element); - baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull(); - } - - if (chargeCalculationType != null) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForSavings()); - } - - } else if (appliesTo.isClientCharge()) { - // client applicable validation - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull(); - if (chargeTimeType != null) { - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType) - .isOneOfTheseValues(ChargeTimeType.validClientValues()); - } - - if (chargeCalculationType != null) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForClients()); - } - - // GL Account can be linked to clients - if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) { - final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element); - baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull() - .longGreaterThanZero(); - } - - } else if (appliesTo.isSharesCharge()) { - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull(); - if (chargeTimeType != null) { - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType) - .isOneOfTheseValues(ChargeTimeType.validShareValues()); - } - - if (chargeCalculationType != null) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForShares()); - } - - if (chargeTimeType != null && chargeTimeType.equals(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue()) - && chargeCalculationType != null) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForShareAccountActivation()); - } - } else if (appliesTo.isWorkingCapitalLoanCharge()) { - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull(); - - if (chargeTimeType != null) { - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType) - .isOneOfTheseValues(ChargeTimeType.validWorkingCapitalLoanValues()); - } - - if (chargeCalculationType != null) { - Object[] validValues = new Object[] {}; - if (ChargeTimeType.SPECIFIED_DUE_DATE.getValue().equals(chargeTimeType)) { - validValues = ChargeCalculationType.validValuesForWorkingCapitalLoanSpecifiedDueDate(); - } - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType).isOneOfTheseValues(validValues); - } - } - - final String name = this.fromApiJsonHelper.extractStringNamed(NAME, element); - baseDataValidator.reset().parameter(NAME).value(name).notBlank().notExceedingLengthOf(100); - - final String currencyCode = this.fromApiJsonHelper.extractStringNamed(CURRENCY_CODE, element); - baseDataValidator.reset().parameter(CURRENCY_CODE).value(currencyCode).notBlank().notExceedingLengthOf(3); - - final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(AMOUNT, element.getAsJsonObject()); - baseDataValidator.reset().parameter(AMOUNT).value(amount).notNull().positiveAmount(); - - if (this.fromApiJsonHelper.parameterExists(PENALTY, element)) { - final Boolean penalty = this.fromApiJsonHelper.extractBooleanNamed(PENALTY, element); - baseDataValidator.reset().parameter(PENALTY).value(penalty).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(ACTIVE, element)) { - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ACTIVE, element); - baseDataValidator.reset().parameter(ACTIVE).value(active).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) { - final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount(); - } - if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) { - final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount(); - } - - if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.taxGroupIdParamName, element)) { - final Long taxGroupId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.taxGroupIdParamName, element); - baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).value(taxGroupId).notNull().longGreaterThanZero(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUpdate(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() { - - }.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - - if (this.fromApiJsonHelper.parameterExists(NAME, element)) { - final String name = this.fromApiJsonHelper.extractStringNamed(NAME, element); - baseDataValidator.reset().parameter(NAME).value(name).notBlank().notExceedingLengthOf(100); - } - - if (this.fromApiJsonHelper.parameterExists(CURRENCY_CODE, element)) { - final String currencyCode = this.fromApiJsonHelper.extractStringNamed(CURRENCY_CODE, element); - baseDataValidator.reset().parameter(CURRENCY_CODE).value(currencyCode).notBlank().notExceedingLengthOf(3); - } - - if (this.fromApiJsonHelper.parameterExists(AMOUNT, element)) { - final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(AMOUNT, element.getAsJsonObject()); - baseDataValidator.reset().parameter(AMOUNT).value(amount).notNull().positiveAmount(); - } - - if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) { - final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount(); - } - - if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) { - final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount(); - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) { - final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element); - baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull() - .isOneOfTheseValues(ChargeAppliesTo.validValues()); - } - - Boolean enableFreeWithdrawalCharge = false; - if (this.fromApiJsonHelper.parameterExists(ENABLE_FREE_WITHDRAWAL_CHARGE, element)) { - enableFreeWithdrawalCharge = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_FREE_WITHDRAWAL_CHARGE, element); - baseDataValidator.reset().parameter(ENABLE_FREE_WITHDRAWAL_CHARGE).value(enableFreeWithdrawalCharge).notNull(); - - if (enableFreeWithdrawalCharge) { - - final Integer freeWithdrawalFrequency = this.fromApiJsonHelper.extractIntegerNamed(FREE_WITHDRAWAL_FREQUENCY, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(FREE_WITHDRAWAL_FREQUENCY).value(freeWithdrawalFrequency).integerGreaterThanZero(); - - final Integer restartCountFrequency = this.fromApiJsonHelper.extractIntegerNamed(RESTART_COUNT_FREQUENCY, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(RESTART_COUNT_FREQUENCY).value(restartCountFrequency).integerGreaterThanZero(); - - final Integer countFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(COUNT_FREQUENCY_TYPE, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(COUNT_FREQUENCY_TYPE).value(countFrequencyType); - } - - Boolean enablePaymentType = false; - if (this.fromApiJsonHelper.parameterExists(ENABLE_PAYMENT_TYPE, element)) { - enablePaymentType = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_PAYMENT_TYPE, element); - baseDataValidator.reset().parameter(ENABLE_PAYMENT_TYPE).value(enablePaymentType).notNull(); - - if (enablePaymentType) { - final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerNamed(PAYMENT_TYPE_ID, element, Locale.getDefault()); - baseDataValidator.reset().parameter(PAYMENT_TYPE_ID).value(paymentTypeId).integerGreaterThanZero(); - } - } - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) { - final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element); - baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull() - .isOneOfTheseValues(ChargeAppliesTo.validValues()); - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) { - final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element); - baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull() - .isOneOfTheseValues(ChargeAppliesTo.validValues()); - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_TIME_TYPE, element)) { - - final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element); - - final Collection validLoanValues = Arrays.asList(ChargeTimeType.validLoanValues()); - final Collection validSavingsValues = Arrays.asList(ChargeTimeType.validSavingsValues()); - final Collection validClientValues = Arrays.asList(ChargeTimeType.validClientValues()); - final Collection validShareValues = Arrays.asList(ChargeTimeType.validShareValues()); - final Collection allValidValues = new ArrayList<>(validLoanValues); - allValidValues.addAll(validSavingsValues); - allValidValues.addAll(validClientValues); - allValidValues.addAll(validShareValues); - baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull() - .isOneOfTheseValues(allValidValues.toArray(new Object[allValidValues.size()])); - } - - if (this.fromApiJsonHelper.parameterExists(FEE_ON_MONTH_DAY, element)) { - final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element); - baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(FEE_INTERVAL, element)) { - final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(FEE_INTERVAL, element, Locale.getDefault()); - baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).integerGreaterThanZero(); - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_CALCULATION_TYPE, element)) { - final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerNamed(CHARGE_CALCULATION_TYPE, element, - Locale.getDefault()); - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType).notNull().inMinMaxRange(1, 5); - } - - if (this.fromApiJsonHelper.parameterExists(CHARGE_PAYMENT_MODE, element)) { - final Integer chargePaymentMode = this.fromApiJsonHelper.extractIntegerNamed(CHARGE_PAYMENT_MODE, element, Locale.getDefault()); - baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode).notNull().inMinMaxRange(0, 1); - } - - if (this.fromApiJsonHelper.parameterExists(PENALTY, element)) { - final Boolean penalty = this.fromApiJsonHelper.extractBooleanNamed(PENALTY, element); - baseDataValidator.reset().parameter(PENALTY).value(penalty).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(ACTIVE, element)) { - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ACTIVE, element); - baseDataValidator.reset().parameter(ACTIVE).value(active).notNull(); - } - if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) { - final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount(); - } - if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) { - final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject()); - baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount(); - } - if (this.fromApiJsonHelper.parameterExists(FEE_FREQUENCY, element)) { - final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed(FEE_FREQUENCY, element, Locale.getDefault()); - baseDataValidator.reset().parameter(FEE_FREQUENCY).value(feeFrequency).inMinMaxRange(0, 3); - } - - if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) { - final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element); - baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull() - .longGreaterThanZero(); - } - - if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.taxGroupIdParamName, element)) { - final Long taxGroupId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.taxGroupIdParamName, element); - baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).value(taxGroupId).notNull().longGreaterThanZero(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateChargeTimeNCalculationType(Integer chargeTimeType, Integer chargeCalculationType) { - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE); - performChargeTimeNCalculationTypeValidation(baseDataValidator, chargeTimeType, chargeCalculationType); - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - private void performChargeTimeNCalculationTypeValidation(DataValidatorBuilder baseDataValidator, final Integer chargeTimeType, - final Integer chargeCalculationType) { - if (chargeTimeType.equals(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue())) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForShareAccountActivation()); - } - - if (chargeTimeType.equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue())) { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isOneOfTheseValues(ChargeCalculationType.validValuesForTrancheDisbursement()); - } else { - baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType) - .isNotOneOfTheseValues(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue()); - } - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } -} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformService.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadService.java similarity index 98% rename from fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformService.java rename to fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadService.java index 61110348565..266b6d24dea 100644 --- a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformService.java +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadService.java @@ -22,7 +22,7 @@ import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; -public interface ChargeReadPlatformService { +public interface ChargeReadService { List retrieveAllCharges(); diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteService.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteService.java new file mode 100644 index 00000000000..94de121720f --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteService.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.charge.service; + +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeCreateResponse; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteRequest; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteResponse; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateResponse; + +/** + * Strongly typed, JsonCommand-free write service backing the command-dispatcher path for charge definitions. + */ +public interface ChargeWriteService { + + ChargeCreateResponse create(ChargeCreateRequest request); + + ChargeUpdateResponse update(ChargeUpdateRequest request); + + ChargeDeleteResponse delete(ChargeDeleteRequest request); +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeCreateValidator.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeCreateValidator.java new file mode 100644 index 00000000000..d0f78115400 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeCreateValidator.java @@ -0,0 +1,138 @@ +/** + * 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.charge.validation; + +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_APPLIES_TO; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_CALCULATION_TYPE; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_PAYMENT_MODE; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_TIME_TYPE; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.FEE_INTERVAL; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.FEE_ON_MONTH_DAY; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.checkChargeTimeAndCalculationType; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.isOneOf; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.validChargeCalculationValuesFor; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.validChargeTimeValuesFor; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.violation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; +import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; +import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; +import org.springframework.stereotype.Component; + +@Component +final class ChargeCreateValidator implements ConstraintValidator { + + private static final String MSG_PREFIX = "{org.apache.fineract.portfolio.charge."; + + @Override + public boolean isValid(final ChargeCreateRequest request, final ConstraintValidatorContext context) { + if (request == null) { + return true; + } + context.disableDefaultConstraintViolation(); + boolean valid = true; + + final Integer chargeAppliesTo = request.getChargeAppliesTo(); + final ChargeAppliesTo appliesTo = ChargeAppliesTo.fromInt(chargeAppliesTo); + if (chargeAppliesTo != null && appliesTo == ChargeAppliesTo.INVALID) { + // an unknown chargeAppliesTo makes every dependent rule below meaningless, so report it and stop + return violation(context, MSG_PREFIX + "charge-applies-to.invalid}", CHARGE_APPLIES_TO); + } + + valid &= checkFeeFrequency(request, context); + valid &= checkFeeOnMonthDay(request, context); + + if (appliesTo == ChargeAppliesTo.INVALID) { + return valid; + } + + final Integer chargeTimeType = request.getChargeTimeType(); + if (chargeTimeType == null) { + valid = violation(context, MSG_PREFIX + "charge-time-type.not-null}", CHARGE_TIME_TYPE); + } else if (!isOneOf(chargeTimeType, validChargeTimeValuesFor(chargeAppliesTo))) { + valid = violation(context, MSG_PREFIX + "charge-time-type.invalid}", CHARGE_TIME_TYPE); + } + + final Integer chargeCalculationType = request.getChargeCalculationType(); + if (chargeCalculationType != null + && !isOneOf(chargeCalculationType, validChargeCalculationValuesFor(chargeAppliesTo, chargeTimeType))) { + valid = violation(context, MSG_PREFIX + "charge-calculation-type.invalid}", CHARGE_CALCULATION_TYPE); + } + + if (appliesTo.isLoanCharge()) { + valid &= checkLoanCharge(request, context); + } else if (appliesTo.isSavingsCharge()) { + valid &= checkSavingsCharge(request, chargeTimeType, context); + } + + return valid; + } + + private boolean checkLoanCharge(final ChargeCreateRequest request, final ConstraintValidatorContext context) { + boolean valid = true; + final Integer chargePaymentMode = request.getChargePaymentMode(); + if (chargePaymentMode == null) { + valid = violation(context, MSG_PREFIX + "charge-payment-mode.not-null}", CHARGE_PAYMENT_MODE); + } else if (!isOneOf(chargePaymentMode, ChargePaymentMode.validValues())) { + valid = violation(context, MSG_PREFIX + "charge-payment-mode.invalid}", CHARGE_PAYMENT_MODE); + } + valid &= checkChargeTimeAndCalculationType(request.getChargeTimeType(), request.getChargeCalculationType(), context); + return valid; + } + + private boolean checkSavingsCharge(final ChargeCreateRequest request, final Integer chargeTimeType, + final ConstraintValidatorContext context) { + final ChargeTimeType timeType = ChargeTimeType.fromInt(chargeTimeType); + boolean valid = true; + + if (timeType.isWeeklyFee() && StringUtils.isNotBlank(request.getFeeOnMonthDay())) { + valid = violation(context, MSG_PREFIX + "fee-on-month-day.not-supported}", FEE_ON_MONTH_DAY); + } + + if (timeType.isMonthlyFee() || timeType.isAnnualFee()) { + if (request.feeOnMonthDayAsMonthDay() == null) { + valid = violation(context, MSG_PREFIX + "fee-on-month-day.not-null}", FEE_ON_MONTH_DAY); + } + if (timeType.isMonthlyFee()) { + final Integer feeInterval = request.getFeeInterval(); + if (feeInterval == null) { + valid = violation(context, MSG_PREFIX + "fee-interval.not-null}", FEE_INTERVAL); + } else if (feeInterval < 1 || feeInterval > 12) { + valid = violation(context, MSG_PREFIX + "fee-interval.monthly-range}", FEE_INTERVAL); + } + } + } + return valid; + } + + private boolean checkFeeFrequency(final ChargeCreateRequest request, final ConstraintValidatorContext context) { + // a fee frequency is only meaningful together with the interval it repeats over + return request.getFeeFrequency() == null || request.getFeeInterval() != null + || violation(context, MSG_PREFIX + "fee-interval.not-null}", FEE_INTERVAL); + } + + private boolean checkFeeOnMonthDay(final ChargeCreateRequest request, final ConstraintValidatorContext context) { + return StringUtils.isBlank(request.getFeeOnMonthDay()) || request.feeOnMonthDayAsMonthDay() != null + || violation(context, MSG_PREFIX + "fee-on-month-day.invalid}", FEE_ON_MONTH_DAY); + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeRulesChecker.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeRulesChecker.java new file mode 100644 index 00000000000..97581a4ad35 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeRulesChecker.java @@ -0,0 +1,107 @@ +/** + * 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.charge.validation; + +import jakarta.validation.ConstraintValidatorContext; +import java.util.Arrays; +import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; +import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; +import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; + +/** + * Charge rules shared by the create and update charge constraints. + */ +final class ChargeRulesChecker { + + static final String CHARGE_APPLIES_TO = "chargeAppliesTo"; + static final String CHARGE_TIME_TYPE = "chargeTimeType"; + static final String CHARGE_CALCULATION_TYPE = "chargeCalculationType"; + static final String CHARGE_PAYMENT_MODE = "chargePaymentMode"; + static final String FEE_ON_MONTH_DAY = "feeOnMonthDay"; + static final String FEE_INTERVAL = "feeInterval"; + static final String TAX_GROUP_ID = "taxGroupId"; + + private static final String MSG_PREFIX = "{org.apache.fineract.portfolio.charge."; + + private ChargeRulesChecker() {} + + /** + * Mirrors the legacy {@code performChargeTimeNCalculationTypeValidation}, which the legacy write service ran + * against the charge state after the update had been applied. Callers therefore pass the effective + * (post-update) values. + */ + static boolean checkChargeTimeAndCalculationType(final Integer chargeTimeType, final Integer chargeCalculationType, + final ConstraintValidatorContext context) { + if (chargeTimeType == null || chargeCalculationType == null) { + return true; + } + if (chargeTimeType.equals(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue())) { + return isOneOf(chargeCalculationType, ChargeCalculationType.validValuesForShareAccountActivation()) || violation(context, + MSG_PREFIX + "charge-calculation-type.invalid-for-share-account-activation}", CHARGE_CALCULATION_TYPE); + } + if (chargeTimeType.equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue())) { + return isOneOf(chargeCalculationType, ChargeCalculationType.validValuesForTrancheDisbursement()) || violation(context, + MSG_PREFIX + "charge-calculation-type.invalid-for-tranche-disbursement}", CHARGE_CALCULATION_TYPE); + } + return !chargeCalculationType.equals(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue()) + || violation(context, MSG_PREFIX + "charge-calculation-type.percent-of-disbursement-not-allowed}", CHARGE_CALCULATION_TYPE); + } + + /** + * The charge time / calculation type combinations permitted for a given {@code chargeAppliesTo}. + */ + static Object[] validChargeTimeValuesFor(final Integer chargeAppliesTo) { + return switch (ChargeAppliesTo.fromInt(chargeAppliesTo)) { + case LOAN -> ChargeTimeType.validLoanValues(); + case SAVINGS -> ChargeTimeType.validSavingsValues(); + case CLIENT -> ChargeTimeType.validClientValues(); + case SHARES -> ChargeTimeType.validShareValues(); + case WORKING_CAPITAL_LOAN -> ChargeTimeType.validWorkingCapitalLoanValues(); + case INVALID -> new Object[] {}; + }; + } + + static Object[] validChargeCalculationValuesFor(final Integer chargeAppliesTo, final Integer chargeTimeType) { + return switch (ChargeAppliesTo.fromInt(chargeAppliesTo)) { + case LOAN -> ChargeCalculationType.validValuesForLoan(); + case SAVINGS -> ChargeCalculationType.validValuesForSavings(); + case CLIENT -> ChargeCalculationType.validValuesForClients(); + case SHARES -> ChargeCalculationType.validValuesForShares(); + // the legacy validator only permitted a calculation type for working capital loan specified-due-date + // charges + case WORKING_CAPITAL_LOAN -> ChargeTimeType.SPECIFIED_DUE_DATE.getValue().equals(chargeTimeType) + ? ChargeCalculationType.validValuesForWorkingCapitalLoanSpecifiedDueDate() + : new Object[] {}; + case INVALID -> new Object[] {}; + }; + } + + static boolean isOneOf(final Object value, final Object[] validValues) { + return value != null && Arrays.asList(validValues).contains(value); + } + + /** + * Records a constraint violation on {@code property} and always returns {@code false}, so callers can write + * {@code condition || violation(...)}. + */ + static boolean violation(final ConstraintValidatorContext context, final String template, final String property) { + context.buildConstraintViolationWithTemplate(template).addPropertyNode(property).addConstraintViolation(); + return false; + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeUpdateValidator.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeUpdateValidator.java new file mode 100644 index 00000000000..530488d1e2d --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ChargeUpdateValidator.java @@ -0,0 +1,189 @@ +/** + * 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.charge.validation; + +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_APPLIES_TO; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_CALCULATION_TYPE; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.CHARGE_TIME_TYPE; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.FEE_INTERVAL; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.FEE_ON_MONTH_DAY; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.TAX_GROUP_ID; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.checkChargeTimeAndCalculationType; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.isOneOf; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.validChargeCalculationValuesFor; +import static org.apache.fineract.portfolio.charge.validation.ChargeRulesChecker.violation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.domain.Charge; +import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; +import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; +import org.apache.fineract.portfolio.charge.domain.ChargeRepository; +import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; +import org.springframework.stereotype.Component; + +/** + * Validates a charge update against the merged state — the values the charge will have once the (partial) + * request has been applied — which is why it needs the persisted charge. The legacy write path achieved the same by + * mutating the entity first and validating afterwards. + */ +@RequiredArgsConstructor +@Component +final class ChargeUpdateValidator implements ConstraintValidator { + + private static final String MSG_PREFIX = "{org.apache.fineract.portfolio.charge."; + + private final ChargeRepository chargeRepository; + + @Override + public boolean isValid(final ChargeUpdateRequest request, final ConstraintValidatorContext context) { + if (request == null || request.getId() == null) { + // the resource-level @Valid pass runs before the path id is bound; the id-aware pass happens in the + // write service + return true; + } + final Charge charge = this.chargeRepository.findById(request.getId()).orElse(null); + if (charge == null) { + // a missing charge is reported as a not-found error by the write service + return true; + } + context.disableDefaultConstraintViolation(); + boolean valid = true; + + if (request.getChargeAppliesTo() != null && ChargeAppliesTo.fromInt(request.getChargeAppliesTo()) == ChargeAppliesTo.INVALID) { + valid = violation(context, MSG_PREFIX + "charge-applies-to.invalid}", CHARGE_APPLIES_TO); + } + + final Integer effectiveChargeTimeType = request.getChargeTimeType() != null ? request.getChargeTimeType() + : charge.getChargeTimeType(); + final Integer effectiveChargeCalculationType = request.getChargeCalculationType() != null ? request.getChargeCalculationType() + : charge.getChargeCalculation(); + final Integer effectiveFeeInterval = request.getFeeInterval() != null ? request.getFeeInterval() : charge.getFeeInterval(); + final Integer effectiveFeeFrequency = request.getFeeFrequency() != null ? request.getFeeFrequency() : charge.getFeeFrequency(); + + if (StringUtils.isNotBlank(request.getFeeOnMonthDay()) && request.feeOnMonthDayAsMonthDay() == null) { + valid = violation(context, MSG_PREFIX + "fee-on-month-day.invalid}", FEE_ON_MONTH_DAY); + } + + if (effectiveFeeFrequency != null && effectiveFeeInterval == null) { + valid = violation(context, MSG_PREFIX + "fee-interval.not-null}", FEE_INTERVAL); + } + + if (request.getChargeTimeType() != null && !isOneOf(request.getChargeTimeType(), allChargeTimeValues())) { + valid = violation(context, MSG_PREFIX + "charge-time-type.invalid}", CHARGE_TIME_TYPE); + } + + if (isChanged(request.getChargeTimeType(), charge.getChargeTimeType())) { + valid &= checkChangedChargeTimeType(request, charge, effectiveChargeTimeType, effectiveChargeCalculationType, + effectiveFeeInterval, context); + } + + if (isChanged(request.getChargeCalculationType(), charge.getChargeCalculation())) { + valid &= checkChangedChargeCalculationType(charge, effectiveChargeTimeType, effectiveChargeCalculationType, context); + } + + valid &= checkChargeTimeAndCalculationType(effectiveChargeTimeType, effectiveChargeCalculationType, context); + + if (isChanged(request.getTaxGroupId(), charge.getTaxGroup() == null ? null : charge.getTaxGroup().getId()) + && charge.getTaxGroup() != null) { + valid = violation(context, MSG_PREFIX + "tax-group-id.modification-not-supported}", TAX_GROUP_ID); + } + + return valid; + } + + private boolean checkChangedChargeTimeType(final ChargeUpdateRequest request, final Charge charge, + final Integer effectiveChargeTimeType, final Integer effectiveChargeCalculationType, final Integer effectiveFeeInterval, + final ConstraintValidatorContext context) { + final ChargeTimeType timeType = ChargeTimeType.fromInt(effectiveChargeTimeType); + boolean valid = true; + + if (charge.isSavingsCharge()) { + if (!timeType.isAllowedSavingsChargeTime()) { + valid = violation(context, MSG_PREFIX + "charge-time-type.not-allowed-for-savings}", CHARGE_TIME_TYPE); + } + // when the charge time becomes monthly, feeOnMonthDay and feeInterval become mandatory + if (timeType.isMonthlyFee()) { + if (request.feeOnMonthDayAsMonthDay() == null) { + valid = violation(context, MSG_PREFIX + "fee-on-month-day.not-null}", FEE_ON_MONTH_DAY); + } + if (effectiveFeeInterval == null) { + valid = violation(context, MSG_PREFIX + "fee-interval.not-null}", FEE_INTERVAL); + } else if (effectiveFeeInterval < 1 || effectiveFeeInterval > 12) { + valid = violation(context, MSG_PREFIX + "fee-interval.monthly-range}", FEE_INTERVAL); + } + } + } else if (charge.isLoanCharge()) { + if (!timeType.isAllowedLoanChargeTime()) { + valid = violation(context, MSG_PREFIX + "charge-time-type.not-allowed-for-loan}", CHARGE_TIME_TYPE); + } + } else if (ChargeAppliesTo.WORKING_CAPITAL_LOAN.getValue().equals(charge.getChargeAppliesTo())) { + if (!isOneOf(effectiveChargeTimeType, ChargeTimeType.validWorkingCapitalLoanValues())) { + valid = violation(context, MSG_PREFIX + "charge-time-type.invalid}", CHARGE_TIME_TYPE); + } + if (!isOneOf(effectiveChargeCalculationType, + validChargeCalculationValuesFor(charge.getChargeAppliesTo(), effectiveChargeTimeType))) { + valid = violation(context, MSG_PREFIX + "charge-calculation-type.invalid}", CHARGE_CALCULATION_TYPE); + } + } else if (charge.isClientCharge() && !timeType.isAllowedLoanChargeTime()) { + // NOTE: the legacy update path checked the loan (not the client) charge times here; kept as-is + valid = violation(context, MSG_PREFIX + "charge-time-type.not-allowed-for-client}", CHARGE_TIME_TYPE); + } + return valid; + } + + private boolean checkChangedChargeCalculationType(final Charge charge, final Integer effectiveChargeTimeType, + final Integer effectiveChargeCalculationType, final ConstraintValidatorContext context) { + final ChargeCalculationType calculationType = ChargeCalculationType.fromInt(effectiveChargeCalculationType); + final ChargeTimeType timeType = ChargeTimeType.fromInt(effectiveChargeTimeType); + boolean valid = true; + + if (charge.isSavingsCharge()) { + if (!calculationType.isAllowedSavingsChargeCalculationType()) { + valid = violation(context, MSG_PREFIX + "charge-calculation-type.not-allowed-for-savings}", CHARGE_CALCULATION_TYPE); + } + if (!(timeType.isWithdrawalFee() || timeType.isSavingsNoActivityFee()) && calculationType.isPercentageOfAmount()) { + valid = violation(context, MSG_PREFIX + "charge-calculation-type.percentage-only-for-withdrawal-or-no-activity}", + CHARGE_CALCULATION_TYPE); + } + } else if (charge.isClientCharge() && !calculationType.isAllowedClientChargeCalculationType()) { + valid = violation(context, MSG_PREFIX + "charge-calculation-type.not-allowed-for-client}", CHARGE_CALCULATION_TYPE); + } + return valid; + } + + private static boolean isChanged(final Object requestValue, final Object currentValue) { + return requestValue != null && !Objects.equals(requestValue, currentValue); + } + + private static Object[] allChargeTimeValues() { + final Collection allValidValues = new ArrayList<>(Arrays.asList(ChargeTimeType.validLoanValues())); + allValidValues.addAll(Arrays.asList(ChargeTimeType.validSavingsValues())); + allValidValues.addAll(Arrays.asList(ChargeTimeType.validClientValues())); + allValidValues.addAll(Arrays.asList(ChargeTimeType.validShareValues())); + return allValidValues.toArray(new Object[0]); + } +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeCreate.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeCreate.java new file mode 100644 index 00000000000..c5bc9775499 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeCreate.java @@ -0,0 +1,37 @@ +/** + * 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.charge.validation; + +import jakarta.validation.Constraint; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ChargeCreateValidator.class) +public @interface ValidChargeCreate { + + String message() default "Charge create request is not valid"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeUpdate.java b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeUpdate.java new file mode 100644 index 00000000000..80c70246010 --- /dev/null +++ b/fineract-charge/src/main/java/org/apache/fineract/portfolio/charge/validation/ValidChargeUpdate.java @@ -0,0 +1,37 @@ +/** + * 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.charge.validation; + +import jakarta.validation.Constraint; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ChargeUpdateValidator.class) +public @interface ValidChargeUpdate { + + String message() default "Charge update request is not valid"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fineract-charge/src/test/java/org/apache/fineract/portfolio/charge/validation/ChargeValidationTest.java b/fineract-charge/src/test/java/org/apache/fineract/portfolio/charge/validation/ChargeValidationTest.java new file mode 100644 index 00000000000..4a919c84b41 --- /dev/null +++ b/fineract-charge/src/test/java/org/apache/fineract/portfolio/charge/validation/ChargeValidationTest.java @@ -0,0 +1,393 @@ +/** + * 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.charge.validation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorFactory; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import java.math.BigDecimal; +import java.time.MonthDay; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.domain.Charge; +import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; +import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; +import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; +import org.apache.fineract.portfolio.charge.domain.ChargeRepository; +import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +public class ChargeValidationTest { + + private static final String PREFIX = "{org.apache.fineract.portfolio.charge."; + private static final String NAME_NOT_BLANK = PREFIX + "name.not-blank}"; + private static final String AMOUNT_POSITIVE = PREFIX + "amount.positive}"; + private static final String CHARGE_APPLIES_TO_NOT_NULL = PREFIX + "charge-applies-to.not-null}"; + private static final String CHARGE_APPLIES_TO_INVALID = PREFIX + "charge-applies-to.invalid}"; + private static final String CHARGE_TIME_TYPE_NOT_NULL = PREFIX + "charge-time-type.not-null}"; + private static final String CHARGE_TIME_TYPE_INVALID = PREFIX + "charge-time-type.invalid}"; + private static final String CHARGE_TIME_TYPE_NOT_ALLOWED_FOR_LOAN = PREFIX + "charge-time-type.not-allowed-for-loan}"; + private static final String CHARGE_CALCULATION_TYPE_INVALID = PREFIX + "charge-calculation-type.invalid}"; + private static final String CHARGE_CALCULATION_TYPE_PERCENTAGE_ONLY = PREFIX + + "charge-calculation-type.percentage-only-for-withdrawal-or-no-activity}"; + private static final String CHARGE_CALCULATION_TYPE_INVALID_FOR_TRANCHE = PREFIX + + "charge-calculation-type.invalid-for-tranche-disbursement}"; + private static final String CHARGE_PAYMENT_MODE_NOT_NULL = PREFIX + "charge-payment-mode.not-null}"; + private static final String FEE_ON_MONTH_DAY_NOT_NULL = PREFIX + "fee-on-month-day.not-null}"; + private static final String FEE_ON_MONTH_DAY_INVALID = PREFIX + "fee-on-month-day.invalid}"; + private static final String FEE_ON_MONTH_DAY_NOT_SUPPORTED = PREFIX + "fee-on-month-day.not-supported}"; + private static final String FEE_INTERVAL_NOT_NULL = PREFIX + "fee-interval.not-null}"; + private static final String FEE_INTERVAL_MONTHLY_RANGE = PREFIX + "fee-interval.monthly-range}"; + private static final String TAX_GROUP_MODIFICATION_NOT_SUPPORTED = PREFIX + "tax-group-id.modification-not-supported}"; + + // the format/value combination the platform is actually called with; it only parses leniently + private static final String FEE_ON_MONTH_DAY = "04 March"; + private static final String MONTH_DAY_FORMAT = "dd MMM"; + + private ChargeRepository repository; + private ValidatorFactory validatorFactory; + private Validator validator; + + @BeforeEach + public void setUp() { + repository = mock(ChargeRepository.class); + validatorFactory = Validation.byDefaultProvider().configure().constraintValidatorFactory(new ConstraintValidatorFactory() { + + @Override + @SuppressWarnings("unchecked") + public > T getInstance(final Class key) { + if (key.equals(ChargeUpdateValidator.class)) { + return (T) new ChargeUpdateValidator(repository); + } + try { + return key.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void releaseInstance(final ConstraintValidator instance) {} + }).buildValidatorFactory(); + validator = validatorFactory.getValidator(); + } + + @AfterEach + public void tearDown() { + validatorFactory.close(); + } + + // ---------------------------------------------------------------- create + + @Test + public void createValidLoanChargeHasNoViolations() { + assertThat(validate(loanChargeRequest())).isEmpty(); + } + + @Test + public void createBlankNameFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setName(" "); + + assertThat(validate(request)).containsExactly(NAME_NOT_BLANK); + } + + @Test + public void createZeroAmountFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setAmount(0.0); + + assertThat(validate(request)).containsExactly(AMOUNT_POSITIVE); + } + + @Test + public void createWithoutChargeAppliesToFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeAppliesTo(null); + + assertThat(validate(request)).contains(CHARGE_APPLIES_TO_NOT_NULL); + } + + @Test + public void createWithUnknownChargeAppliesToFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeAppliesTo(99); + + assertThat(validate(request)).containsExactly(CHARGE_APPLIES_TO_INVALID); + } + + @Test + public void createWithoutChargeTimeTypeFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeTimeType(null); + + assertThat(validate(request)).containsExactly(CHARGE_TIME_TYPE_NOT_NULL); + } + + @Test + public void createLoanChargeWithSavingsOnlyChargeTimeTypeFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeTimeType(ChargeTimeType.MONTHLY_FEE.getValue()); + + assertThat(validate(request)).containsExactly(CHARGE_TIME_TYPE_INVALID); + } + + @Test + public void createLoanChargeWithoutChargePaymentModeFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargePaymentMode(null); + + assertThat(validate(request)).containsExactly(CHARGE_PAYMENT_MODE_NOT_NULL); + } + + @Test + public void createTrancheDisbursementWithUnsupportedCalculationTypeFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeTimeType(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()); + request.setChargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST.getValue()); + + assertThat(validate(request)).containsExactly(CHARGE_CALCULATION_TYPE_INVALID_FOR_TRANCHE); + } + + @Test + public void createClientChargeWithPercentageCalculationTypeFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setChargeAppliesTo(ChargeAppliesTo.CLIENT.getValue()); + request.setChargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()); + request.setChargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()); + request.setChargePaymentMode(null); + + assertThat(validate(request)).containsExactly(CHARGE_CALCULATION_TYPE_INVALID); + } + + @Test + public void createValidSavingsMonthlyFeeHasNoViolations() { + assertThat(validate(savingsMonthlyFeeRequest())).isEmpty(); + } + + @Test + public void createSavingsMonthlyFeeWithoutFeeOnMonthDayFails() { + final ChargeCreateRequest request = savingsMonthlyFeeRequest(); + request.setFeeOnMonthDay(null); + + assertThat(validate(request)).containsExactly(FEE_ON_MONTH_DAY_NOT_NULL); + } + + @Test + public void createSavingsMonthlyFeeWithoutFeeIntervalFails() { + final ChargeCreateRequest request = savingsMonthlyFeeRequest(); + request.setFeeInterval(null); + + assertThat(validate(request)).containsExactly(FEE_INTERVAL_NOT_NULL); + } + + @Test + public void createSavingsMonthlyFeeWithFeeIntervalAboveTwelveFails() { + final ChargeCreateRequest request = savingsMonthlyFeeRequest(); + request.setFeeInterval(13); + + assertThat(validate(request)).containsExactly(FEE_INTERVAL_MONTHLY_RANGE); + } + + @Test + public void createSavingsWeeklyFeeWithFeeOnMonthDayFails() { + final ChargeCreateRequest request = savingsMonthlyFeeRequest(); + request.setChargeTimeType(ChargeTimeType.WEEKLY_FEE.getValue()); + + assertThat(validate(request)).containsExactly(FEE_ON_MONTH_DAY_NOT_SUPPORTED); + } + + @Test + public void createWithUnparseableFeeOnMonthDayFails() { + final ChargeCreateRequest request = savingsMonthlyFeeRequest(); + request.setFeeOnMonthDay("not-a-date"); + + assertThat(validate(request)).containsExactlyInAnyOrder(FEE_ON_MONTH_DAY_INVALID, FEE_ON_MONTH_DAY_NOT_NULL); + } + + @Test + public void createWithFeeFrequencyButNoFeeIntervalFails() { + final ChargeCreateRequest request = loanChargeRequest(); + request.setFeeFrequency(2); + + assertThat(validate(request)).containsExactly(FEE_INTERVAL_NOT_NULL); + } + + // ---------------------------------------------------------------- update + + @Test + public void updateWithoutIdIsSkipped() { + // the resource-level @Valid pass runs before the path id is bound + final ChargeUpdateRequest request = new ChargeUpdateRequest(); + request.setChargeTimeType(99); + + assertThat(validate(request)).isEmpty(); + } + + @Test + public void updateOfUnknownChargeIsSkipped() { + when(repository.findById(1L)).thenReturn(Optional.empty()); + final ChargeUpdateRequest request = new ChargeUpdateRequest(); + request.setId(1L); + request.setChargeTimeType(ChargeTimeType.MONTHLY_FEE.getValue()); + + assertThat(validate(request)).isEmpty(); + } + + @Test + public void updateBlankNameFails() { + givenCharge(loanCharge()); + final ChargeUpdateRequest request = updateRequest(); + request.setName(" "); + + assertThat(validate(request)).containsExactly(NAME_NOT_BLANK); + } + + @Test + public void updateLoanChargeToSavingsOnlyChargeTimeTypeFails() { + givenCharge(loanCharge()); + final ChargeUpdateRequest request = updateRequest(); + request.setChargeTimeType(ChargeTimeType.MONTHLY_FEE.getValue()); + + assertThat(validate(request)).containsExactly(CHARGE_TIME_TYPE_NOT_ALLOWED_FOR_LOAN); + } + + @Test + public void updateSavingsActivationFeeToPercentageCalculationFails() { + givenCharge(savingsCharge(ChargeTimeType.SAVINGS_ACTIVATION, ChargeCalculationType.FLAT)); + final ChargeUpdateRequest request = updateRequest(); + request.setChargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()); + + assertThat(validate(request)).containsExactly(CHARGE_CALCULATION_TYPE_PERCENTAGE_ONLY); + } + + @Test + public void updateWithdrawalFeeToPercentageCalculationIsAllowed() { + givenCharge(savingsCharge(ChargeTimeType.WITHDRAWAL_FEE, ChargeCalculationType.FLAT)); + final ChargeUpdateRequest request = updateRequest(); + request.setChargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()); + + assertThat(validate(request)).isEmpty(); + } + + @Test + public void updateTaxGroupOfChargeThatAlreadyHasOneFails() { + final Charge charge = loanCharge(); + charge.setTaxGroup(taxGroup(7L)); + givenCharge(charge); + final ChargeUpdateRequest request = updateRequest(); + request.setTaxGroupId(8L); + + assertThat(validate(request)).containsExactly(TAX_GROUP_MODIFICATION_NOT_SUPPORTED); + } + + @Test + public void updateAmountOnlyHasNoViolations() { + givenCharge(loanCharge()); + final ChargeUpdateRequest request = updateRequest(); + request.setAmount(25.0); + + assertThat(validate(request)).isEmpty(); + } + + // ---------------------------------------------------------------- helpers + + private Set validate(final Object request) { + return validator.validate(request).stream().map(ConstraintViolation::getMessageTemplate).collect(Collectors.toSet()); + } + + private ChargeCreateRequest loanChargeRequest() { + final ChargeCreateRequest request = new ChargeCreateRequest(); + request.setChargeAppliesTo(ChargeAppliesTo.LOAN.getValue()); + request.setName("Processing Fee"); + request.setCurrencyCode("USD"); + request.setChargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()); + request.setChargeCalculationType(ChargeCalculationType.FLAT.getValue()); + request.setChargePaymentMode(ChargePaymentMode.REGULAR.getValue()); + request.setAmount(10.0); + request.setActive(true); + request.setLocale("en"); + return request; + } + + private ChargeCreateRequest savingsMonthlyFeeRequest() { + final ChargeCreateRequest request = new ChargeCreateRequest(); + request.setChargeAppliesTo(ChargeAppliesTo.SAVINGS.getValue()); + request.setName("Monthly Fee"); + request.setCurrencyCode("USD"); + request.setChargeTimeType(ChargeTimeType.MONTHLY_FEE.getValue()); + request.setChargeCalculationType(ChargeCalculationType.FLAT.getValue()); + request.setAmount(10.0); + request.setActive(true); + request.setFeeOnMonthDay(FEE_ON_MONTH_DAY); + request.setMonthDayFormat(MONTH_DAY_FORMAT); + request.setFeeInterval(1); + request.setLocale("en"); + return request; + } + + private ChargeUpdateRequest updateRequest() { + final ChargeUpdateRequest request = new ChargeUpdateRequest(); + request.setId(1L); + request.setLocale("en"); + return request; + } + + private void givenCharge(final Charge charge) { + when(repository.findById(1L)).thenReturn(Optional.of(charge)); + } + + private Charge loanCharge() { + return charge(ChargeAppliesTo.LOAN, ChargeTimeType.SPECIFIED_DUE_DATE, ChargeCalculationType.FLAT, ChargePaymentMode.REGULAR, null); + } + + private Charge savingsCharge(final ChargeTimeType chargeTimeType, final ChargeCalculationType chargeCalculationType) { + final MonthDay feeOnMonthDay = chargeTimeType.isMonthlyFee() || chargeTimeType.isAnnualFee() ? MonthDay.of(3, 4) : null; + return charge(ChargeAppliesTo.SAVINGS, chargeTimeType, chargeCalculationType, null, feeOnMonthDay); + } + + private Charge charge(final ChargeAppliesTo chargeAppliesTo, final ChargeTimeType chargeTimeType, + final ChargeCalculationType chargeCalculationType, final ChargePaymentMode chargePaymentMode, final MonthDay feeOnMonthDay) { + final Charge charge = new Charge("Charge", BigDecimal.TEN, "USD", chargeAppliesTo, chargeTimeType, chargeCalculationType, false, + true, chargePaymentMode, feeOnMonthDay, null, null, null, null, false, null, null, null, null, null, false, null); + ReflectionTestUtils.setField(charge, "id", 1L); + return charge; + } + + private TaxGroup taxGroup(final Long id) { + final TaxGroup taxGroup = TaxGroup.createTaxGroup("Tax Group", new HashSet<>()); + ReflectionTestUtils.setField(taxGroup, "id", id); + return taxGroup; + } +} diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index baaa6b13a1c..a79d640af17 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -160,7 +160,6 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_BATCH_BUSINESS_STEP; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CALENDAR; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CENTER; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CHARGE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CLIENT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CLIENTIDENTIFIER; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CLIENT_COLLATERAL_PRODUCT; @@ -672,30 +671,6 @@ public CommandWrapperBuilder deleteCode(final Long codeId) { return this; } - public CommandWrapperBuilder createCharge() { - this.actionName = ACTION_CREATE; - this.entityName = ENTITY_CHARGE; - this.entityId = null; - this.href = "/charges/template"; - return this; - } - - public CommandWrapperBuilder updateCharge(final Long chargeId) { - this.actionName = ACTION_UPDATE; - this.entityName = ENTITY_CHARGE; - this.entityId = chargeId; - this.href = "/charges/" + chargeId; - return this; - } - - public CommandWrapperBuilder deleteCharge(final Long chargeId) { - this.actionName = ACTION_DELETE; - this.entityName = ENTITY_CHARGE; - this.entityId = chargeId; - this.href = "/charges/" + chargeId; - return this; - } - public CommandWrapperBuilder createLoanProduct() { this.actionName = ACTION_CREATE; this.entityName = ENTITY_LOANPRODUCT; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/WorkingCapitalChargeRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/WorkingCapitalChargeRequestFactory.java index a35df096859..6acbc2a3b10 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/WorkingCapitalChargeRequestFactory.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/WorkingCapitalChargeRequestFactory.java @@ -18,7 +18,7 @@ */ package org.apache.fineract.test.factory; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; import org.apache.fineract.test.data.ChargeCalculationType; import org.apache.fineract.test.data.ChargeProductAppliesTo; import org.apache.fineract.test.data.ChargeTimeType; @@ -34,8 +34,8 @@ public class WorkingCapitalChargeRequestFactory { public static final String DEFAULT_NAME_PREFIX = "WCL_CHARGE_"; public static final int DEFAULT_NAME_RANDOM_LENGTH = 10; - public ChargeRequest defaultWorkingCapitalChargeRequest() { - return new ChargeRequest() // + public ChargeCreateRequest defaultWorkingCapitalChargeRequest() { + return new ChargeCreateRequest() // .chargeAppliesTo(ChargeProductAppliesTo.WORKING_CAPITAL_LOAN.value) // .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.value) // .chargeCalculationType(ChargeCalculationType.FLAT.value) // diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanProductAdvancedAccountingTestHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanProductAdvancedAccountingTestHelper.java index ca91660bcb9..e884c9e5fe0 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanProductAdvancedAccountingTestHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanProductAdvancedAccountingTestHelper.java @@ -30,12 +30,12 @@ import java.util.function.Consumer; import java.util.function.Function; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetCodeValuesDataResponse; import org.apache.fineract.client.models.GetGLAccountsResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoanProductsTemplateResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostGLAccountsRequest; import org.apache.fineract.client.models.PostWorkingCapitalLoanProductsRequest; import org.apache.fineract.client.models.PutWorkingCapitalLoanProductsProductIdRequest; @@ -209,11 +209,11 @@ public static void assertProductHasExpectedAdvancedMappings(final ObjectMapper o private static Long createChargeForAdvancedMappings(final FineractFeignClient fineractFeignClient, final boolean penalty, final double amount) { - final ChargeRequest request = new ChargeRequest().active(true).name(Utils.randomStringGenerator("WCLP_ADV_CHARGE_", 8)) + final ChargeCreateRequest request = new ChargeCreateRequest().active(true).name(Utils.randomStringGenerator("WCLP_ADV_CHARGE_", 8)) .chargeAppliesTo(1).chargeCalculationType(ChargeCalculationType.FLAT.value) .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.value).chargePaymentMode(ChargePaymentMode.REGULAR.value).penalty(penalty) .amount(amount).currencyCode("USD").locale("en"); - final PostChargesResponse response = ok(() -> fineractFeignClient.charges().createCharge(request)); + final ChargeCreateResponse response = ok(() -> fineractFeignClient.charges().createCharge(request)); return response.getResourceId(); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/ChargeStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/ChargeStepDef.java index 2ee0eed361d..3b47cdf1cd3 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/ChargeStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/ChargeStepDef.java @@ -22,7 +22,7 @@ import io.cucumber.java.en.When; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeUpdateRequest; import org.apache.fineract.test.data.ChargeCalculationType; import org.apache.fineract.test.data.ChargeProductResolver; import org.apache.fineract.test.data.ChargeProductType; @@ -39,7 +39,7 @@ public class ChargeStepDef extends AbstractStepDef { @When("Admin updates charge {string} with {string} calculation type and {double} % of transaction amount") public void updateCharge(String chargeType, String chargeCalculationType, double amount) { - ChargeRequest disbursementChargeUpdateRequest = new ChargeRequest(); + ChargeUpdateRequest disbursementChargeUpdateRequest = new ChargeUpdateRequest(); ChargeCalculationType chargeProductTypeValue = ChargeCalculationType.valueOf(chargeCalculationType); disbursementChargeUpdateRequest.chargeCalculationType(chargeProductTypeValue.value).amount(amount).locale("en"); @@ -51,7 +51,7 @@ public void updateCharge(String chargeType, String chargeCalculationType, double @When("Admin updates charge {string} with {string} calculation type and {double} EUR amount") public void updateChargeWithFlatAmount(String chargeType, String chargeCalculationType, double flatAmount) { - ChargeRequest disbursementChargeUpdateRequest = new ChargeRequest(); + ChargeUpdateRequest disbursementChargeUpdateRequest = new ChargeUpdateRequest(); ChargeCalculationType chargeProductTypeValue = ChargeCalculationType.valueOf(chargeCalculationType); disbursementChargeUpdateRequest.chargeCalculationType(chargeProductTypeValue.value).amount(flatAmount).locale("en"); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java index 9ce0af4fcdf..736ff970e95 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java @@ -36,8 +36,10 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.ChargeData; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeUpdateRequest; import org.apache.fineract.client.models.EnumOptionData; import org.apache.fineract.client.models.ExecuteWorkingCapitalLoanTransactionCommandRequest; import org.apache.fineract.client.models.GetBalance; @@ -45,7 +47,6 @@ import org.apache.fineract.client.models.GetWorkingCapitalLoanTransactionIdResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoanTransactionsResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.client.models.PostWorkingCapitalLoansLoanIdChargesChargeIdRequest; @@ -107,7 +108,8 @@ public void createWorkingCapitalLoanChargeWithParams(String chargeTimeTypeName, @When("Admin updates working capital loan charge") public void updateWorkingCapitalLoanCharge() { final Long id = getChargeId(); - final ChargeRequest request = chargeRequestFactory.defaultWorkingCapitalChargeRequest().amount(30.0D).penalty(true); + final ChargeUpdateRequest request = new ChargeUpdateRequest().amount(30.0D).penalty(true) + .locale(WorkingCapitalChargeRequestFactory.DEFAULT_LOCALE); ok(() -> fineractClient.charges().updateCharge(id, request)); } @@ -401,7 +403,7 @@ public void verifyTemplateChargePaymentModeOptions() { public void createWclChargeWithInvalidParamsFails(String chargeTimeTypeName, String chargeCalcTypeName, DataTable table) { final ChargeTimeType timeType = ChargeTimeType.valueOf(chargeTimeTypeName); final ChargeCalculationType calcType = ChargeCalculationType.valueOf(chargeCalcTypeName); - final ChargeRequest request = chargeRequestFactory.defaultWorkingCapitalChargeRequest() // + final ChargeCreateRequest request = chargeRequestFactory.defaultWorkingCapitalChargeRequest() // .chargeTimeType(timeType.value) // .chargeCalculationType(calcType.value); @@ -557,14 +559,14 @@ private GetWorkingCapitalLoanTransactionIdResponse getLastChargeAdjustmentTransa } // Charge API Helpers - private void createChargeAndStore(final ChargeRequest request) { - final PostChargesResponse response = ok(() -> fineractClient.charges().createCharge(request)); + private void createChargeAndStore(final ChargeCreateRequest request) { + final ChargeCreateResponse response = ok(() -> fineractClient.charges().createCharge(request)); testContext().set(TestContextKey.WORKING_CAPITAL_CHARGE_ID, response.getResourceId()); log.info("Created WCL charge with ID: {}", response.getResourceId()); } private GetChargesResponse retrieveCharge(final Long chargeId) { - final GetChargesResponse chargeData = ok(() -> fineractClient.charges().retrieveOneCharge(chargeId)); + final GetChargesResponse chargeData = ok(() -> fineractClient.charges().retrieveOneCharge(chargeId, (Boolean) null)); assertThat(chargeData).as("Charge data should not be null").isNotNull(); return chargeData; } diff --git a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/ChargeGlobalInitializerStep.java b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/ChargeGlobalInitializerStep.java index ed238235381..c5360353245 100644 --- a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/ChargeGlobalInitializerStep.java +++ b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/ChargeGlobalInitializerStep.java @@ -27,9 +27,9 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.ChargeData; -import org.apache.fineract.client.models.ChargeRequest; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.test.data.ChargeCalculationType; import org.apache.fineract.test.data.ChargePaymentMode; import org.apache.fineract.test.data.ChargeProductAppliesTo; @@ -170,9 +170,10 @@ public void initialize() { ParallelExecutionHelper.runInParallel(items); } - private PostChargesResponse createChargeIfNotExists(List existingCharges, Enum appliesTo, + private ChargeCreateResponse createChargeIfNotExists(List existingCharges, Enum appliesTo, String name, Integer chargeTimeType, Integer chargeCalculationType, Double amount, Boolean isActive, Boolean isPenalty) { - ChargeRequest request = defaultChargesRequest(appliesTo, name, chargeTimeType, chargeCalculationType, amount, isActive, isPenalty); + ChargeCreateRequest request = defaultChargesRequest(appliesTo, name, chargeTimeType, chargeCalculationType, amount, isActive, + isPenalty); try { return ok(() -> fineractClient.charges().createCharge(request, Map.of())); @@ -181,7 +182,7 @@ private PostChargesResponse createChargeIfNotExists(List existingCha log.debug("Charge '{}' already exists, retrieving existing charge", name); ChargeData existing = existingCharges.stream().filter(c -> name.equals(c.getName())).findFirst().orElse(null); if (existing != null) { - PostChargesResponse response = new PostChargesResponse(); + ChargeCreateResponse response = new ChargeCreateResponse(); response.setResourceId(existing.getId()); return response; } @@ -190,9 +191,9 @@ private PostChargesResponse createChargeIfNotExists(List existingCha } } - public static ChargeRequest defaultChargesRequest(Enum appliesTo, String name, Integer chargeTimeType, + public static ChargeCreateRequest defaultChargesRequest(Enum appliesTo, String name, Integer chargeTimeType, Integer chargeCalculationType, Double amount, Boolean isActive, Boolean isPenalty) { - ChargeRequest request = new ChargeRequest(); + ChargeCreateRequest request = new ChargeCreateRequest(); Integer chargeAppliesTo; if (appliesTo.equals(ChargeProductAppliesTo.CLIENT)) { diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature index b877a42c107..2e19d6dcc6c 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature @@ -35,20 +35,20 @@ Feature: WorkingCapitalLoanChargesFeature @TestRailId:C80959 Scenario: Verify Working Capital Charge product - UC6: invalid chargeTimeType Disbursement fails (Negative) Then Creating working capital loan charge with "DISBURSEMENT" chargeTimeType and "FLAT" chargeCalculationType results an error with the following data: - | httpCode | errorMessage | - | 400 | The parameter `chargeTimeType` must be one of [ 2 ] . | + | httpCode | errorMessage | + | 400 | The parameter 'chargeTimeType' is not one of the values supported for this 'chargeAppliesTo' | @TestRailId:C80960 Scenario: Verify Working Capital Charge product - UC7: invalid chargeCalculationType Percentage Amount fails (Negative) Then Creating working capital loan charge with "SPECIFIED_DUE_DATE" chargeTimeType and "PERCENTAGE_AMOUNT" chargeCalculationType results an error with the following data: - | httpCode | errorMessage | - | 400 | The parameter `chargeCalculationType` must be one of [ 1 ] . | + | httpCode | errorMessage | + | 400 | The parameter 'chargeCalculationType' is not one of the values supported for this 'chargeAppliesTo' | @TestRailId:C80961 Scenario: Verify Working Capital Charge product - UC8: invalid chargeTimeType Instalment Fee fails (Negative) Then Creating working capital loan charge with "INSTALLMENT_FEE" chargeTimeType and "FLAT" chargeCalculationType results an error with the following data: - | httpCode | errorMessage | - | 400 | The parameter `chargeTimeType` must be one of [ 2 ] . | + | httpCode | errorMessage | + | 400 | The parameter 'chargeTimeType' is not one of the values supported for this 'chargeAppliesTo' | # ############################################# # --- Loan Account level --- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java index 14351c97b5b..eabe2b5422d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java @@ -78,7 +78,7 @@ import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.service.StaffReadService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.fund.data.FundData; @@ -134,7 +134,7 @@ public class BulkImportWorkbookPopulatorServiceImpl implements BulkImportWorkboo private final CodeValueReadPlatformService codeValueReadPlatformService; private final SavingsProductReadPlatformService savingsProductReadPlatformService; private final ShareProductReadPlatformService shareProductReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final DepositProductReadPlatformService depositProductReadPlatformService; private final RoleReadPlatformService roleReadPlatformService; @@ -150,8 +150,7 @@ public BulkImportWorkbookPopulatorServiceImpl(final PlatformSecurityContext cont final SavingsAccountReadPlatformService savingsAccountReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService, final SavingsProductReadPlatformService savingsProductReadPlatformService, - final ShareProductReadPlatformService shareProductReadPlatformService, - final ChargeReadPlatformService chargeReadPlatformService, + final ShareProductReadPlatformService shareProductReadPlatformService, final ChargeReadService chargeReadService, final DepositProductReadPlatformService depositProductReadPlatformService, final RoleReadPlatformService roleReadPlatformService) { this.officeReadPlatformService = officeReadPlatformService; @@ -170,7 +169,7 @@ public BulkImportWorkbookPopulatorServiceImpl(final PlatformSecurityContext cont this.codeValueReadPlatformService = codeValueReadPlatformService; this.savingsProductReadPlatformService = savingsProductReadPlatformService; this.shareProductReadPlatformService = shareProductReadPlatformService; - this.chargeReadPlatformService = chargeReadPlatformService; + this.chargeReadService = chargeReadService; this.depositProductReadPlatformService = depositProductReadPlatformService; this.roleReadPlatformService = roleReadPlatformService; } @@ -282,7 +281,7 @@ private List fetchOffices(final Long officeId) { } private List fetchCharges() { - return this.chargeReadPlatformService.retrieveAllCharges(); + return this.chargeReadService.retrieveAllCharges(); } private List fetchStaff(final Long staffId) { @@ -529,7 +528,7 @@ private WorkbookPopulator populateSharedAccountsWorkbook(Long officeId) { } private List fetchChargesForShares() { - return chargeReadPlatformService.retrieveSharesApplicableCharges(); + return chargeReadService.retrieveSharesApplicableCharges(); } private List fetchSharedProducts() { 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 27a328d7b8c..d628510a235 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 @@ -412,6 +412,17 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/standinginstructionrunhistory")) .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_STANDINGINSTRUCTION") + // charge + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/charges")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_CHARGE") + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/charges/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_CHARGE") + .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/charges")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_CHARGE") + .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/charges/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_CHARGE") + .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/charges/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_CHARGE") .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated() .requestMatchers(API_MATCHER.matcher("/api/*/twofactor")).fullyAuthenticated() diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java index 20d7f300f12..ffff15d15c2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java @@ -30,7 +30,7 @@ import org.apache.fineract.organisation.monetary.domain.OrganisationCurrency; import org.apache.fineract.organisation.monetary.domain.OrganisationCurrencyRepository; import org.apache.fineract.organisation.monetary.exception.CurrencyInUseException; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; import org.springframework.transaction.annotation.Transactional; @@ -42,7 +42,7 @@ public class CurrencyWritePlatformServiceJpaRepositoryImpl implements CurrencyWr private final OrganisationCurrencyRepository organisationCurrencyRepository; private final LoanProductReadPlatformService loanProductService; private final SavingsProductReadPlatformService savingsProductService; - private final ChargeReadPlatformService chargeService; + private final ChargeReadService chargeService; @Transactional @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/starter/OrganisationMonetaryConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/starter/OrganisationMonetaryConfiguration.java index 0db76dd7b7a..a7a5f9af5c8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/starter/OrganisationMonetaryConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/monetary/starter/OrganisationMonetaryConfiguration.java @@ -26,7 +26,7 @@ import org.apache.fineract.organisation.monetary.service.CurrencyWritePlatformServiceJpaRepositoryImpl; import org.apache.fineract.organisation.monetary.service.OrganisationCurrencyReadPlatformService; import org.apache.fineract.organisation.monetary.service.OrganisationCurrencyReadPlatformServiceImpl; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -47,7 +47,7 @@ public CurrencyReadPlatformService currencyReadPlatformService(JdbcTemplate jdbc @ConditionalOnMissingBean(CurrencyWritePlatformService.class) public CurrencyWritePlatformService currencyWritePlatformService(ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, OrganisationCurrencyRepository organisationCurrencyRepository, LoanProductReadPlatformService loanProductService, - SavingsProductReadPlatformService savingsProductService, ChargeReadPlatformService chargeService) { + SavingsProductReadPlatformService savingsProductService, ChargeReadService chargeService) { return new CurrencyWritePlatformServiceJpaRepositoryImpl(applicationCurrencyRepository, organisationCurrencyRepository, loanProductService, savingsProductService, chargeService); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadServiceImpl.java similarity index 99% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadServiceImpl.java index 78051122e9d..da6f005daa0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeReadServiceImpl.java @@ -59,7 +59,7 @@ */ @RequiredArgsConstructor @Transactional(readOnly = true) -public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService { +public class ChargeReadServiceImpl implements ChargeReadService { private final CurrencyReadPlatformService currencyReadPlatformService; private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java deleted file mode 100644 index e56bdbfea66..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java +++ /dev/null @@ -1,291 +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.charge.service; - -import jakarta.persistence.PersistenceException; -import java.util.Collection; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.fineract.accounting.glaccount.domain.GLAccount; -import org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper; -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.exception.ErrorHandler; -import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType; -import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.portfolio.charge.api.ChargesApiConstants; -import org.apache.fineract.portfolio.charge.domain.Charge; -import org.apache.fineract.portfolio.charge.domain.ChargeRepository; -import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeDeletedException; -import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; -import org.apache.fineract.portfolio.charge.exception.ChargeNotFoundException; -import org.apache.fineract.portfolio.charge.serialization.ChargeDefinitionCommandFromApiJsonDeserializer; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; -import org.apache.fineract.portfolio.paymentdetail.PaymentDetailConstants; -import org.apache.fineract.portfolio.paymenttype.domain.PaymentType; -import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository; -import org.apache.fineract.portfolio.paymenttype.exception.PaymentTypeNotFoundException; -import org.apache.fineract.portfolio.tax.domain.TaxGroup; -import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.orm.jpa.JpaSystemException; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@RequiredArgsConstructor -public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWritePlatformService { - - private final PlatformSecurityContext context; - private final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer; - private final ChargeRepository chargeRepository; - private final LoanProductRepository loanProductRepository; - private final JdbcTemplate jdbcTemplate; - private final FineractEntityAccessUtil fineractEntityAccessUtil; - private final GLAccountRepositoryWrapper glAccountRepository; - private final TaxGroupRepositoryWrapper taxGroupRepository; - private final PaymentTypeRepository paymentTypeRepository; - - @Transactional - @Override - @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") - public CommandProcessingResult createCharge(final JsonCommand command) { - try { - this.context.authenticatedUser(); - this.fromApiJsonDeserializer.validateForCreate(command.json()); - - // Retrieve linked GLAccount for Client charges (if present) - final Long glAccountId = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName); - - GLAccount glAccount = null; - if (glAccountId != null) { - glAccount = this.glAccountRepository.findOneWithNotFoundDetection(glAccountId); - } - - final Long taxGroupId = command.longValueOfParameterNamed(ChargesApiConstants.taxGroupIdParamName); - TaxGroup taxGroup = null; - if (taxGroupId != null) { - taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(taxGroupId); - } - - final boolean enablePaymentType = command.booleanPrimitiveValueOfParameterNamed("enablePaymentType"); - PaymentType paymentType = null; - if (enablePaymentType) { - final Long paymentTypeId = command.longValueOfParameterNamed(PaymentDetailConstants.paymentTypeParamName); - if (paymentTypeId != null) { - paymentType = findPaymentTypeWithNotFoundDetection(paymentTypeId); - } - } - - final Charge charge = Charge.fromJson(command, glAccount, taxGroup, paymentType); - this.chargeRepository.saveAndFlush(charge); - - // check if the office specific products are enabled. If yes, then - // save this savings product against a specific office - // i.e. this savings product is specific for this office. - fineractEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice( - FineractEntityAccessType.OFFICE_ACCESS_TO_CHARGES, charge.getId()); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withEntityId(charge.getId()) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); - return CommandProcessingResult.empty(); - } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - } - - @Transactional - @Override - @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") - public CommandProcessingResult updateCharge(final Long chargeId, final JsonCommand command) { - - try { - this.fromApiJsonDeserializer.validateForUpdate(command.json()); - - final Charge chargeForUpdate = this.chargeRepository.findById(chargeId) - .orElseThrow(() -> new ChargeNotFoundException(chargeId)); - - final Map changes = chargeForUpdate.update(command); - - this.fromApiJsonDeserializer.validateChargeTimeNCalculationType(chargeForUpdate.getChargeTimeType(), - chargeForUpdate.getChargeCalculation()); - - // MIFOSX-900: Check if the Charge has been active before and now is - // deactivated: - if (changes.containsKey("active")) { - // IF the key exists then it has changed (otherwise it would - // have been filtered), so check current state: - if (!chargeForUpdate.isActive()) { - // TODO: Change this function to only check the mappings!!! - final Boolean isChargeExistWithLoans = isAnyLoanProductsAssociateWithThisCharge(chargeId); - final Boolean isChargeExistWithSavings = isAnySavingsProductsAssociateWithThisCharge(chargeId); - - if (isChargeExistWithLoans || isChargeExistWithSavings) { - throw new ChargeCannotBeUpdatedException("error.msg.charge.cannot.be.updated.it.is.used.in.loan", - "This charge cannot be updated, it is used in loan"); - } - } - } else if ((changes.containsKey("feeFrequency") || changes.containsKey("feeInterval")) && chargeForUpdate.isLoanCharge()) { - final Boolean isChargeExistWithLoans = isAnyLoanProductsAssociateWithThisCharge(chargeId); - if (isChargeExistWithLoans) { - throw new ChargeCannotBeUpdatedException("error.msg.charge.frequency.cannot.be.updated.it.is.used.in.loan", - "This charge frequency cannot be updated, it is used in loan"); - } - } - - // Has account Id been changed ? - if (changes.containsKey(ChargesApiConstants.glAccountIdParamName)) { - final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName); - GLAccount newIncomeAccount = null; - if (newValue != null) { - newIncomeAccount = this.glAccountRepository.findOneWithNotFoundDetection(newValue); - } - chargeForUpdate.setAccount(newIncomeAccount); - } - - final String paymentTypeIdParamName = "paymentTypeId"; - if (changes.containsKey(paymentTypeIdParamName)) { - - final Long paymentTypeIdNewValue = command.longValueOfParameterNamed(paymentTypeIdParamName); - - PaymentType paymentType = null; - if (paymentTypeIdNewValue != null) { - final Long paymentTypeId = paymentTypeIdNewValue.longValue(); - - paymentType = findPaymentTypeWithNotFoundDetection(paymentTypeId); - chargeForUpdate.setPaymentType(paymentType); - } - - } - - if (changes.containsKey(ChargesApiConstants.taxGroupIdParamName)) { - final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.taxGroupIdParamName); - TaxGroup taxGroup = null; - if (newValue != null) { - taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(newValue); - } - chargeForUpdate.setTaxGroup(taxGroup); - } - - if (!changes.isEmpty()) { - this.chargeRepository.save(chargeForUpdate); - } - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withEntityId(chargeId) // - .with(changes) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); - return CommandProcessingResult.empty(); - } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - } - - @Transactional - @Override - @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") - public CommandProcessingResult deleteCharge(final Long chargeId) { - - final Charge chargeForDelete = this.chargeRepository.findById(chargeId).orElseThrow(() -> new ChargeNotFoundException(chargeId)); - if (chargeForDelete.isDeleted()) { - throw new ChargeNotFoundException(chargeId); - } - - final Collection loanProducts = this.loanProductRepository.retrieveLoanProductsByChargeId(chargeId); - final Boolean isChargeExistWithLoans = isAnyLoansAssociateWithThisCharge(chargeId); - final Boolean isChargeExistWithSavings = isAnySavingsAssociateWithThisCharge(chargeId); - final Boolean isChargeExistWithWorkingCapitalLoan = chargeRepository.isAnyWorkingCapitalLoansAssociateWithThisCharge(chargeId) - .isPresent(); - - // TODO: Change error messages around: - if (!loanProducts.isEmpty() || isChargeExistWithLoans || isChargeExistWithSavings || isChargeExistWithWorkingCapitalLoan) { - throw new ChargeCannotBeDeletedException("error.msg.charge.cannot.be.deleted.it.is.already.used.in.loan", - "This charge cannot be deleted, it is already used in loan"); - } - - chargeForDelete.delete(); - - this.chargeRepository.save(chargeForDelete); - - return new CommandProcessingResultBuilder() // - .withEntityId(chargeForDelete.getId()) // - .build(); - } - - /* - * Guaranteed to throw an exception no matter what the data integrity issue is. - */ - private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) { - if (realCause.getMessage().contains("name")) { - final String name = command.stringValueOfParameterNamed("name"); - throw new PlatformDataIntegrityException("error.msg.charge.duplicate.name", "Charge with name `" + name + "` already exists", - "name", name); - } - - log.error("Error occured.", dve); - throw ErrorHandler.getMappable(dve, "error.msg.charge.unknown.data.integrity.issue", - "Unknown data integrity issue with resource: " + realCause.getMessage()); - } - - private PaymentType findPaymentTypeWithNotFoundDetection(final Long paymentTypeId) { - return this.paymentTypeRepository.findById(paymentTypeId).orElseThrow(() -> new PaymentTypeNotFoundException(paymentTypeId)); - } - - private boolean isAnyLoansAssociateWithThisCharge(final Long chargeId) { - final String sql = "select (CASE WHEN exists (select 1 from m_loan_charge lc where lc.charge_id = ? and lc.is_active = true) THEN 'true' ELSE 'false' END)"; - final String isLoansUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); - return Boolean.valueOf(isLoansUsingCharge); - } - - private boolean isAnySavingsAssociateWithThisCharge(final Long chargeId) { - final String sql = "select (CASE WHEN exists (select 1 from m_savings_account_charge sc where sc.charge_id = ? and sc.is_active = true) THEN 'true' ELSE 'false' END)"; - final String isSavingsUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); - return Boolean.valueOf(isSavingsUsingCharge); - } - - private boolean isAnyLoanProductsAssociateWithThisCharge(final Long chargeId) { - final String sql = "select (CASE WHEN exists (select 1 from m_product_loan_charge lc where lc.charge_id = ?) THEN 'true' ELSE 'false' END)"; - final String isLoansUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); - return Boolean.valueOf(isLoansUsingCharge); - } - - private boolean isAnySavingsProductsAssociateWithThisCharge(final Long chargeId) { - final String sql = "select (CASE WHEN (exists (select 1 from m_savings_product_charge sc where sc.charge_id = ?)) = 1 THEN 'true' ELSE 'false' END)"; - final String isSavingsUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); - return Boolean.valueOf(isSavingsUsingCharge); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteServiceImpl.java new file mode 100644 index 00000000000..25f5eaf36d5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/service/ChargeWriteServiceImpl.java @@ -0,0 +1,491 @@ +/** + * 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.charge.service; + +import static org.apache.fineract.portfolio.charge.domain.Charge.CHARGE_CALCULATION_TYPE_PARAM_NAME; +import static org.apache.fineract.portfolio.charge.domain.Charge.CHARGE_TIME_PARAM_NAME; +import static org.apache.fineract.portfolio.charge.domain.Charge.FEE_FREQUENCY_PARAM_NAME; +import static org.apache.fineract.portfolio.charge.domain.Charge.FEE_INTERVAL_PARAM_NAME; +import static org.apache.fineract.portfolio.charge.domain.Charge.FEE_ON_MONTH_DAY_PARAM_NAME; +import static org.apache.fineract.portfolio.charge.domain.Charge.LOCALE_PARAM_NAME; + +import jakarta.persistence.PersistenceException; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; +import java.math.BigDecimal; +import java.time.MonthDay; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.LocaleUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.fineract.accounting.glaccount.domain.GLAccount; +import org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper; +import org.apache.fineract.infrastructure.core.exception.ErrorHandler; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType; +import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil; +import org.apache.fineract.portfolio.charge.api.ChargesApiConstants; +import org.apache.fineract.portfolio.charge.data.ChargeCreateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeCreateResponse; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteRequest; +import org.apache.fineract.portfolio.charge.data.ChargeDeleteResponse; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateRequest; +import org.apache.fineract.portfolio.charge.data.ChargeUpdateResponse; +import org.apache.fineract.portfolio.charge.domain.Charge; +import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo; +import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; +import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; +import org.apache.fineract.portfolio.charge.domain.ChargeRepository; +import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; +import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeDeletedException; +import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; +import org.apache.fineract.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException; +import org.apache.fineract.portfolio.charge.exception.ChargeMustBePenaltyException; +import org.apache.fineract.portfolio.charge.exception.ChargeNotFoundException; +import org.apache.fineract.portfolio.charge.exception.ChargeParameterUpdateNotSupportedException; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; +import org.apache.fineract.portfolio.paymenttype.domain.PaymentType; +import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository; +import org.apache.fineract.portfolio.paymenttype.exception.PaymentTypeNotFoundException; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; +import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.orm.jpa.JpaSystemException; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@RequiredArgsConstructor +public class ChargeWriteServiceImpl implements ChargeWriteService { + + private static final String NAME_PARAM_NAME = "name"; + private static final String CURRENCY_CODE_PARAM_NAME = "currencyCode"; + private static final String AMOUNT_PARAM_NAME = "amount"; + private static final String PENALTY_PARAM_NAME = "penalty"; + private static final String ACTIVE_PARAM_NAME = "active"; + private static final String MIN_CAP_PARAM_NAME = "minCap"; + private static final String MAX_CAP_PARAM_NAME = "maxCap"; + private static final String CHARGE_PAYMENT_MODE_PARAM_NAME = "chargePaymentMode"; + private static final String PAYMENT_TYPE_ID_PARAM_NAME = "paymentTypeId"; + private static final String ENABLE_PAYMENT_TYPE_PARAM_NAME = "enablePaymentType"; + private static final String ENABLE_FREE_WITHDRAWAL_PARAM_NAME = "enableFreeWithdrawalCharge"; + private static final String FREE_WITHDRAWAL_FREQUENCY_PARAM_NAME = "freeWithdrawalFrequency"; + private static final String RESTART_COUNT_FREQUENCY_PARAM_NAME = "restartCountFrequency"; + private static final String COUNT_FREQUENCY_TYPE_PARAM_NAME = "countFrequencyType"; + + private final Validator validator; + private final ChargeRepository chargeRepository; + private final LoanProductRepository loanProductRepository; + private final JdbcTemplate jdbcTemplate; + private final FineractEntityAccessUtil fineractEntityAccessUtil; + private final GLAccountRepositoryWrapper glAccountRepository; + private final TaxGroupRepositoryWrapper taxGroupRepository; + private final PaymentTypeRepository paymentTypeRepository; + + @Transactional + @Override + @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") + public ChargeCreateResponse create(final ChargeCreateRequest request) { + try { + validate(request); + + TaxGroup taxGroup = null; + if (request.getTaxGroupId() != null) { + taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(request.getTaxGroupId()); + } + + PaymentType paymentType = null; + if (Boolean.TRUE.equals(request.getEnablePaymentType()) && request.getPaymentTypeId() != null) { + paymentType = findPaymentTypeWithNotFoundDetection(request.getPaymentTypeId()); + } + + final Charge charge = buildCharge(request, taxGroup, paymentType); + this.chargeRepository.saveAndFlush(charge); + + // check if the office specific products are enabled. If yes, then save this charge against a specific + // office i.e. this charge is specific for this office. + fineractEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice( + FineractEntityAccessType.OFFICE_ACCESS_TO_CHARGES, charge.getId()); + + return ChargeCreateResponse.builder().resourceId(charge.getId()).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + handleDataIntegrityIssues(request.getName(), dve.getMostSpecificCause(), dve); + return ChargeCreateResponse.builder().build(); + } catch (final PersistenceException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); + handleDataIntegrityIssues(request.getName(), throwable, dve); + return ChargeCreateResponse.builder().build(); + } + } + + @Transactional + @Override + @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") + public ChargeUpdateResponse update(final ChargeUpdateRequest request) { + try { + final Long chargeId = request.getId(); + final Charge chargeForUpdate = this.chargeRepository.findById(chargeId) + .orElseThrow(() -> new ChargeNotFoundException(chargeId)); + validate(request); + + final Map changes = applyChanges(chargeForUpdate, request); + + // MIFOSX-900: Check if the Charge has been active before and now is deactivated: + if (changes.containsKey(ACTIVE_PARAM_NAME)) { + // IF the key exists then it has changed (otherwise it would have been filtered), so check current + // state: + if (!chargeForUpdate.isActive()) { + final boolean isChargeExistWithLoans = isAnyLoanProductsAssociateWithThisCharge(chargeId); + final boolean isChargeExistWithSavings = isAnySavingsProductsAssociateWithThisCharge(chargeId); + + if (isChargeExistWithLoans || isChargeExistWithSavings) { + throw new ChargeCannotBeUpdatedException("error.msg.charge.cannot.be.updated.it.is.used.in.loan", + "This charge cannot be updated, it is used in loan"); + } + } + } else if ((changes.containsKey(FEE_FREQUENCY_PARAM_NAME) || changes.containsKey(FEE_INTERVAL_PARAM_NAME)) + && chargeForUpdate.isLoanCharge()) { + if (isAnyLoanProductsAssociateWithThisCharge(chargeId)) { + throw new ChargeCannotBeUpdatedException("error.msg.charge.frequency.cannot.be.updated.it.is.used.in.loan", + "This charge frequency cannot be updated, it is used in loan"); + } + } + + // Has account Id been changed ? + if (changes.containsKey(ChargesApiConstants.glAccountIdParamName)) { + final Long newValue = request.getIncomeAccountId(); + GLAccount newIncomeAccount = null; + if (newValue != null) { + newIncomeAccount = this.glAccountRepository.findOneWithNotFoundDetection(newValue); + } + chargeForUpdate.setAccount(newIncomeAccount); + } + + if (changes.containsKey(PAYMENT_TYPE_ID_PARAM_NAME) && request.getPaymentTypeId() != null) { + chargeForUpdate.setPaymentType(findPaymentTypeWithNotFoundDetection(request.getPaymentTypeId())); + } + + if (changes.containsKey(ChargesApiConstants.taxGroupIdParamName)) { + final Long newValue = request.getTaxGroupId(); + TaxGroup taxGroup = null; + if (newValue != null) { + taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(newValue); + } + chargeForUpdate.setTaxGroup(taxGroup); + } + + if (!changes.isEmpty()) { + this.chargeRepository.save(chargeForUpdate); + } + + return ChargeUpdateResponse.builder().resourceId(chargeId).changes(changes).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + handleDataIntegrityIssues(request.getName(), dve.getMostSpecificCause(), dve); + return ChargeUpdateResponse.builder().build(); + } catch (final PersistenceException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); + handleDataIntegrityIssues(request.getName(), throwable, dve); + return ChargeUpdateResponse.builder().build(); + } + } + + @Transactional + @Override + @CacheEvict(value = "charges", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") + public ChargeDeleteResponse delete(final ChargeDeleteRequest request) { + final Long chargeId = request.getId(); + final Charge chargeForDelete = this.chargeRepository.findById(chargeId).orElseThrow(() -> new ChargeNotFoundException(chargeId)); + if (chargeForDelete.isDeleted()) { + throw new ChargeNotFoundException(chargeId); + } + + final Collection loanProducts = this.loanProductRepository.retrieveLoanProductsByChargeId(chargeId); + final boolean isChargeExistWithLoans = isAnyLoansAssociateWithThisCharge(chargeId); + final boolean isChargeExistWithSavings = isAnySavingsAssociateWithThisCharge(chargeId); + final boolean isChargeExistWithWorkingCapitalLoan = chargeRepository.isAnyWorkingCapitalLoansAssociateWithThisCharge(chargeId) + .isPresent(); + + // TODO: Change error messages around: + if (!loanProducts.isEmpty() || isChargeExistWithLoans || isChargeExistWithSavings || isChargeExistWithWorkingCapitalLoan) { + throw new ChargeCannotBeDeletedException("error.msg.charge.cannot.be.deleted.it.is.already.used.in.loan", + "This charge cannot be deleted, it is already used in loan"); + } + + chargeForDelete.delete(); + + this.chargeRepository.save(chargeForDelete); + + return ChargeDeleteResponse.builder().resourceId(chargeForDelete.getId()).build(); + } + + private void validate(final T request) { + final Set> violations = this.validator.validate(request); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + } + + private Charge buildCharge(final ChargeCreateRequest request, final TaxGroup taxGroup, final PaymentType paymentType) { + final ChargeAppliesTo chargeAppliesTo = ChargeAppliesTo.fromInt(request.getChargeAppliesTo()); + final ChargePaymentMode paymentMode = request.getChargePaymentMode() == null + ? (chargeAppliesTo.isWorkingCapitalLoanCharge() ? ChargePaymentMode.REGULAR : null) + : ChargePaymentMode.fromInt(request.getChargePaymentMode()); + final BigDecimal amount = request.getAmount() == null ? null : BigDecimal.valueOf(request.getAmount()); + + // the create contract exposes neither an income account nor the free-withdrawal settings + return new Charge(request.getName(), amount, request.getCurrencyCode(), chargeAppliesTo, + ChargeTimeType.fromInt(request.getChargeTimeType()), ChargeCalculationType.fromInt(request.getChargeCalculationType()), + Boolean.TRUE.equals(request.getPenalty()), Boolean.TRUE.equals(request.getActive()), paymentMode, + request.feeOnMonthDayAsMonthDay(), request.getFeeInterval(), request.getMinCap(), request.getMaxCap(), + request.getFeeFrequency(), false, null, null, null, null, taxGroup, Boolean.TRUE.equals(request.getEnablePaymentType()), + paymentType); + } + + /** + * Applies the (partial) update request to the charge, recording every value that actually changed. Mirrors the + * PATCH semantics of the legacy {@code Charge.update(JsonCommand)}: a field is only touched when it is present in + * the request AND differs from the persisted value. + */ + private Map applyChanges(final Charge charge, final ChargeUpdateRequest request) { + final Map actualChanges = new LinkedHashMap<>(7); + final String localeAsInput = localeLanguage(request); + + if (isChanged(request.getName(), charge.getName())) { + charge.setName(request.getName()); + actualChanges.put(NAME_PARAM_NAME, request.getName()); + } + + if (isChanged(request.getCurrencyCode(), charge.getCurrencyCode())) { + charge.setCurrencyCode(request.getCurrencyCode()); + actualChanges.put(CURRENCY_CODE_PARAM_NAME, request.getCurrencyCode()); + } + + final BigDecimal amount = request.getAmount() == null ? null : BigDecimal.valueOf(request.getAmount()); + if (isChangedAmount(amount, charge.getAmount())) { + charge.setAmount(amount); + actualChanges.put(AMOUNT_PARAM_NAME, amount); + putLocale(actualChanges, localeAsInput); + } + + if (isChanged(request.getChargeTimeType(), charge.getChargeTimeType())) { + charge.setChargeTimeType(ChargeTimeType.fromInt(request.getChargeTimeType()).getValue()); + actualChanges.put(CHARGE_TIME_PARAM_NAME, request.getChargeTimeType()); + putLocale(actualChanges, localeAsInput); + } + + if (isChanged(request.getFreeWithdrawalFrequency(), charge.getFreeWithdrawalFrequency())) { + charge.setFreeWithdrawalFrequency(request.getFreeWithdrawalFrequency()); + actualChanges.put(FREE_WITHDRAWAL_FREQUENCY_PARAM_NAME, request.getFreeWithdrawalFrequency()); + } + + if (isChanged(request.getRestartCountFrequency(), charge.getRestartFrequency())) { + charge.setRestartFrequency(request.getRestartCountFrequency()); + actualChanges.put(RESTART_COUNT_FREQUENCY_PARAM_NAME, request.getRestartCountFrequency()); + } + + if (isChanged(request.getCountFrequencyType(), charge.getRestartFrequencyEnum())) { + // NOTE: the legacy update path resolved this through ChargeTimeType (not PeriodFrequencyType); kept as-is + charge.setRestartFrequencyEnum(ChargeTimeType.fromInt(request.getCountFrequencyType()).getValue()); + actualChanges.put(COUNT_FREQUENCY_TYPE_PARAM_NAME, request.getCountFrequencyType()); + } + + if (isChanged(request.getEnableFreeWithdrawalCharge(), charge.isEnableFreeWithdrawal())) { + charge.setEnableFreeWithdrawal(request.getEnableFreeWithdrawalCharge()); + actualChanges.put(ENABLE_FREE_WITHDRAWAL_PARAM_NAME, request.getEnableFreeWithdrawalCharge()); + } + + if (isChanged(request.getEnablePaymentType(), charge.isEnablePaymentType())) { + charge.setEnablePaymentType(request.getEnablePaymentType()); + actualChanges.put(ENABLE_PAYMENT_TYPE_PARAM_NAME, request.getEnablePaymentType()); + } + + if (isChanged(request.getPaymentTypeId(), charge.getPaymentTypeId())) { + // the payment type itself is resolved and set by the caller + actualChanges.put(PAYMENT_TYPE_ID_PARAM_NAME, request.getPaymentTypeId()); + } + + if (isChanged(request.getChargeAppliesTo(), charge.getChargeAppliesTo())) { + // AA: Do not allow to change chargeAppliesTo. + throw new ChargeParameterUpdateNotSupportedException("charge.applies.to", "Update of Charge applies to is not supported"); + } + + if (isChanged(request.getChargeCalculationType(), charge.getChargeCalculation())) { + charge.setChargeCalculation(ChargeCalculationType.fromInt(request.getChargeCalculationType()).getValue()); + actualChanges.put(CHARGE_CALCULATION_TYPE_PARAM_NAME, request.getChargeCalculationType()); + putLocale(actualChanges, localeAsInput); + } + + // charge payment mode is only meaningful for loan charges + if (charge.isLoanCharge() && isChanged(request.getChargePaymentMode(), charge.getChargePaymentMode())) { + charge.setChargePaymentMode(ChargePaymentMode.fromInt(request.getChargePaymentMode()).getValue()); + actualChanges.put(CHARGE_PAYMENT_MODE_PARAM_NAME, request.getChargePaymentMode()); + putLocale(actualChanges, localeAsInput); + } + + applyFeeOnMonthDayChange(charge, request, actualChanges, localeAsInput); + + if (isChanged(request.getFeeInterval(), charge.getFeeInterval())) { + charge.setFeeInterval(request.getFeeInterval()); + actualChanges.put(FEE_INTERVAL_PARAM_NAME, request.getFeeInterval()); + putLocale(actualChanges, localeAsInput); + } + + if (isChanged(request.getFeeFrequency(), charge.getFeeFrequency())) { + charge.setFeeFrequency(request.getFeeFrequency()); + actualChanges.put(FEE_FREQUENCY_PARAM_NAME, request.getFeeFrequency()); + putLocale(actualChanges, localeAsInput); + } + + if (isChanged(request.getPenalty(), charge.isPenalty())) { + charge.setPenalty(request.getPenalty()); + actualChanges.put(PENALTY_PARAM_NAME, request.getPenalty()); + } + + if (isChanged(request.getActive(), charge.isActive())) { + charge.setActive(request.getActive()); + actualChanges.put(ACTIVE_PARAM_NAME, request.getActive()); + } + + // allow min and max cap to be only added to PERCENT_OF_AMOUNT for now + if (charge.isPercentageOfApprovedAmount()) { + if (isChangedAmount(request.getMinCap(), charge.getMinCap())) { + charge.setMinCap(request.getMinCap()); + actualChanges.put(MIN_CAP_PARAM_NAME, request.getMinCap()); + putLocale(actualChanges, localeAsInput); + } + if (isChangedAmount(request.getMaxCap(), charge.getMaxCap())) { + charge.setMaxCap(request.getMaxCap()); + actualChanges.put(MAX_CAP_PARAM_NAME, request.getMaxCap()); + putLocale(actualChanges, localeAsInput); + } + } + + if (charge.isPenalty() && ChargeTimeType.fromInt(charge.getChargeTimeType()).isTimeOfDisbursement()) { + throw new ChargeDueAtDisbursementCannotBePenaltyException(charge.getName()); + } + if (!charge.isPenalty() && ChargeTimeType.fromInt(charge.getChargeTimeType()).isOverdueInstallment()) { + throw new ChargeMustBePenaltyException(charge.getName()); + } + + if (isChanged(request.getIncomeAccountId(), charge.getIncomeAccountId())) { + // the account itself is resolved and set by the caller + actualChanges.put(ChargesApiConstants.glAccountIdParamName, request.getIncomeAccountId()); + } + + if (isChanged(request.getTaxGroupId(), charge.getTaxGroupId())) { + // the tax group itself is resolved and set by the caller + actualChanges.put(ChargesApiConstants.taxGroupIdParamName, request.getTaxGroupId()); + } + + return actualChanges; + } + + private void applyFeeOnMonthDayChange(final Charge charge, final ChargeUpdateRequest request, final Map actualChanges, + final String localeAsInput) { + if (StringUtils.isBlank(request.getFeeOnMonthDay())) { + return; + } + final MonthDay monthDay = request.feeOnMonthDayAsMonthDay(); + if (monthDay == null) { + return; + } + if (!Objects.equals(charge.getFeeOnDay(), monthDay.getDayOfMonth())) { + charge.setFeeOnDay(monthDay.getDayOfMonth()); + actualChanges.put(FEE_ON_MONTH_DAY_PARAM_NAME, request.getFeeOnMonthDay()); + putLocale(actualChanges, localeAsInput); + } + if (!Objects.equals(charge.getFeeOnMonth(), monthDay.getMonthValue())) { + charge.setFeeOnMonth(monthDay.getMonthValue()); + actualChanges.put(FEE_ON_MONTH_DAY_PARAM_NAME, request.getFeeOnMonthDay()); + putLocale(actualChanges, localeAsInput); + } + } + + private static void putLocale(final Map actualChanges, final String localeAsInput) { + if (localeAsInput != null) { + actualChanges.put(LOCALE_PARAM_NAME, localeAsInput); + } + } + + private static String localeLanguage(final ChargeUpdateRequest request) { + return StringUtils.isBlank(request.getLocale()) ? null : LocaleUtils.toLocale(request.getLocale()).getLanguage(); + } + + private static boolean isChanged(final Object requestValue, final Object currentValue) { + return requestValue != null && !Objects.equals(requestValue, currentValue); + } + + /** + * Amounts must be compared by value, not by scale: {@code 10} and {@code 10.00} are the same amount. + */ + private static boolean isChangedAmount(final BigDecimal requestValue, final BigDecimal currentValue) { + return requestValue != null && (currentValue == null || requestValue.compareTo(currentValue) != 0); + } + + /* + * Guaranteed to throw an exception no matter what the data integrity issue is. + */ + private void handleDataIntegrityIssues(final String name, final Throwable realCause, final Exception dve) { + if (realCause.getMessage().contains(NAME_PARAM_NAME)) { + throw new PlatformDataIntegrityException("error.msg.charge.duplicate.name", "Charge with name `" + name + "` already exists", + NAME_PARAM_NAME, name); + } + + log.error("Error occured.", dve); + throw ErrorHandler.getMappable(dve, "error.msg.charge.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + realCause.getMessage()); + } + + private PaymentType findPaymentTypeWithNotFoundDetection(final Long paymentTypeId) { + return this.paymentTypeRepository.findById(paymentTypeId).orElseThrow(() -> new PaymentTypeNotFoundException(paymentTypeId)); + } + + private boolean isAnyLoansAssociateWithThisCharge(final Long chargeId) { + final String sql = "select (CASE WHEN exists (select 1 from m_loan_charge lc where lc.charge_id = ? and lc.is_active = true) THEN 'true' ELSE 'false' END)"; + final String isLoansUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); + return Boolean.parseBoolean(isLoansUsingCharge); + } + + private boolean isAnySavingsAssociateWithThisCharge(final Long chargeId) { + final String sql = "select (CASE WHEN exists (select 1 from m_savings_account_charge sc where sc.charge_id = ? and sc.is_active = true) THEN 'true' ELSE 'false' END)"; + final String isSavingsUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); + return Boolean.parseBoolean(isSavingsUsingCharge); + } + + private boolean isAnyLoanProductsAssociateWithThisCharge(final Long chargeId) { + final String sql = "select (CASE WHEN exists (select 1 from m_product_loan_charge lc where lc.charge_id = ?) THEN 'true' ELSE 'false' END)"; + final String isLoansUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); + return Boolean.parseBoolean(isLoansUsingCharge); + } + + private boolean isAnySavingsProductsAssociateWithThisCharge(final Long chargeId) { + final String sql = "select (CASE WHEN (exists (select 1 from m_savings_product_charge sc where sc.charge_id = ?)) = 1 THEN 'true' ELSE 'false' END)"; + final String isSavingsUsingCharge = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { chargeId }); + return Boolean.parseBoolean(isSavingsUsingCharge); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/starter/ChargeConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/starter/ChargeConfiguration.java index edc8f72e08b..51612372ebe 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/starter/ChargeConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/starter/ChargeConfiguration.java @@ -18,20 +18,19 @@ */ package org.apache.fineract.portfolio.charge.starter; +import jakarta.validation.Validator; import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService; import org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainServiceJpa; import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.domain.ChargeRepository; -import org.apache.fineract.portfolio.charge.serialization.ChargeDefinitionCommandFromApiJsonDeserializer; import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService; import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformServiceImpl; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformServiceImpl; -import org.apache.fineract.portfolio.charge.service.ChargeWritePlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeWritePlatformServiceJpaRepositoryImpl; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; +import org.apache.fineract.portfolio.charge.service.ChargeReadServiceImpl; +import org.apache.fineract.portfolio.charge.service.ChargeWriteService; +import org.apache.fineract.portfolio.charge.service.ChargeWriteServiceImpl; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository; @@ -53,25 +52,24 @@ public ChargeDropdownReadPlatformService chargeDropdownReadPlatformService() { } @Bean - @ConditionalOnMissingBean(ChargeReadPlatformService.class) - public ChargeReadPlatformService chargeReadPlatformService(CurrencyReadPlatformService currencyReadPlatformService, + @ConditionalOnMissingBean(ChargeReadService.class) + public ChargeReadService chargeReadService(CurrencyReadPlatformService currencyReadPlatformService, ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, JdbcTemplate jdbcTemplate, DropdownReadPlatformService dropdownReadPlatformService, FineractEntityAccessUtil fineractEntityAccessUtil, AccountingDropdownReadPlatformService accountingDropdownReadPlatformService, TaxReadPlatformService taxReadPlatformService, ConfigurationDomainServiceJpa configurationDomainServiceJpa, NamedParameterJdbcTemplate namedParameterJdbcTemplate) { - return new ChargeReadPlatformServiceImpl(currencyReadPlatformService, chargeDropdownReadPlatformService, jdbcTemplate, + return new ChargeReadServiceImpl(currencyReadPlatformService, chargeDropdownReadPlatformService, jdbcTemplate, dropdownReadPlatformService, fineractEntityAccessUtil, accountingDropdownReadPlatformService, taxReadPlatformService, configurationDomainServiceJpa, namedParameterJdbcTemplate); } @Bean - @ConditionalOnMissingBean(ChargeWritePlatformService.class) - public ChargeWritePlatformService chargeWritePlatformService(PlatformSecurityContext context, - ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, ChargeRepository chargeRepository, + @ConditionalOnMissingBean(ChargeWriteService.class) + public ChargeWriteService chargeWriteService(Validator validator, ChargeRepository chargeRepository, LoanProductRepository loanProductRepository, JdbcTemplate jdbcTemplate, FineractEntityAccessUtil fineractEntityAccessUtil, GLAccountRepositoryWrapper glAccountRepository, TaxGroupRepositoryWrapper taxGroupRepository, PaymentTypeRepository paymentTypeRepository) { - return new ChargeWritePlatformServiceJpaRepositoryImpl(context, fromApiJsonDeserializer, chargeRepository, loanProductRepository, - jdbcTemplate, fineractEntityAccessUtil, glAccountRepository, taxGroupRepository, paymentTypeRepository); + return new ChargeWriteServiceImpl(validator, chargeRepository, loanProductRepository, jdbcTemplate, fineractEntityAccessUtil, + glAccountRepository, taxGroupRepository, paymentTypeRepository); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java index 01bf74f1a43..a0fa067e116 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java @@ -56,7 +56,7 @@ import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.data.ClientChargeData; import org.apache.fineract.portfolio.client.data.ClientTransactionData; import org.apache.fineract.portfolio.client.service.ClientChargeReadPlatformService; @@ -73,7 +73,7 @@ public class ClientChargesApiResource { private final PlatformSecurityContext context; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final ClientChargeReadPlatformService clientChargeReadPlatformService; private final ClientTransactionReadPlatformService clientTransactionReadPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; @@ -121,7 +121,7 @@ public String retrieveTemplate(@Context final UriInfo uriInfo, this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); - final Collection chargeOptions = this.chargeReadPlatformService.retrieveAllChargesApplicableToClients(); + final Collection chargeOptions = this.chargeReadService.retrieveAllChargesApplicableToClients(); final ClientChargeData clientChargeData = ClientChargeData.template(chargeOptions); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResource.java index e4745522dd7..91c59c5d07c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResource.java @@ -60,7 +60,7 @@ import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService; @@ -85,7 +85,7 @@ public class LoanChargesApiResource { "amount", "amountPaid", "chargeOptions", "installmentChargeData", "externalId")); private static final String RESOURCE_NAME_FOR_PERMISSIONS = "LOAN"; private final PlatformSecurityContext context; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final LoanChargeReadPlatformService loanChargeReadPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; @@ -526,7 +526,7 @@ private String retrieveTemplate(final Long loanId, final String loanExternalIdSt ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); Long resolvedLoanId = loanId == null ? loanReadPlatformService.getResolvedLoanId(loanExternalId) : loanId; - final List chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(resolvedLoanId, + final List chargeOptions = this.chargeReadService.retrieveLoanAccountApplicableCharges(resolvedLoanId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT }); final LoanChargeData loanChargeTemplate = LoanChargeData.template(chargeOptions); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index bf01e5c2a8a..82f864b40e0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -109,7 +109,7 @@ import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.collateralmanagement.data.LoanCollateralResponseData; @@ -279,7 +279,7 @@ public class LoansApiResource { private final LoanProductReadPlatformService loanProductReadPlatformService; private final LoanDropdownReadPlatformService dropdownReadPlatformService; private final FundReadPlatformService fundReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final LoanChargeReadPlatformService loanChargeReadPlatformService; private final LoanScheduleCalculationPlatformService calculationPlatformService; private final GuarantorReadPlatformService guarantorReadPlatformService; @@ -1232,10 +1232,10 @@ private String retrieveLoan(final Long loanId, final String loanExternalIdStr, b fundOptions = this.fundReadPlatformService.retrieveAllFunds(); repaymentStrategyOptions = this.dropdownReadPlatformService.retrieveTransactionProcessingStrategies(); if (product.getMultiDisburseLoan()) { - chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(resolvedLoanId, + chargeOptions = this.chargeReadService.retrieveLoanAccountApplicableCharges(resolvedLoanId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT }); } else { - chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(resolvedLoanId, + chargeOptions = this.chargeReadService.retrieveLoanAccountApplicableCharges(resolvedLoanId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT }); } chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate(); @@ -1274,8 +1274,8 @@ private String retrieveLoan(final Long loanId, final String loanExternalIdStr, b } - Collection overdueCharges = this.chargeReadPlatformService - .retrieveLoanProductCharges(loanBasicDetails.getLoanProductId(), ChargeTimeType.OVERDUE_INSTALLMENT); + Collection overdueCharges = this.chargeReadService.retrieveLoanProductCharges(loanBasicDetails.getLoanProductId(), + ChargeTimeType.OVERDUE_INSTALLMENT); paidInAdvanceTemplate = this.loanReadPlatformService.retrieveTotalPaidInAdvance(resolvedLoanId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 90802d4efbe..0057ad99840 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -78,7 +78,7 @@ import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.domain.ClientEnumerations; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; @@ -175,7 +175,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa private final GroupReadPlatformService groupReadPlatformService; private final LoanDropdownReadPlatformService loanDropdownReadPlatformService; private final FundReadPlatformService fundReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final CodeValueReadPlatformService codeValueReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService; private final StaffReadService staffReadPlatformService; @@ -1492,10 +1492,10 @@ public LoanAccountData retrieveLoanProductDetailsTemplate(final Long productId, .retrieveCodeValuesByCode("LoanCollateral"); Collection chargeOptions = null; if (loanProduct.getMultiDisburseLoan()) { - chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId, + chargeOptions = this.chargeReadService.retrieveLoanProductApplicableCharges(productId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT }); } else { - chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId, + chargeOptions = this.chargeReadService.retrieveLoanProductApplicableCharges(productId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT }); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java index fa99902f783..d3e591f4f6d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java @@ -53,7 +53,7 @@ import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralAssembler; @@ -340,7 +340,7 @@ public LoanReadPlatformServiceImpl loanReadPlatformService(JdbcTemplate jdbcTemp LoanRepositoryWrapper loanRepositoryWrapper, ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, LoanProductReadPlatformService loanProductReadPlatformService, ClientReadPlatformService clientReadPlatformService, GroupReadPlatformService groupReadPlatformService, LoanDropdownReadPlatformService loanDropdownReadPlatformService, - FundReadPlatformService fundReadPlatformService, ChargeReadPlatformService chargeReadPlatformService, + FundReadPlatformService fundReadPlatformService, ChargeReadService chargeReadService, CodeValueReadPlatformService codeValueReadPlatformService, CalendarReadPlatformService calendarReadPlatformService, StaffReadService staffReadPlatformService, PaginationHelper paginationHelper, PaymentTypeReadService paymentTypeReadPlatformService, FloatingRatesReadPlatformService floatingRatesReadPlatformService, @@ -356,7 +356,7 @@ public LoanReadPlatformServiceImpl loanReadPlatformService(JdbcTemplate jdbcTemp LoanRepaymentScheduleService loanRepaymentScheduleService) { return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository, loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService, - fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService, + fundReadPlatformService, chargeReadService, codeValueReadPlatformService, calendarReadPlatformService, staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService, floatingRatesReadPlatformService, loanUtilService, configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator, delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index 14c06149a86..e0671173f60 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -75,7 +75,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData; @@ -154,7 +154,7 @@ public class LoanProductsApiResource { private final PlatformSecurityContext context; private final LoanProductReadPlatformService loanProductReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final CurrencyReadPlatformService currencyReadPlatformService; private final FundReadPlatformService fundReadPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; @@ -391,12 +391,12 @@ private String getLoanProductDetails(Long productId, UriInfo uriInfo) { private LoanProductData handleTemplate(final LoanProductData productData) { - Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableFees(); + Collection chargeOptions = this.chargeReadService.retrieveLoanApplicableFees(); if (chargeOptions.isEmpty()) { chargeOptions = null; } - Collection penaltyOptions = this.chargeReadPlatformService.retrieveLoanApplicablePenalties(); + Collection penaltyOptions = this.chargeReadService.retrieveLoanApplicablePenalties(); if (penaltyOptions.isEmpty()) { penaltyOptions = null; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index cd86e81bfd1..bcf8e39acac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -41,7 +41,7 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; import org.apache.fineract.portfolio.common.service.CommonEnumerations; import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData; @@ -83,7 +83,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo private final PlatformSecurityContext context; private final JdbcTemplate jdbcTemplate; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final RateReadService rateReadService; private final DatabaseSpecificSQLGenerator sqlGenerator; private final FineractEntityAccessUtil fineractEntityAccessUtil; @@ -94,7 +94,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo public LoanProductData retrieveLoanProduct(final Long loanProductId) { try { - final Collection charges = this.chargeReadPlatformService.retrieveLoanProductCharges(loanProductId); + final Collection charges = this.chargeReadService.retrieveLoanProductCharges(loanProductId); final Collection rates = this.rateReadService.retrieveProductLoanRates(loanProductId); final Collection borrowerCycleVariationDatas = retrieveLoanProductBorrowerCycleVariations( loanProductId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java index e5617d0c193..1e78dfc72b6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java @@ -24,7 +24,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository; import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper; @@ -64,10 +64,10 @@ public LoanDropdownReadPlatformService loanDropdownReadPlatformService( @Bean @ConditionalOnMissingBean(LoanProductReadPlatformService.class) public LoanProductReadPlatformService loanProductReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate, - ChargeReadPlatformService chargeReadPlatformService, RateReadService rateReadService, DatabaseSpecificSQLGenerator sqlGenerator, + ChargeReadService chargeReadService, RateReadService rateReadService, DatabaseSpecificSQLGenerator sqlGenerator, FineractEntityAccessUtil fineractEntityAccessUtil, DelinquencyReadPlatformService delinquencyReadPlatformService, LoanProductRepository loanProductRepository) { - return new LoanProductReadPlatformServiceImpl(context, jdbcTemplate, chargeReadPlatformService, rateReadService, sqlGenerator, + return new LoanProductReadPlatformServiceImpl(context, jdbcTemplate, chargeReadService, rateReadService, sqlGenerator, fineractEntityAccessUtil, delinquencyReadPlatformService, loanProductRepository); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResource.java index 4f7515d75c7..4b0dd84b588 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResource.java @@ -62,7 +62,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData; import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartReadService; @@ -104,7 +104,7 @@ public class FixedDepositProductsApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final InterestRateChartReadService chartReadPlatformService; private final InterestRateChartReadService interestRateChartReadPlatformService; private final DepositsDropdownReadPlatformService depositsDropdownReadPlatformService; @@ -208,7 +208,7 @@ public String retrieveOne(@PathParam("productId") @Parameter(description = "prod FixedDepositProductData fixedDepositProductData = (FixedDepositProductData) this.depositProductReadPlatformService .retrieveOne(DepositAccountType.FIXED_DEPOSIT, productId); - final Collection charges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + final Collection charges = this.chargeReadService.retrieveSavingsProductCharges(productId); fixedDepositProductData = FixedDepositProductData.withCharges(fixedDepositProductData, charges); final Collection charts = this.chartReadPlatformService.retrieveAllWithSlabsWithTemplate(productId); @@ -308,10 +308,10 @@ private FixedDepositProductData handleTemplateRelatedData(final FixedDepositProd // charges final boolean feeChargesOnly = true; - Collection chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly); + Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); chargeOptions = CollectionUtils.isEmpty(chargeOptions) ? null : chargeOptions; - Collection penaltyOptions = this.chargeReadPlatformService.retrieveSavingsApplicablePenalties(); + Collection penaltyOptions = this.chargeReadService.retrieveSavingsApplicablePenalties(); penaltyOptions = CollectionUtils.isEmpty(penaltyOptions) ? null : penaltyOptions; final Collection taxGroupOptions = this.taxReadPlatformService.retrieveTaxGroupsForLookUp(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResource.java index 4d566c91862..032c34b19f5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResource.java @@ -63,7 +63,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData; import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartReadService; @@ -104,7 +104,7 @@ public class RecurringDepositProductsApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final InterestRateChartReadService chartReadPlatformService; private final InterestRateChartReadService interestRateChartReadPlatformService; private final DepositsDropdownReadPlatformService depositsDropdownReadPlatformService; @@ -191,7 +191,7 @@ public String retrieveOne(@PathParam("productId") @Parameter(description = "prod RecurringDepositProductData recurringDepositProductData = (RecurringDepositProductData) this.depositProductReadPlatformService .retrieveOne(DepositAccountType.RECURRING_DEPOSIT, productId); - final Collection charges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + final Collection charges = this.chargeReadService.retrieveSavingsProductCharges(productId); recurringDepositProductData = RecurringDepositProductData.withCharges(recurringDepositProductData, charges); final Collection charts = this.chartReadPlatformService.retrieveAllWithSlabsWithTemplate(productId); @@ -286,10 +286,10 @@ private RecurringDepositProductData handleTemplateRelatedData(final RecurringDep // charges final boolean feeChargesOnly = true; - Collection chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly); + Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); chargeOptions = CollectionUtils.isEmpty(chargeOptions) ? null : chargeOptions; - Collection penaltyOptions = this.chargeReadPlatformService.retrieveSavingsApplicablePenalties(); + Collection penaltyOptions = this.chargeReadService.retrieveSavingsApplicablePenalties(); penaltyOptions = CollectionUtils.isEmpty(penaltyOptions) ? null : penaltyOptions; final Collection periodFrequencyTypeOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountChargesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountChargesApiResource.java index de6a37c14b5..8a5fd0b5e18 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountChargesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountChargesApiResource.java @@ -59,7 +59,7 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData; import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService; import org.springframework.stereotype.Component; @@ -73,7 +73,7 @@ public class SavingsAccountChargesApiResource { private final PlatformSecurityContext context; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final SavingsAccountChargeReadPlatformService savingsAccountChargeReadPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; @@ -124,8 +124,7 @@ public String retrieveTemplate(@PathParam("savingsAccountId") @Parameter(descrip this.context.authenticatedUser().validateHasReadPermission(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME); - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsAccountApplicableCharges(savingsAccountId); + final Collection chargeOptions = this.chargeReadService.retrieveSavingsAccountApplicableCharges(savingsAccountId); final SavingsAccountChargeData savingsAccountChargeTemplate = SavingsAccountChargeData.template(chargeOptions); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java index d3297002844..e51371a3bf2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java @@ -63,7 +63,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData; import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService; import org.apache.fineract.portfolio.savings.SavingsApiConstants; @@ -96,7 +96,7 @@ public class SavingsProductsApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final PaymentTypeReadService paymentTypeReadPlatformService; private final TaxReadPlatformService taxReadPlatformService; private final ConfigurationDomainService configurationDomainService; @@ -171,7 +171,7 @@ public String retrieveOne(@PathParam("productId") @Parameter(description = "prod SavingsProductData savingProductData = this.savingProductReadPlatformService.retrieveOne(productId); - final Collection charges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + final Collection charges = this.chargeReadService.retrieveSavingsProductCharges(productId); savingProductData = SavingsProductData.withCharges(savingProductData, charges); @@ -266,10 +266,10 @@ private SavingsProductData handleTemplateRelatedData(final SavingsProductData sa // charges final boolean feeChargesOnly = false; - Collection chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly); + Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); chargeOptions = CollectionUtils.isEmpty(chargeOptions) ? null : chargeOptions; - Collection penaltyOptions = this.chargeReadPlatformService.retrieveSavingsApplicablePenalties(); + Collection penaltyOptions = this.chargeReadService.retrieveSavingsApplicablePenalties(); penaltyOptions = CollectionUtils.isEmpty(penaltyOptions) ? null : penaltyOptions; final Collection taxGroupOptions = this.taxReadPlatformService.retrieveTaxGroupsForLookUp(); SavingsProductData savingsProductToReturn = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java index 5f9aceb03b4..18cf5a51b2c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java @@ -55,7 +55,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; @@ -120,7 +120,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead private final GroupReadPlatformService groupReadPlatformService; private final DepositProductReadPlatformService depositProductReadPlatformService; private final SavingsDropdownReadPlatformService savingsDropdownReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final StaffReadService staffReadPlatformService; private final DepositsDropdownReadPlatformService depositsDropdownReadPlatformService; private final SavingsAccountReadPlatformService savingsAccountReadPlatformService; @@ -343,13 +343,12 @@ public DepositAccountData retrieveTemplate(final DepositAccountType depositAccou .retrievewithdrawalFeeTypeOptions(); final Collection transactions = null; - final Collection productCharges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + final Collection productCharges = this.chargeReadService.retrieveSavingsProductCharges(productId); // update charges from Product charges final Collection charges = fromChargesToSavingsCharges(productCharges); final boolean feeChargesOnly = false; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); + final Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); final Collection maturityInstructionOptions = this.depositsDropdownReadPlatformService .maturityInstructionOptions(); @@ -429,8 +428,7 @@ public DepositAccountData retrieveTemplate(final DepositAccountType depositAccou final Collection maturityInstructionOptions = null; final boolean feeChargesOnly = true; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); + final Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); if (depositAccountType == DepositAccountType.FIXED_DEPOSIT) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java index 8d9b95c9b5a..55cfa6cbdc1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java @@ -37,7 +37,7 @@ import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.service.StaffReadService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; @@ -71,14 +71,14 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc private final SavingsProductReadPlatformService savingsProductReadPlatformService; private final StaffReadService staffReadPlatformService; private final SavingsDropdownReadPlatformService dropdownReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final EntityDatatableChecksReadService entityDatatableChecksReadService; public SavingsAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate, final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService, final SavingsProductReadPlatformService savingProductReadPlatformService, final StaffReadService staffReadPlatformService, - final SavingsDropdownReadPlatformService dropdownReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService, + final SavingsDropdownReadPlatformService dropdownReadPlatformService, final ChargeReadService chargeReadService, final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator) { this.context = context; this.jdbcTemplate = jdbcTemplate; @@ -87,7 +87,7 @@ public SavingsAccountTemplateReadPlatformServiceImpl(final PlatformSecurityConte this.savingsProductReadPlatformService = savingProductReadPlatformService; this.staffReadPlatformService = staffReadPlatformService; this.dropdownReadPlatformService = dropdownReadPlatformService; - this.chargeReadPlatformService = chargeReadPlatformService; + this.chargeReadService = chargeReadService; this.entityDatatableChecksReadService = entityDatatableChecksReadService; } @@ -137,13 +137,12 @@ public SavingsAccountData retrieveTemplate(final Long clientId, final Long group final Collection withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions(); final Collection transactions = null; - final Collection productCharges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + final Collection productCharges = this.chargeReadService.retrieveSavingsProductCharges(productId); // update charges from Product charges final Collection charges = fromChargesToSavingsCharges(productCharges); final boolean feeChargesOnly = false; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); + final Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); Collection fieldOfficerOptions = null; @@ -201,8 +200,7 @@ public SavingsAccountData retrieveTemplate(final Long clientId, final Long group final Collection charges = null; final boolean feeChargesOnly = false; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); + final Collection chargeOptions = this.chargeReadService.retrieveSavingsProductApplicableCharges(feeChargesOnly); template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java index 78cbb2b386a..db82c84c33a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java @@ -54,7 +54,7 @@ import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; @@ -210,13 +210,13 @@ public DepositAccountReadPlatformService depositAccountReadPlatformService(Platf PaginationParametersDataValidator paginationParametersDataValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper, ClientReadPlatformService clientReadPlatformService, GroupReadPlatformService groupReadPlatformService, DepositProductReadPlatformService depositProductReadPlatformService, - SavingsDropdownReadPlatformService savingsDropdownReadPlatformService, ChargeReadPlatformService chargeReadPlatformService, + SavingsDropdownReadPlatformService savingsDropdownReadPlatformService, ChargeReadService chargeReadService, StaffReadService staffReadPlatformService, DepositsDropdownReadPlatformService depositsDropdownReadPlatformService, SavingsAccountReadPlatformService savingsAccountReadPlatformService, DropdownReadPlatformService dropdownReadPlatformService, CalendarReadPlatformService calendarReadPlatformService, PaymentTypeReadService paymentTypeReadPlatformService) { return new DepositAccountReadPlatformServiceImpl(context, jdbcTemplate, chartReadPlatformService, productChartReadPlatformService, paginationParametersDataValidator, sqlGenerator, paginationHelper, clientReadPlatformService, groupReadPlatformService, - depositProductReadPlatformService, savingsDropdownReadPlatformService, chargeReadPlatformService, staffReadPlatformService, + depositProductReadPlatformService, savingsDropdownReadPlatformService, chargeReadService, staffReadPlatformService, depositsDropdownReadPlatformService, savingsAccountReadPlatformService, dropdownReadPlatformService, calendarReadPlatformService, paymentTypeReadPlatformService); } @@ -372,10 +372,10 @@ public SavingsAccountTemplateReadPlatformService savingsAccountTemplateReadPlatf JdbcTemplate jdbcTemplate, ClientReadPlatformService clientReadPlatformService, GroupReadPlatformService groupReadPlatformService, SavingsProductReadPlatformService savingProductReadPlatformService, StaffReadService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService, - ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService, + ChargeReadService chargeReadService, EntityDatatableChecksReadService entityDatatableChecksReadService, ColumnValidator columnValidator) { return new SavingsAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService, - savingProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService, + savingProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadService, entityDatatableChecksReadService, columnValidator); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java index a6f807f83f8..19febc271b0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java @@ -41,7 +41,7 @@ import org.apache.fineract.portfolio.accounts.data.AccountData; import org.apache.fineract.portfolio.accounts.exceptions.ShareAccountNotFoundException; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; @@ -71,7 +71,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlatformService { private final ApplicationContext applicationContext; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService; private final SavingsAccountReadPlatformService savingsAccountReadPlatformService; private final ClientReadPlatformService clientReadPlatformService; @@ -92,7 +92,7 @@ public ShareAccountData retrieveTemplate(Long clientId, Long productId) { if (productId != null) { final ShareProductData productData = (ShareProductData) service.retrieveOne(productId, false); final BigDecimal marketPrice = deriveMarketPrice(productData); - final Collection productCharges = this.chargeReadPlatformService.retrieveShareProductCharges(productId); + final Collection productCharges = this.chargeReadService.retrieveShareProductCharges(productId); final Collection charges = convertChargesToShareAccountCharges(productCharges); final Collection lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService .retrieveLockinPeriodFrequencyTypeOptions(); @@ -105,7 +105,7 @@ public ShareAccountData retrieveTemplate(Long clientId, Long productId) { productData.getNominalShares()); } else { Collection productOptions = service.retrieveAllForLookup(); - final Collection chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges(); + final Collection chargeOptions = this.chargeReadService.retrieveSharesApplicableCharges(); toReturn = new ShareAccountData(client.getId(), client.getDisplayName(), productOptions, chargeOptions); } return toReturn; @@ -150,7 +150,7 @@ public ShareAccountData retrieveOne(final Long id, final boolean includeTemplate final Collection clientSavingsAccounts = this.savingsAccountReadPlatformService .retrieveActiveForLookup(data.getClientId(), DepositAccountType.SAVINGS_DEPOSIT, productData.getCurrency().getCode()); Collection productOptions = service.retrieveAllForLookup(); - final Collection chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges(); + final Collection chargeOptions = this.chargeReadService.retrieveSharesApplicableCharges(); data = ShareAccountData.template(data, productOptions, chargeOptions, clientSavingsAccounts, lockinPeriodFrequencyTypeOptions, minimumActivePeriodFrequencyTypeOptions); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java index 6daf958342d..1200b43bc1f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java @@ -28,7 +28,7 @@ import org.apache.fineract.portfolio.account.service.AccountNumberGenerator; import org.apache.fineract.portfolio.accounts.constants.AccountsApiConstants; import org.apache.fineract.portfolio.accounts.service.AccountsCommandsService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.note.domain.NoteRepository; import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler; @@ -91,15 +91,14 @@ public ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformS @Bean(value = "share" + AccountsApiConstants.READPLATFORM_NAME) @ConditionalOnMissingBean(ShareAccountReadPlatformService.class) public ShareAccountReadPlatformService shareAccountReadPlatformService(ApplicationContext applicationContext, - ChargeReadPlatformService chargeReadPlatformService, - ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService, + ChargeReadService chargeReadService, ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService, SavingsAccountReadPlatformService savingsAccountReadPlatformService, ClientReadPlatformService clientReadPlatformService, ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService, PurchasedSharesReadPlatformService purchasedSharesReadPlatformService, JdbcTemplate jdbcTemplate, PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) { - return new ShareAccountReadPlatformServiceImpl(applicationContext, chargeReadPlatformService, - shareProductDropdownReadPlatformService, savingsAccountReadPlatformService, clientReadPlatformService, - shareAccountChargeReadPlatformService, purchasedSharesReadPlatformService, jdbcTemplate, paginationHelper, sqlGenerator); + return new ShareAccountReadPlatformServiceImpl(applicationContext, chargeReadService, shareProductDropdownReadPlatformService, + savingsAccountReadPlatformService, clientReadPlatformService, shareAccountChargeReadPlatformService, + purchasedSharesReadPlatformService, jdbcTemplate, paginationHelper, sqlGenerator); } @Bean diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java index 7b3ac127491..054f65e5280 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java @@ -42,7 +42,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.products.data.ProductData; import org.apache.fineract.portfolio.products.exception.ProductNotFoundException; import org.apache.fineract.portfolio.products.service.ShareProductReadPlatformService; @@ -58,7 +58,7 @@ public class ShareProductReadPlatformServiceImpl implements ShareProductReadPlat private final JdbcTemplate jdbcTemplate; private final CurrencyReadPlatformService currencyReadPlatformService; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService; private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; @@ -92,7 +92,7 @@ public ProductData retrieveOne(Long productId, boolean includeTemplate) { final String sql1 = "select " + marketRowMapper.schema() + " where marketData.product_id = ?"; final Collection shareMarketCollection = this.jdbcTemplate.query(sql1, marketRowMapper, // NOSONAR new Object[] { productId }); - final Collection charges = this.chargeReadPlatformService.retrieveShareProductCharges(productId); + final Collection charges = this.chargeReadService.retrieveShareProductCharges(productId); ShareProductRowMapper mapper = new ShareProductRowMapper(shareMarketCollection, charges); final String sql = "select " + mapper.schema() + " where shareproduct.id = ?"; ShareProductData data = (ShareProductData) this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId }); // NOSONAR @@ -109,7 +109,7 @@ public ProductData retrieveOne(Long productId, boolean includeTemplate) { } if (includeTemplate) { - Collection chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges(); + Collection chargeOptions = this.chargeReadService.retrieveSharesApplicableCharges(); final Collection currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies(); final Collection lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService .retrieveLockinPeriodFrequencyTypeOptions(); @@ -128,7 +128,7 @@ public ProductData retrieveOne(Long productId, boolean includeTemplate) { @Override public ProductData retrieveTemplate() { - Collection chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges(); + Collection chargeOptions = this.chargeReadService.retrieveSharesApplicableCharges(); final Collection currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies(); final Collection lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService .retrieveLockinPeriodFrequencyTypeOptions(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/starter/ShareProductsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/starter/ShareProductsConfiguration.java index 2cbe6469d5c..c3ab16601ff 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/starter/ShareProductsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/starter/ShareProductsConfiguration.java @@ -27,7 +27,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.products.service.ShareProductReadPlatformService; import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService; import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividentPayOutDetailsRepositoryWrapper; @@ -82,12 +82,12 @@ public ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformS @Bean(value = "shareReadPlatformService") @ConditionalOnMissingBean(ShareProductReadPlatformService.class) public ShareProductReadPlatformService shareProductReadPlatformService(JdbcTemplate jdbcTemplate, - CurrencyReadPlatformService currencyReadPlatformService, ChargeReadPlatformService chargeReadPlatformService, + CurrencyReadPlatformService currencyReadPlatformService, ChargeReadService chargeReadService, ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService, AccountingDropdownReadPlatformService accountingDropdownReadPlatformService, ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService, PaginationHelper shareProductDataPaginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) { - return new ShareProductReadPlatformServiceImpl(jdbcTemplate, currencyReadPlatformService, chargeReadPlatformService, + return new ShareProductReadPlatformServiceImpl(jdbcTemplate, currencyReadPlatformService, chargeReadService, shareProductDropdownReadPlatformService, accountingDropdownReadPlatformService, accountMappingReadPlatformService, shareProductDataPaginationHelper, sqlGenerator); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceRetrieveApprovalTemplateTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceRetrieveApprovalTemplateTest.java index 64a0e3685f0..c0a8c4a9dca 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceRetrieveApprovalTemplateTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceRetrieveApprovalTemplateTest.java @@ -41,7 +41,7 @@ import org.apache.fineract.portfolio.account.service.PortfolioAccountReadPlatformService; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralManagementReadService; import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; @@ -125,7 +125,7 @@ private static LoansApiResource newLoansApiResource(PlatformSecurityContext cont ApiRequestParameterHelper helper = mock(ApiRequestParameterHelper.class); return new LoansApiResource(context, loanReadPlatformService, mock(LoanProductReadPlatformService.class), - mock(LoanDropdownReadPlatformService.class), mock(FundReadPlatformService.class), mock(ChargeReadPlatformService.class), + mock(LoanDropdownReadPlatformService.class), mock(FundReadPlatformService.class), mock(ChargeReadService.class), mock(LoanChargeReadPlatformService.class), mock(LoanScheduleCalculationPlatformService.class), mock(GuarantorReadPlatformService.class), mock(CodeValueReadPlatformService.class), mock(GroupReadPlatformService.class), mock(DefaultToApiJsonSerializer.class), mock(DefaultToApiJsonSerializer.class), mock(DefaultToApiJsonSerializer.class), diff --git a/fineract-validation/src/main/resources/ValidationMessages.properties b/fineract-validation/src/main/resources/ValidationMessages.properties index c5fd63504a6..b7499b0f8c6 100644 --- a/fineract-validation/src/main/resources/ValidationMessages.properties +++ b/fineract-validation/src/main/resources/ValidationMessages.properties @@ -135,3 +135,46 @@ org.apache.fineract.portfolio.meeting.date-format.not-null=The parameter 'dateFo org.apache.fineract.portfolio.meeting.locale.not-null=The parameter 'locale' is mandatory org.apache.fineract.portfolio.meeting.attendance.client-id.not-null=The parameter 'clientId' is mandatory org.apache.fineract.portfolio.meeting.attendance.attendance-type.not-null=The parameter 'attendanceType' is mandatory + +# charges + +org.apache.fineract.portfolio.charge.name.not-blank=The parameter 'name' is mandatory +org.apache.fineract.portfolio.charge.name.max=The parameter 'name' exceeds the maximum size of {max} characters +org.apache.fineract.portfolio.charge.currency-code.not-blank=The parameter 'currencyCode' is mandatory +org.apache.fineract.portfolio.charge.currency-code.max=The parameter 'currencyCode' exceeds the maximum size of {max} characters +org.apache.fineract.portfolio.charge.amount.not-null=The parameter 'amount' is mandatory +org.apache.fineract.portfolio.charge.amount.positive=The parameter 'amount' must be greater than zero +org.apache.fineract.portfolio.charge.min-cap.positive=The parameter 'minCap' must be greater than zero +org.apache.fineract.portfolio.charge.max-cap.positive=The parameter 'maxCap' must be greater than zero +org.apache.fineract.portfolio.charge.charge-applies-to.not-null=The parameter 'chargeAppliesTo' is mandatory +org.apache.fineract.portfolio.charge.charge-applies-to.invalid=The parameter 'chargeAppliesTo' is not one of the supported values +org.apache.fineract.portfolio.charge.charge-time-type.not-null=The parameter 'chargeTimeType' is mandatory +org.apache.fineract.portfolio.charge.charge-time-type.invalid=The parameter 'chargeTimeType' is not one of the values supported for this 'chargeAppliesTo' +org.apache.fineract.portfolio.charge.charge-time-type.not-allowed-for-savings=The parameter 'chargeTimeType' is not allowed for a savings charge +org.apache.fineract.portfolio.charge.charge-time-type.not-allowed-for-loan=The parameter 'chargeTimeType' is not allowed for a loan charge +org.apache.fineract.portfolio.charge.charge-time-type.not-allowed-for-client=The parameter 'chargeTimeType' is not allowed for a client charge +org.apache.fineract.portfolio.charge.charge-calculation-type.not-null=The parameter 'chargeCalculationType' is mandatory +org.apache.fineract.portfolio.charge.charge-calculation-type.range=The parameter 'chargeCalculationType' must be between 1 and 5 +org.apache.fineract.portfolio.charge.charge-calculation-type.invalid=The parameter 'chargeCalculationType' is not one of the values supported for this 'chargeAppliesTo' +org.apache.fineract.portfolio.charge.charge-calculation-type.not-allowed-for-savings=The parameter 'chargeCalculationType' is not allowed for a savings charge +org.apache.fineract.portfolio.charge.charge-calculation-type.not-allowed-for-client=The parameter 'chargeCalculationType' is not allowed for a client charge +org.apache.fineract.portfolio.charge.charge-calculation-type.percentage-only-for-withdrawal-or-no-activity=The parameter 'chargeCalculationType' can only be a percentage of amount for a withdrawal or no-activity fee +org.apache.fineract.portfolio.charge.charge-calculation-type.invalid-for-share-account-activation=The parameter 'chargeCalculationType' is not one of the values supported for a share account activation charge +org.apache.fineract.portfolio.charge.charge-calculation-type.invalid-for-tranche-disbursement=The parameter 'chargeCalculationType' is not one of the values supported for a tranche disbursement charge +org.apache.fineract.portfolio.charge.charge-calculation-type.percent-of-disbursement-not-allowed=The parameter 'chargeCalculationType' cannot be a percentage of the disbursement amount for this 'chargeTimeType' +org.apache.fineract.portfolio.charge.charge-payment-mode.not-null=The parameter 'chargePaymentMode' is mandatory +org.apache.fineract.portfolio.charge.charge-payment-mode.invalid=The parameter 'chargePaymentMode' is not one of the supported values +org.apache.fineract.portfolio.charge.charge-payment-mode.range=The parameter 'chargePaymentMode' must be between 0 and 1 +org.apache.fineract.portfolio.charge.fee-on-month-day.not-null=The parameter 'feeOnMonthDay' is mandatory +org.apache.fineract.portfolio.charge.fee-on-month-day.invalid=The parameter 'feeOnMonthDay' is not valid for the given 'monthDayFormat' and 'locale' +org.apache.fineract.portfolio.charge.fee-on-month-day.not-supported=The parameter 'feeOnMonthDay' is not supported for this 'chargeTimeType' +org.apache.fineract.portfolio.charge.fee-interval.not-null=The parameter 'feeInterval' is mandatory +org.apache.fineract.portfolio.charge.fee-interval.positive=The parameter 'feeInterval' must be greater than zero +org.apache.fineract.portfolio.charge.fee-interval.monthly-range=The parameter 'feeInterval' must be between 1 and 12 +org.apache.fineract.portfolio.charge.fee-frequency.range=The parameter 'feeFrequency' must be between 0 and 3 +org.apache.fineract.portfolio.charge.free-withdrawal-frequency.positive=The parameter 'freeWithdrawalFrequency' must be greater than zero +org.apache.fineract.portfolio.charge.restart-count-frequency.positive=The parameter 'restartCountFrequency' must be greater than zero +org.apache.fineract.portfolio.charge.payment-type-id.positive=The parameter 'paymentTypeId' must be greater than zero +org.apache.fineract.portfolio.charge.income-account-id.positive=The parameter 'incomeAccountId' must be greater than zero +org.apache.fineract.portfolio.charge.tax-group-id.positive=The parameter 'taxGroupId' must be greater than zero +org.apache.fineract.portfolio.charge.tax-group-id.modification-not-supported=The parameter 'taxGroupId' cannot be modified once a tax group has been assigned diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanChargesApiResource.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanChargesApiResource.java index 10b620d715c..360dc4c9d1e 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanChargesApiResource.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanChargesApiResource.java @@ -49,7 +49,7 @@ import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.service.ChargeReadService; import org.apache.fineract.portfolio.workingcapitalloan.WorkingCapitalLoanConstants; import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanChargeData; import org.apache.fineract.portfolio.workingcapitalloan.repository.WorkingCapitalLoanChargeRepository; @@ -65,7 +65,7 @@ public class WorkingCapitalLoanChargesApiResource { private final WorkingCapitalLoanRepository workingCapitalLoanRepository; - private final ChargeReadPlatformService chargeReadPlatformService; + private final ChargeReadService chargeReadService; private final PlatformSecurityContext securityContext; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final WorkingCapitalLoanChargeReadPlatformService loanChargeReadPlatformService; @@ -274,7 +274,7 @@ private WorkingCapitalLoanChargeData retrieveTemplate(final Long loanId, final S ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); Long resolvedLoanId = loanId == null ? workingCapitalLoanRepository.findIdByExternalId(loanExternalId) : loanId; - final List chargeOptions = chargeReadPlatformService.retrieveWorkingCapitalLoanAccountApplicableCharges(resolvedLoanId); + final List chargeOptions = chargeReadService.retrieveWorkingCapitalLoanAccountApplicableCharges(resolvedLoanId); return WorkingCapitalLoanChargeData.template(chargeOptions); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccrualsOnLoanClosureTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccrualsOnLoanClosureTest.java index 03a6b6f7de8..3ce0d82b1f9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccrualsOnLoanClosureTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccrualsOnLoanClosureTest.java @@ -24,9 +24,9 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; @@ -48,7 +48,7 @@ public class AccrualsOnLoanClosureTest extends FeignLoanTestBase { private static final Double chargeAmount = 20.0; private static Long loanId; - private static PostChargesResponse penaltyResponse; + private static ChargeCreateResponse penaltyResponse; private static final String penaltyCharge1AddedDate = "24 April 2024"; @Test @@ -60,9 +60,9 @@ public void testAccrualCreatedOnLoanClosureWithSubmittedDate() { Assertions.assertNotNull(loanId); disburseLoan(loanId, BigDecimal.valueOf(disbursementAmount), disbursementDate); - penaltyResponse = chargesHelper.createCharge( - new ChargeRequest().active(true).chargeTimeType(2).chargeAppliesTo(1).chargeCalculationType(1).penalty(true).amount(20.0) - .currencyCode("USD").locale("en").chargePaymentMode(0).name(Utils.randomStringGenerator("PENALTY_", 6))); + penaltyResponse = chargesHelper.createCharge(new ChargeCreateRequest().active(true).chargeTimeType(2).chargeAppliesTo(1) + .chargeCalculationType(1).penalty(true).amount(20.0).currencyCode("USD").locale("en").chargePaymentMode(0) + .name(Utils.randomStringGenerator("PENALTY_", 6))); runAt(startDate, () -> { globalConfigurationHelper.updateGlobalConfiguration(CHARGE_ACCRUAL_DATE, new PutGlobalConfigurationsRequest().stringValue("submitted-date")); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java index fc463ffe7d3..9ac14138408 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java @@ -60,6 +60,7 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.AllowAttributeOverrides; import org.apache.fineract.client.models.BusinessDateUpdateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; @@ -71,7 +72,6 @@ import org.apache.fineract.client.models.LoanApprovedAmountHistoryData; import org.apache.fineract.client.models.LoanPointInTimeData; import org.apache.fineract.client.models.PaymentAllocationOrder; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; @@ -1491,12 +1491,12 @@ protected Long addChargebackForLoan(Long loanId, Long transactionId, Double amou return response.getResourceId(); } - protected PostChargesResponse createCharge(Double amount) { + protected ChargeCreateResponse createCharge(Double amount) { String payload = ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, amount.toString(), false); return ChargesHelper.createLoanCharge(requestSpec, responseSpec, payload); } - protected PostChargesResponse createCharge(Double amount, String currencyCode) { + protected ChargeCreateResponse createCharge(Double amount, String currencyCode) { String payload = ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, amount.toString(), false, currencyCode); return ChargesHelper.createLoanCharge(requestSpec, responseSpec, payload); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ChargesTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ChargesTest.java index a31f340326e..fe36ff39165 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ChargesTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ChargesTest.java @@ -29,9 +29,9 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetChargesResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostTaxesComponentsRequest; import org.apache.fineract.client.models.PostTaxesComponentsResponse; import org.apache.fineract.client.models.PostTaxesGroupRequest; @@ -345,11 +345,11 @@ public void testChargeUsingPercentageCalculationWithMinAndMaxGapValues() { final BigDecimal minCapVal = BigDecimal.valueOf(23); final BigDecimal maxCapVal = BigDecimal.valueOf(45); - final PostChargesResponse feeCharge = chargesHelper.createCharges( - new ChargeRequest().penalty(false).amount(9.0).chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()) - .chargeTimeType(ChargeTimeType.DISBURSEMENT.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) - .currencyCode("USD").name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)) - .chargeAppliesTo(1).locale("en").active(true).minCap(minCapVal).maxCap(maxCapVal)); + final ChargeCreateResponse feeCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(false).amount(9.0) + .chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()) + .chargeTimeType(ChargeTimeType.DISBURSEMENT.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) + .currencyCode("USD").name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)) + .chargeAppliesTo(1).locale("en").active(true).minCap(minCapVal).maxCap(maxCapVal)); Assertions.assertNotNull(feeCharge); final Long chargeId = feeCharge.getResourceId(); @@ -380,11 +380,11 @@ public void testChargeCreationWithTaxGroup() { final PostTaxesGroupResponse taxGroupResponse = TaxGroupHelper.createTaxGroup(taxGroupRequest); Assertions.assertNotNull(taxGroupResponse); - final PostChargesResponse feeCharge = chargesHelper.createCharges( - new ChargeRequest().penalty(false).amount(9.0).chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()) - .chargeTimeType(ChargeTimeType.DISBURSEMENT.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) - .currencyCode("USD").name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)) - .chargeAppliesTo(1).locale("en").active(true).taxGroupId(taxGroupResponse.getResourceId())); + final ChargeCreateResponse feeCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(false).amount(9.0) + .chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue()) + .chargeTimeType(ChargeTimeType.DISBURSEMENT.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) + .currencyCode("USD").name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)) + .chargeAppliesTo(1).locale("en").active(true).taxGroupId(taxGroupResponse.getResourceId())); Assertions.assertNotNull(feeCharge); final Long chargeId = feeCharge.getResourceId(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientChargeRoundingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientChargeRoundingTest.java index 849a46942dd..46f377a5945 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientChargeRoundingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientChargeRoundingTest.java @@ -31,12 +31,12 @@ import java.util.List; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.CurrencyConfigurationData; import org.apache.fineract.client.models.CurrencyUpdateRequest; import org.apache.fineract.client.models.GetClientsChargesPageItems; import org.apache.fineract.client.models.GetClientsClientIdChargesResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.FineractClientHelper; import org.apache.fineract.integrationtests.common.Utils; @@ -60,7 +60,7 @@ public void setup() throws Exception { @Test public void shouldRoundUsdClientChargeTo_TwoDecimalPlaces() throws Exception { - PostChargesResponse chargesResponse = createFlatClientCharge(19.876, "USD"); + ChargeCreateResponse chargesResponse = createFlatClientCharge(19.876, "USD"); Integer appliedChargeId = applyChargeToClient(clientId, chargesResponse.getResourceId(), new BigDecimal("19.876")); @@ -74,7 +74,7 @@ public void shouldRoundUsdClientChargeTo_TwoDecimalPlaces() throws Exception { @Test public void shouldRoundJpyClientChargeTo_ZeroDecimalPlaces() throws Exception { - PostChargesResponse chargesResponse = createFlatClientCharge(19.8, "JPY"); + ChargeCreateResponse chargesResponse = createFlatClientCharge(19.8, "JPY"); Integer appliedChargeId = applyChargeToClient(clientId, chargesResponse.getResourceId(), new BigDecimal("19.8")); @@ -88,7 +88,7 @@ public void shouldRoundJpyClientChargeTo_ZeroDecimalPlaces() throws Exception { @Test public void shouldRoundUpJpyClientCharge_whenValueIsAboveHalfTo_ZeroDecimalPlaces() throws Exception { - PostChargesResponse chargesResponse = createFlatClientCharge(0.55, "JPY"); + ChargeCreateResponse chargesResponse = createFlatClientCharge(0.55, "JPY"); Integer appliedChargeId = applyChargeToClient(clientId, chargesResponse.getResourceId(), new BigDecimal("0.55")); @@ -102,7 +102,7 @@ public void shouldRoundUpJpyClientCharge_whenValueIsAboveHalfTo_ZeroDecimalPlace @Test public void shouldFailToAddJpyClientCharge_whenRoundedToZero() throws Exception { - PostChargesResponse chargesResponse = createFlatClientCharge(0.5, "JPY"); + ChargeCreateResponse chargesResponse = createFlatClientCharge(0.5, "JPY"); Response response = applyChargeToClientRaw(clientId, chargesResponse.getResourceId(), new BigDecimal("0.5")); @@ -116,9 +116,9 @@ public void shouldFailToAddJpyClientCharge_whenRoundedToZero() throws Exception // HELPERS // ----------------------------- - private PostChargesResponse createFlatClientCharge(double amount, String currencyCode) { + private ChargeCreateResponse createFlatClientCharge(double amount, String currencyCode) { String uniqueChargeName = "Client Charge Flat " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(3) // CLIENT + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(3) // CLIENT .chargeTimeType(2).chargeCalculationType(1) // FLAT .amount(amount).currencyCode(currencyCode).locale("en").active(true).penalty(false)); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index c6594da3c5f..fa9d895b7f8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -55,7 +55,8 @@ import org.apache.fineract.accounting.glaccount.domain.GLAccountType; import org.apache.fineract.client.models.AllowAttributeOverrides; import org.apache.fineract.client.models.BusinessDateUpdateRequest; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.GetLoanTransactionRelation; import org.apache.fineract.client.models.GetLoansLoanIdLoanTransactionRelation; @@ -65,7 +66,6 @@ import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.JournalEntryTransactionItem; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostGLAccountsRequest; @@ -5503,13 +5503,13 @@ public void chargeAdjustmentAccountingValidation() { .name(Utils.uniqueRandomStringGenerator("UNIQUE_PENALTY_INCOME" + Calendar.getInstance().getTimeInMillis(), 5)) .usage(1)); - PostChargesResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeRequest().penalty(true).amount(10.0) + ChargeCreateResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeCreateRequest().penalty(true).amount(10.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()) .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) .currencyCode("USD").name(Utils.randomStringGenerator("PENALTY_" + Calendar.getInstance().getTimeInMillis(), 5)) .chargeAppliesTo(1).locale("en").active(true)); - PostChargesResponse feeCharge = CHARGES_HELPER.createCharges(new ChargeRequest().penalty(false).amount(9.0) + ChargeCreateResponse feeCharge = CHARGES_HELPER.createCharges(new ChargeCreateRequest().penalty(false).amount(9.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()) .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) .currencyCode("USD").name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)) @@ -7005,7 +7005,7 @@ public void testLoanTransactionOrderAfterReverseReplay() { PostLoanProductsRequest loanProductsRequest = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct(); final PostLoanProductsResponse loanProductResponse = LOAN_PRODUCT_HELPER.createLoanProduct(loanProductsRequest); LOG.info("-----------------------------------CREATE CHARGES-----------------------------------------"); - PostChargesResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeRequest().penalty(true).amount(10.0) + ChargeCreateResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeCreateRequest().penalty(true).amount(10.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()) .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) .currencyCode("USD").name(Utils.randomStringGenerator("PENALTY_" + Calendar.getInstance().getTimeInMillis(), 5)) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java index 0ba8a37d44d..b078d699bbb 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java @@ -25,7 +25,7 @@ import java.math.BigDecimal; import java.time.LocalDate; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdResponse; @@ -1503,7 +1503,7 @@ public void scenario11() { } private Long createSpecifiedDueDateCharge(double amount, boolean penalty) { - ChargeRequest request = ChargeRequestBuilders.loanSpecifiedDueDateFee(amount); + ChargeCreateRequest request = ChargeRequestBuilders.loanSpecifiedDueDateFee(amount); if (penalty) { request.penalty(true); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java index 15eb5c7257e..8a224b0d951 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java @@ -21,8 +21,8 @@ import java.math.BigDecimal; import java.time.LocalDate; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; @@ -54,7 +54,7 @@ public void beforeEach() { @Test public void loanChargeAfterMaturityTest() { runAt("02 October 2024", () -> { - final PostChargesResponse chargeResponse = createCharge(20.0d, "EUR"); + final ChargeCreateResponse chargeResponse = createCharge(20.0d, "EUR"); addLoanCharge(loanId, chargeResponse.getResourceId(), "02 October 2024", 20.0d); final GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); @@ -73,7 +73,7 @@ public void immediateChargeAccrualPostMaturityTest() { executeInlineCOB(loanId); globalConfigurationHelper.manageConfigurations(GlobalConfigurationConstants.ENABLE_IMMEDIATE_CHARGE_ACCRUAL_POST_MATURITY, true); - final PostChargesResponse chargeResponse = createCharge(20.0d, "EUR"); + final ChargeCreateResponse chargeResponse = createCharge(20.0d, "EUR"); addLoanCharge(loanId, chargeResponse.getResourceId(), "03 October 2024", 20.0d); final GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); Assertions.assertTrue(loanDetails.getTransactions().stream() diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeRoundingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeRoundingTest.java index ad42c56ee26..b0f9da889c7 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeRoundingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeRoundingTest.java @@ -34,10 +34,10 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicReference; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansDisbursementData; @@ -72,7 +72,7 @@ public void shouldApplyRoundingRules_forFlatCharge() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createFlatCharge(19.8); + ChargeCreateResponse chargeResponse = createFlatCharge(19.8); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 19.8); @@ -93,7 +93,7 @@ public void shouldRoundUpFlatCharge_whenValueIsAboveHalf() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createFlatCharge(0.6); + ChargeCreateResponse chargeResponse = createFlatCharge(0.6); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 0.6); @@ -115,7 +115,7 @@ public void shouldFailToAddFlatCharge_whenAmountRoundsToZero() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createFlatCharge(0.5); + ChargeCreateResponse chargeResponse = createFlatCharge(0.5); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.5); @@ -139,7 +139,7 @@ public void shouldApplyRoundingRules_forPercentageOfAmountCharge() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createPercentageOfAmountCharge(2.5067); + ChargeCreateResponse chargeResponse = createPercentageOfAmountCharge(2.5067); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 2.5067); @@ -163,7 +163,7 @@ public void shouldRoundUpPercentageOfAmountCharge_whenValueIsAboveHalf() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createPercentageOfAmountCharge(0.006); + ChargeCreateResponse chargeResponse = createPercentageOfAmountCharge(0.006); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 0.006); @@ -186,7 +186,7 @@ public void shouldFailToAddPercentageOfAmountCharge_whenRoundedToZero() { Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createPercentageOfAmountCharge(0.005); + ChargeCreateResponse chargeResponse = createPercentageOfAmountCharge(0.005); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.005); @@ -210,7 +210,7 @@ public void shouldApplyRoundingRules_forPercentageOfAmountPlusInterestCharge_bef Long loanId = applyAndApproveLoan(productId, 10000.0, 1); - PostChargesResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(2.536); + ChargeCreateResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(2.536); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 2.536); @@ -239,7 +239,7 @@ public void shouldApplyRoundingRules_forPercentageOfAmountPlusInterestCharge_aft BigDecimal totalInterest = executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(2.536); + ChargeCreateResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(2.536); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), LATER_DATE, 2.536); @@ -268,7 +268,7 @@ public void shouldRoundUpPercentageOfAmountPlusInterestCharge_whenValueIsAboveHa BigDecimal totalInterest = executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(0.56); + ChargeCreateResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(0.56); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), LATER_DATE, 0.56); @@ -298,7 +298,7 @@ public void shouldFailToAddPercentageOfAmountPlusInterestCharge_whenRoundedToZer executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(0.38); + ChargeCreateResponse chargeResponse = createPercentageOfAmountPlusInterestCharge(0.38); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.38); @@ -328,7 +328,7 @@ public void shouldApplyRoundingRules_forPercentageOfInterestCharge() { BigDecimal totalInterest = executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfInterestCharge(2.536); + ChargeCreateResponse chargeResponse = createPercentageOfInterestCharge(2.536); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), LATER_DATE, 2.536); @@ -355,7 +355,7 @@ public void shouldRoundUpPercentageOfInterestCharge_whenValueIsAboveHalf() { BigDecimal totalInterest = executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfInterestCharge(2.068); + ChargeCreateResponse chargeResponse = createPercentageOfInterestCharge(2.068); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), LATER_DATE, 2.068); @@ -383,7 +383,7 @@ public void shouldFailToAddPercentageOfInterestCharge_whenRoundedToZero() { executeCobAndGetTotalInterest(loanId); - PostChargesResponse chargeResponse = createPercentageOfInterestCharge(1.68); + ChargeCreateResponse chargeResponse = createPercentageOfInterestCharge(1.68); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 1.68); @@ -411,7 +411,7 @@ public void shouldApplyRoundingRules_forPercentageOfTrancheDisbursementCharge() Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.5); + ChargeCreateResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.5); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 0.5); @@ -443,7 +443,7 @@ public void shouldFailToAddPercentageOfTrancheDisbursementCharge_whenAnyTrancheR Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.09); + ChargeCreateResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.09); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.09); @@ -473,7 +473,7 @@ public void shouldFailToAddAnyCharges_whenAllRoundedChargesBecomeZero_forPercent Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.04); + ChargeCreateResponse chargeResponse = createPercentageOfTrancheDisbursementCharge(0.04); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.04); @@ -504,7 +504,7 @@ public void shouldApplyRoundingRules_forPercentageOfDisbursementCharge() { Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfDisbursementCharge(0.5); + ChargeCreateResponse chargeResponse = createPercentageOfDisbursementCharge(0.5); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 0.5); @@ -534,7 +534,7 @@ public void shouldRoundUpPercentageOfDisbursementCharge_whenValueIsAboveHalf() { Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfDisbursementCharge(0.09); + ChargeCreateResponse chargeResponse = createPercentageOfDisbursementCharge(0.09); assertNotNull(chargeResponse.getResourceId()); addLoanCharge(loanId, chargeResponse.getResourceId(), DATE, 0.09); @@ -565,7 +565,7 @@ public void shouldFailToAddPercentageOfDisbursementCharge_whenRoundedToZero() { Long loanId = applyAndApproveMultiTrancheLoan(productId, disbursements); - PostChargesResponse chargeResponse = createPercentageOfDisbursementCharge(0.04); + ChargeCreateResponse chargeResponse = createPercentageOfDisbursementCharge(0.04); assertNotNull(chargeResponse.getResourceId()); PostLoansLoanIdChargesRequest request = buildLoanChargeRequest(chargeResponse.getResourceId(), DATE, 0.04); @@ -643,44 +643,44 @@ private Long applyAndApproveMultiTrancheLoan(Long productId, List { // Given – charge with NO tax group - PostChargesResponse chargeResponse = createFlatLoanCharge(100.0, null); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(100.0, null); Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); Long loanProductId = loanProductHelper.createLoanProduct(createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct()) @@ -289,7 +289,7 @@ public void testChargeDefinition_hasTaxGroupPopulated() { PostTaxesGroupResponse taxGroup = createTaxGroup(taxComponent.getResourceId()); // When – create charge linked to the tax group - PostChargesResponse chargeResponse = createFlatLoanCharge(50.0, taxGroup.getResourceId()); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(50.0, taxGroup.getResourceId()); // Then – retrieve and verify taxGroup is set ChargesHelper chargesHelper = new ChargesHelper(); @@ -362,7 +362,7 @@ public void testLoanChargeTax_appliedIndependentlyToEachLoan() { // Given – shared charge definition with 10 % tax PostTaxesComponentsResponse taxComponent = createTaxComponent(10.0f); PostTaxesGroupResponse taxGroup = createTaxGroup(taxComponent.getResourceId()); - PostChargesResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); Long chargeDefinitionId = chargeResponse.getResourceId(); // Given – two separate loans @@ -419,7 +419,7 @@ public void testCashAccounting_journalEntries_feeWithTaxSplitsIncomeAndLiability PostTaxesGroupResponse taxGroup = createTaxGroup(taxComponent.getResourceId()); // Given – flat charge of 100 with 10 % tax, due on the loan start date - PostChargesResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); // Given – a cash-based loan (principal = 1000, no interest) Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); @@ -480,7 +480,7 @@ public void testAccrualAccounting_journalEntries_feeWithTaxSplitsIncomeAndLiabil PostTaxesGroupResponse taxGroup = createTaxGroup(taxComponent.getResourceId()); // Given – flat charge of 100 with 10 % tax, due on the loan start date - PostChargesResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); // Given – a periodic-accrual loan (principal = 1000, no interest) Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); @@ -526,7 +526,7 @@ public void testLoanChargeList_containsOriginalAmount() { // Given PostTaxesComponentsResponse taxComponent = createTaxComponent(10.0f); PostTaxesGroupResponse taxGroup = createTaxGroup(taxComponent.getResourceId()); - PostChargesResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); + ChargeCreateResponse chargeResponse = createFlatLoanCharge(100.0, taxGroup.getResourceId()); Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); Long loanProductId = loanProductHelper.createLoanProduct(createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct()) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargesMultipleDebitAccountsTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargesMultipleDebitAccountsTest.java index c10d7fdefd1..05d80ce3c9c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargesMultipleDebitAccountsTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargesMultipleDebitAccountsTest.java @@ -29,9 +29,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.JournalEntryTransactionItem; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; @@ -92,9 +92,9 @@ public void testMultipleChargesCreateChargeSpecificJournalEntries() { assertNotNull(loanProductId); // Create charges with different amounts to test aggregation - PostChargesResponse charge1 = createCharge(100.0); - PostChargesResponse charge2 = createCharge(200.0); - PostChargesResponse charge3 = createCharge(150.0); + ChargeCreateResponse charge1 = createCharge(100.0); + ChargeCreateResponse charge2 = createCharge(200.0); + ChargeCreateResponse charge3 = createCharge(150.0); assertNotNull(charge1); assertNotNull(charge2); assertNotNull(charge3); @@ -157,9 +157,9 @@ public void testChargeAggregationByGLAccount() { Long loanProductId = loanProductResponse.getResourceId(); // Create multiple charges that would map to same GL account type - PostChargesResponse charge1 = createCharge(75.0); - PostChargesResponse charge2 = createCharge(125.0); - PostChargesResponse charge3 = createCharge(50.0); + ChargeCreateResponse charge1 = createCharge(75.0); + ChargeCreateResponse charge2 = createCharge(125.0); + ChargeCreateResponse charge3 = createCharge(50.0); Long clientId = clientHelper.createClient(clientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "15 January 2023", 5000.0, 2); @@ -197,7 +197,7 @@ public void testBackwardCompatibilityWithExistingConfigurations() { PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(loanProduct); Long loanProductId = loanProductResponse.getResourceId(); - PostChargesResponse charge = createCharge(300.0); + ChargeCreateResponse charge = createCharge(300.0); Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "10 January 2023", 8000.0, 3); @@ -228,7 +228,7 @@ public void testAccountingIntegrityValidation() { PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(loanProduct); Long loanProductId = loanProductResponse.getResourceId(); - PostChargesResponse charge = createCharge(500.0); + ChargeCreateResponse charge = createCharge(500.0); Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "20 January 2023", 12000.0, 4); @@ -261,9 +261,9 @@ public void testChargeSpecificGLAccountValidation() { assertNotNull(loanProductId, "Loan product should be created successfully"); // Create three different charges to test individual GL account mapping - PostChargesResponse processingFeeCharge = createCharge(250.0); - PostChargesResponse penaltyCharge = createCharge(175.0); - PostChargesResponse documentationFeeCharge = createCharge(325.0); + ChargeCreateResponse processingFeeCharge = createCharge(250.0); + ChargeCreateResponse penaltyCharge = createCharge(175.0); + ChargeCreateResponse documentationFeeCharge = createCharge(325.0); assertNotNull(processingFeeCharge, "Processing fee charge should be created"); assertNotNull(penaltyCharge, "Penalty charge should be created"); assertNotNull(documentationFeeCharge, "Documentation fee charge should be created"); @@ -326,9 +326,9 @@ public void testProportionalDistributionLogic() { Long loanProductId = loanProductResponse.getResourceId(); // Create charges with specific amounts to test proportional distribution - PostChargesResponse charge1 = createCharge(400.0); // 40% of 1000 - PostChargesResponse charge2 = createCharge(300.0); // 30% of 1000 - PostChargesResponse charge3 = createCharge(300.0); // 30% of 1000 + ChargeCreateResponse charge1 = createCharge(400.0); // 40% of 1000 + ChargeCreateResponse charge2 = createCharge(300.0); // 30% of 1000 + ChargeCreateResponse charge3 = createCharge(300.0); // 30% of 1000 Long clientId = clientHelper.createClient(clientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "10 February 2023", 20000.0, 6); @@ -375,7 +375,7 @@ public void testAccountingImbalanceErrorHandling() { PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(loanProduct); Long loanProductId = loanProductResponse.getResourceId(); - PostChargesResponse charge = createCharge(500.0); + ChargeCreateResponse charge = createCharge(500.0); Long clientId = clientHelper.createClient(clientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "15 February 2023", 10000.0, 3); @@ -413,7 +413,7 @@ public void testMissingGLAccountMappingHandling() { PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(loanProduct); Long loanProductId = loanProductResponse.getResourceId(); - PostChargesResponse charge = createCharge(300.0); + ChargeCreateResponse charge = createCharge(300.0); Long clientId = clientHelper.createClient(clientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "20 February 2023", 8000.0, 2); @@ -451,8 +451,8 @@ public void testZeroAmountChargeHandling() { Long loanProductId = loanProductResponse.getResourceId(); // Create charges - use minimum valid amounts instead of zero - PostChargesResponse regularCharge = createCharge(200.0); - PostChargesResponse smallCharge = createCharge(0.01); // Minimum valid amount instead of zero + ChargeCreateResponse regularCharge = createCharge(200.0); + ChargeCreateResponse smallCharge = createCharge(0.01); // Minimum valid amount instead of zero Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "25 February 2023", 5000.0, 2); @@ -489,9 +489,9 @@ public void testMixedChargeTypesAndTimingScenarios() { Long loanProductId = loanProductResponse.getResourceId(); // Create different types of charges - PostChargesResponse flatFeeCharge = createCharge(150.0); - PostChargesResponse percentageCharge = createCharge(200.0); - PostChargesResponse penaltyCharge = createCharge(100.0); + ChargeCreateResponse flatFeeCharge = createCharge(150.0); + ChargeCreateResponse percentageCharge = createCharge(200.0); + ChargeCreateResponse penaltyCharge = createCharge(100.0); Long clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "05 March 2023", 18000.0, 5); @@ -541,8 +541,8 @@ public void testChargeIdParameterValidationInGLAccountMapping() { assertNotNull(loanProductId, "Loan product should be created successfully"); // Create multiple charges with different IDs to test charge-specific GL account mapping - PostChargesResponse primaryCharge = createCharge(250.0); - PostChargesResponse secondaryCharge = createCharge(350.0); + ChargeCreateResponse primaryCharge = createCharge(250.0); + ChargeCreateResponse secondaryCharge = createCharge(350.0); assertNotNull(primaryCharge, "Primary charge should be created"); assertNotNull(secondaryCharge, "Secondary charge should be created"); @@ -604,7 +604,7 @@ public void testAdvancedAccountingRulesOverrideForChargeSpecificGLAccounts() { assertNotNull(loanProductId, "Loan product should be created successfully"); // Create charge that will test advanced accounting rules override - PostChargesResponse feeCharge = createCharge(400.0); + ChargeCreateResponse feeCharge = createCharge(400.0); assertNotNull(feeCharge, "Fee charge should be created"); // Create additional GL accounts for advanced accounting rules override @@ -681,8 +681,8 @@ public void testChargeRemovalAndCOBAccrualAdjustmentProcessing() { assertNotNull(loanProductId, "Loan product should be created successfully"); // Create charges that will be removed to test accrual adjustment - PostChargesResponse feeCharge = createCharge(300.0); - PostChargesResponse penaltyCharge = createCharge(200.0); + ChargeCreateResponse feeCharge = createCharge(300.0); + ChargeCreateResponse penaltyCharge = createCharge(200.0); assertNotNull(feeCharge, "Fee charge should be created"); assertNotNull(penaltyCharge, "Penalty charge should be created"); @@ -764,9 +764,9 @@ public void testMultipleDebitAccountsForAccrualAdjustmentWithChargeIdResolution( assertNotNull(loanProductId, "Loan product should be created successfully"); // Create multiple charges that could use different debit GL accounts - PostChargesResponse processingFeeCharge = createCharge(500.0); - PostChargesResponse serviceFeeCharge = createCharge(300.0); - PostChargesResponse lateFeeCharge = createCharge(150.0); + ChargeCreateResponse processingFeeCharge = createCharge(500.0); + ChargeCreateResponse serviceFeeCharge = createCharge(300.0); + ChargeCreateResponse lateFeeCharge = createCharge(150.0); assertNotNull(processingFeeCharge, "Processing fee charge should be created"); assertNotNull(serviceFeeCharge, "Service fee charge should be created"); assertNotNull(lateFeeCharge, "Late fee charge should be created"); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRecalculationCOBTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRecalculationCOBTest.java index 1591078bac7..36a14379aec 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRecalculationCOBTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRecalculationCOBTest.java @@ -37,8 +37,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; @@ -689,7 +689,7 @@ public void verifyChargeCreationAfterMaturityDateOnInterestBearingProgressiveLoa inlineLoanCOBHelper.executeInlineCOB(List.of(loanId)); // create charge - PostChargesResponse chargeResult = createCharge(10.0); + ChargeCreateResponse chargeResult = createCharge(10.0); Assertions.assertNotNull(chargeResult); Long chargeId = chargeResult.getResourceId(); Assertions.assertNotNull(chargeId); @@ -735,7 +735,7 @@ public void verifyChargeCreationAfterMaturityDateOnInterestBearingProgressiveLoa Long loanId = loanIdRef.get(); // create charge - PostChargesResponse chargeResult = createCharge(10.0); + ChargeCreateResponse chargeResult = createCharge(10.0); Assertions.assertNotNull(chargeResult); Long chargeId = chargeResult.getResourceId(); Assertions.assertNotNull(chargeId); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java index 1185a73068e..85ff1a7cf86 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java @@ -28,13 +28,13 @@ import java.util.HashMap; import java.util.List; import java.util.UUID; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.DelinquencyBucketResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdSummary; import org.apache.fineract.client.models.GetLoansLoanIdTransactions; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.client.models.PostLoansLoanIdRequest; @@ -530,7 +530,7 @@ public void loanRepaymentScheduleWithChargeAndDownPayment() { final Integer loanId = createApproveAndDisburseLoanAccount(clientId, loanProductId.longValue(), loanExternalIdStr, "1", "0"); final Double feeAmount = 10.00; - final PostChargesResponse postChargesResponse = createCharge(feeAmount); + final ChargeCreateResponse postChargesResponse = createCharge(feeAmount); assertNotNull(postChargesResponse); final Long loanChargeId = postChargesResponse.getResourceId(); PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = addLoanCharge(loanId.longValue(), loanChargeId, @@ -592,7 +592,7 @@ public void loanRepaymentScheduleWithMultiDisbursementProductTwoDisbursementAndT "0"); final Double feeAmount = 10.00; - final PostChargesResponse postChargesResponse = createCharge(feeAmount); + final ChargeCreateResponse postChargesResponse = createCharge(feeAmount); assertNotNull(postChargesResponse); final Long loanChargeId = postChargesResponse.getResourceId(); PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = addLoanCharge(loanId.longValue(), loanChargeId, @@ -693,7 +693,7 @@ public void loanRepaymentScheduleWithChargeAndInterestAndDownPayment() { final Integer loanId = createApproveAndDisburseLoanAccount(clientId, loanProductId.longValue(), loanExternalIdStr, "1", "1"); final Double feeAmount = 10.00; - final PostChargesResponse postChargesResponse = createCharge(feeAmount); + final ChargeCreateResponse postChargesResponse = createCharge(feeAmount); assertNotNull(postChargesResponse); final Long loanChargeId = postChargesResponse.getResourceId(); PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = addLoanCharge(loanId.longValue(), loanChargeId, @@ -757,7 +757,7 @@ public void loanRepaymentScheduleWithMultiDisbursementProductTwoDisbursementAndT "1"); final Double feeAmount = 10.00; - final PostChargesResponse postChargesResponse = createCharge(feeAmount); + final ChargeCreateResponse postChargesResponse = createCharge(feeAmount); assertNotNull(postChargesResponse); final Long loanChargeId = postChargesResponse.getResourceId(); PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = addLoanCharge(loanId.longValue(), loanChargeId, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java index 9e550332b12..46bc7623a38 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java @@ -36,9 +36,9 @@ import java.util.HashMap; import java.util.List; import org.apache.fineract.client.models.BusinessDateUpdateRequest; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; @@ -436,7 +436,7 @@ public void addChargeAfterLoanMaturity() { BUSINESS_DATE_HELPER.updateBusinessDate(new BusinessDateUpdateRequest().type(BusinessDateUpdateRequest.TypeEnum.BUSINESS_DATE) .date("01 September 2023").dateFormat(DATETIME_PATTERN).locale("en")); - PostChargesResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeRequest().penalty(true).amount(10.0) + ChargeCreateResponse penaltyCharge = CHARGES_HELPER.createCharges(new ChargeCreateRequest().penalty(true).amount(10.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()) .chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue()) .currencyCode("USD").name(Utils.randomStringGenerator("PENALTY_" + Calendar.getInstance().getTimeInMillis(), 5)) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java index e14ea9d1856..612c1b657e4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java @@ -35,13 +35,13 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.AllowAttributeOverrides; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoanPaymentChannelToFundSourceMappings; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdStatus; import org.apache.fineract.client.models.LoanProductChargeData; import org.apache.fineract.client.models.LoanProductChargeToGLAccountMapper; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; @@ -1548,7 +1548,7 @@ private PostLoanProductsRequest loanProductsRequestInterestDecliningBalanceDaily private void chargeFee(Long loanId, Double amount, String dueDate) { LOG.info("Charge FEE amount {} dueDate {}", amount, dueDate); - PostChargesResponse feeCharge = chargesHelper.createCharges(new ChargeRequest().penalty(false).amount(9.0) + ChargeCreateResponse feeCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(false).amount(9.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()).chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()) .chargePaymentMode(ChargePaymentMode.REGULAR.getValue()).currencyCode("USD") .name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)).chargeAppliesTo(1).locale("en") @@ -1562,7 +1562,7 @@ private void chargeFee(Long loanId, Double amount, String dueDate) { private void chargePenalty(Long loanId, Double amount, String dueDate) { LOG.info("Charge PENALTY amount {} dueDate {}", amount, dueDate); - PostChargesResponse penaltyCharge = chargesHelper.createCharges(new ChargeRequest().penalty(true).amount(10.0) + ChargeCreateResponse penaltyCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(true).amount(10.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()).chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()) .chargePaymentMode(ChargePaymentMode.REGULAR.getValue()).currencyCode("USD") .name(Utils.randomStringGenerator("PENALTY_" + Calendar.getInstance().getTimeInMillis(), 5)).chargeAppliesTo(1).locale("en") diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java index 0817e69169c..b924a84c302 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java @@ -45,11 +45,11 @@ import org.apache.fineract.batch.domain.BatchResponse; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.BusinessDateUpdateRequest; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; @@ -2036,7 +2036,7 @@ private PostLoanProductsRequest create4IProgressiveWithChargeOffBehaviour() { } private void chargeFee(Long loanId, Double amount, String dueDate) { - PostChargesResponse feeCharge = chargesHelper.createCharges(new ChargeRequest().penalty(false).amount(9.0) + ChargeCreateResponse feeCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(false).amount(9.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()).chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()) .chargePaymentMode(ChargePaymentMode.REGULAR.getValue()).currencyCode("USD") .name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)).chargeAppliesTo(1).locale("en") @@ -2049,7 +2049,7 @@ private void chargeFee(Long loanId, Double amount, String dueDate) { } private void chargePenalty(Long loanId, Double amount, String dueDate) { - PostChargesResponse penaltyCharge = chargesHelper.createCharges(new ChargeRequest().penalty(true).amount(10.0) + ChargeCreateResponse penaltyCharge = chargesHelper.createCharges(new ChargeCreateRequest().penalty(true).amount(10.0) .chargeCalculationType(ChargeCalculationType.FLAT.getValue()).chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()) .chargePaymentMode(ChargePaymentMode.REGULAR.getValue()).currencyCode("USD") .name(Utils.randomStringGenerator("PENALTY_" + Calendar.getInstance().getTimeInMillis(), 5)).chargeAppliesTo(1).locale("en") diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWaiveChargeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWaiveChargeTest.java index 577ab684251..5698466e501 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWaiveChargeTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWaiveChargeTest.java @@ -30,9 +30,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargePaidByData; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.client.models.PostLoansRequest; @@ -99,7 +99,7 @@ public void test_LoanPaidByDateIsCorrect_WhenNPlusOneInstallmentCharge_IsWaived( // create charge double chargeAmount = 100.0; - PostChargesResponse chargeResult = createCharge(chargeAmount); + ChargeCreateResponse chargeResult = createCharge(chargeAmount); Long chargeId = chargeResult.getResourceId(); // add charge after maturity @@ -189,7 +189,7 @@ public void accrualIsCalculatedWhenThereIsWaivedChargeAndLoanIsClosed(boolean ad // create charge double chargeAmount = 10.0; - PostChargesResponse chargeResult = createCharge(chargeAmount); + ChargeCreateResponse chargeResult = createCharge(chargeAmount); Long chargeId = chargeResult.getResourceId(); PostLoansLoanIdChargesResponse loanChargeResult = addLoanCharge(loanId, chargeId, "09 January 2023", chargeAmount); @@ -210,7 +210,7 @@ public void accrualIsCalculatedWhenThereIsWaivedChargeAndLoanIsClosed(boolean ad // create charge double chargeAmount = 9.0; - PostChargesResponse chargeResult = createCharge(chargeAmount); + ChargeCreateResponse chargeResult = createCharge(chargeAmount); Long chargeId = chargeResult.getResourceId(); PostLoansLoanIdChargesResponse loanChargeResult = addLoanCharge(loanId, chargeId, "10 January 2023", chargeAmount); @@ -237,7 +237,7 @@ public void accrualIsCalculatedWhenThereIsWaivedChargeAndLoanIsClosed(boolean ad // create charge double chargeAmount = 8.0; - PostChargesResponse chargeResult = createCharge(chargeAmount); + ChargeCreateResponse chargeResult = createCharge(chargeAmount); Long chargeId = chargeResult.getResourceId(); PostLoansLoanIdChargesResponse loanChargeResult = addLoanCharge(loanId, chargeId, "11 January 2023", chargeAmount); @@ -285,7 +285,7 @@ public void testLoanCannotBeChargedOffWhenUndoingFeeWaiver() { runAt("23 January 2023", () -> { // create charge double chargeAmount = 5.0; - PostChargesResponse chargeResult = createCharge(chargeAmount, "EUR"); + ChargeCreateResponse chargeResult = createCharge(chargeAmount, "EUR"); Long chargeId = chargeResult.getResourceId(); PostLoansLoanIdChargesResponse loanChargeResult = addLoanCharge(appliedLoanId.get(), chargeId, "23 January 2023", chargeAmount); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanUndoDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanUndoDisbursementTest.java index 412323f8a7b..9c147e85b67 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanUndoDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanUndoDisbursementTest.java @@ -22,8 +22,8 @@ import java.util.Calendar; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import org.apache.fineract.client.models.ChargeRequest; -import org.apache.fineract.client.models.PostChargesResponse; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.PostLoansRequestChargeData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.Utils; @@ -40,7 +40,7 @@ public void testProgressiveLoanUndoDisbursementWithChargeAtDisbursement() { Long loanProductId = createLoanProduct(create4IProgressive()); - final PostChargesResponse disbCharge = chargesHelper.createCharge(new ChargeRequest().active(true).chargeAppliesTo(1) + final ChargeCreateResponse disbCharge = chargesHelper.createCharge(new ChargeCreateRequest().active(true).chargeAppliesTo(1) .chargeCalculationType(1).chargePaymentMode(0).chargeTimeType(1).currencyCode("EUR").amount(10.0d) .name(Utils.randomStringGenerator("FEE_" + Calendar.getInstance().getTimeInMillis(), 5)).locale("en")); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java index 2a42af23f04..ac760f22b74 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java @@ -30,10 +30,10 @@ import java.util.List; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesResponse; import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostSavingsAccountTransactionsRequest; import org.apache.fineract.client.models.PostSavingsAccountTransactionsResponse; import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesRequest; @@ -68,7 +68,7 @@ public void shouldApplyRoundingRules_forFlatCharge() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createFlatCharge(19.8); + ChargeCreateResponse charge = createFlatCharge(19.8); assertNotNull(charge.getResourceId()); Long savingsChargeId = addFlatCharge(savingsId, charge.getResourceId(), 19.8, DATE); @@ -88,7 +88,7 @@ public void shouldRoundUpFlatCharge_whenValueIsAboveHalf() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createFlatCharge(0.6); + ChargeCreateResponse charge = createFlatCharge(0.6); assertNotNull(charge.getResourceId()); Long savingsChargeId = addFlatCharge(savingsId, charge.getResourceId(), 0.6, DATE); @@ -109,7 +109,7 @@ public void shouldFailToAddFlatCharge_whenAmountRoundsToZero() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createFlatCharge(0.4); + ChargeCreateResponse charge = createFlatCharge(0.4); assertNotNull(charge.getResourceId()); CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, @@ -128,7 +128,7 @@ public void shouldApplyRoundingRules_forPercentageOfWithdrawalCharge() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); + ChargeCreateResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); @@ -160,7 +160,7 @@ public void shouldRoundUpPercentageOfWithdrawalCharge_whenValueIsAboveHalf() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); + ChargeCreateResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); @@ -193,7 +193,7 @@ public void shouldIgnorePercentageOfWithdrawalCharge_whenRoundedToZero() { Long productId = createSavingsProduct(0, 1); Long savingsId = createAndActivateSavingsAccount(productId, DATE); - PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); + ChargeCreateResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); @@ -232,17 +232,17 @@ private Long createAndActivateSavingsAccount(Long productId, String date) { return savingsId; } - private PostChargesResponse createFlatCharge(double amount) { + private ChargeCreateResponse createFlatCharge(double amount) { String uniqueChargeName = "Savings Account Flat Charge " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS .chargeTimeType(2) // SPECIFIED DUE DATE .chargeCalculationType(1) // FLAT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); } - private PostChargesResponse createPercentageWithdrawalCharge(double percentage) { + private ChargeCreateResponse createPercentageWithdrawalCharge(double percentage) { String uniqueChargeName = "Savings Account Withdrawal Charge " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS .chargeTimeType(5) // WITHDRAWAL .chargeCalculationType(2) // % OF AMOUNT .amount(percentage).currencyCode("USD").locale("en").chargePaymentMode(0).active(true).penalty(false)); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ShareAccountChargeRoundingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ShareAccountChargeRoundingTest.java index 002b2254d6b..8576dccf6a6 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ShareAccountChargeRoundingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ShareAccountChargeRoundingTest.java @@ -38,14 +38,14 @@ import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.models.AccountChargesRequest; import org.apache.fineract.client.models.AccountRequest; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetAccountsCharges; import org.apache.fineract.client.models.GetAccountsPurchasedShares; import org.apache.fineract.client.models.GetAccountsTypeAccountIdResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.JournalEntryTransactionItem; import org.apache.fineract.client.models.PostAccountsTypeAccountIdRequest; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostProductsTypeRequest; import org.apache.fineract.client.models.PostSavingsProductsRequest; import org.apache.fineract.client.util.CallFailedRuntimeException; @@ -84,7 +84,7 @@ public void shouldApplyRoundingRules_forFlatActivationCharge() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createActivationFeeFlatCharge(19.8); + ChargeCreateResponse chargeResponse = createActivationFeeFlatCharge(19.8); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 19.8, DATE); @@ -105,7 +105,7 @@ public void shouldRoundUpFlatActivationCharge_whenValueIsAboveHalf() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createActivationFeeFlatCharge(0.55); + ChargeCreateResponse chargeResponse = createActivationFeeFlatCharge(0.55); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 0.55, DATE); @@ -127,7 +127,7 @@ public void shouldFailToAddFlatActivationCharge_whenRoundedToZero() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createActivationFeeFlatCharge(0.5); + ChargeCreateResponse chargeResponse = createActivationFeeFlatCharge(0.5); Long shareProductId = createShareProduct(0, 1); CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, @@ -144,7 +144,7 @@ void verifyActivationChargeRoundedCorrectlyWithAccountingEnabled() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createActivationFeeFlatCharge(19.8); + ChargeCreateResponse chargeResponse = createActivationFeeFlatCharge(19.8); Long shareProductId = createShareProductWithAccountingRule2(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 19.8, DATE); @@ -185,7 +185,7 @@ public void shouldApplyRoundingRules_forFlatPurchaseCharge() { Long savingsProductId = createSavingsProduct(0, 3); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeeFlatCharge(19.8); + ChargeCreateResponse chargeResponse = createPurchaseFeeFlatCharge(19.8); Long shareProductId = createShareProduct(0, 3); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 19.8, DATE); @@ -204,7 +204,7 @@ public void shouldRoundUpFlatPurchaseCharge_whenValueIsAboveHalf() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeeFlatCharge(0.51); + ChargeCreateResponse chargeResponse = createPurchaseFeeFlatCharge(0.51); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 0.51, DATE); @@ -224,7 +224,7 @@ public void shouldFailToAddFlatPurchaseCharge_whenRoundedToZero() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeeFlatCharge(0.5); + ChargeCreateResponse chargeResponse = createPurchaseFeeFlatCharge(0.5); Long shareProductId = createShareProduct(0, 1); CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, @@ -242,7 +242,7 @@ public void shouldApplyRoundingRules_forPercentagePurchaseCharge() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeePercentCharge(2.5); + ChargeCreateResponse chargeResponse = createPurchaseFeePercentCharge(2.5); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 2.5, DATE); @@ -261,7 +261,7 @@ public void shouldRoundUpPercentagePurchaseCharge_whenValueIsAboveHalf() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeePercentCharge(0.51); + ChargeCreateResponse chargeResponse = createPurchaseFeePercentCharge(0.51); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 0.51, DATE); @@ -281,7 +281,7 @@ public void shouldFailToAddPercentagePurchaseCharge_whenRoundedToZero() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createPurchaseFeePercentCharge(0.5); + ChargeCreateResponse chargeResponse = createPurchaseFeePercentCharge(0.5); Long shareProductId = createShareProduct(0, 1); CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, @@ -299,7 +299,7 @@ public void shouldApplyRoundingRules_forFlatRedeemCharge() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeeFlatCharge(10.7); + ChargeCreateResponse chargeResponse = createRedeemFeeFlatCharge(10.7); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 10.7, DATE); @@ -321,7 +321,7 @@ public void shouldRoundUpFlatRedeemCharge_whenValueIsAboveHalf() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeeFlatCharge(0.6); + ChargeCreateResponse chargeResponse = createRedeemFeeFlatCharge(0.6); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 0.6, DATE); @@ -344,7 +344,7 @@ public void shouldIgnoreFlatRedeemCharge_whenRoundedToZero() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeeFlatCharge(0.5); + ChargeCreateResponse chargeResponse = createRedeemFeeFlatCharge(0.5); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 0.5, DATE); @@ -368,7 +368,7 @@ public void shouldApplyRoundingRules_forPercentageRedeemCharge() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeePercentCharge(5.5); + ChargeCreateResponse chargeResponse = createRedeemFeePercentCharge(5.5); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 5.5, DATE); @@ -390,7 +390,7 @@ public void shouldRoundUpPercentageRedeemCharge_whenValueIsAboveHalf() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeePercentCharge(1.5); + ChargeCreateResponse chargeResponse = createRedeemFeePercentCharge(1.5); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 1.5, DATE); @@ -413,7 +413,7 @@ public void shouldIgnorePercentageRedeemCharge_whenRoundedToZero() { Long savingsProductId = createSavingsProduct(0, 1); Long savingsAccountId = createAndActivateSavingsAccount(savingsProductId, DATE); - PostChargesResponse chargeResponse = createRedeemFeePercentCharge(1); + ChargeCreateResponse chargeResponse = createRedeemFeePercentCharge(1); Long shareProductId = createShareProduct(0, 1); Long shareAccountId = applyShareAccount(clientId, shareProductId, savingsAccountId, chargeResponse.getResourceId(), 1, DATE); @@ -449,41 +449,41 @@ private Long createAndActivateSavingsAccount(Long productId, String date) { return savingsId; } - private PostChargesResponse createActivationFeeFlatCharge(double amount) { + private ChargeCreateResponse createActivationFeeFlatCharge(double amount) { String uniqueChargeName = "Share Account Activation Fee Flat " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE .chargeTimeType(13) // ACTIVATION .chargeCalculationType(1) // FLAT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); } - private PostChargesResponse createPurchaseFeeFlatCharge(double amount) { + private ChargeCreateResponse createPurchaseFeeFlatCharge(double amount) { String uniqueChargeName = "Share Account Purchase Fee Flat " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE .chargeTimeType(14) // PURCHASE .chargeCalculationType(1) // FLAT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); } - private PostChargesResponse createPurchaseFeePercentCharge(double amount) { + private ChargeCreateResponse createPurchaseFeePercentCharge(double amount) { String uniqueChargeName = "Share Account Purchase Fee Percent " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE .chargeTimeType(14) // PURCHASE .chargeCalculationType(2) // PERCENT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); } - private PostChargesResponse createRedeemFeeFlatCharge(double amount) { + private ChargeCreateResponse createRedeemFeeFlatCharge(double amount) { String uniqueChargeName = "Share Account Redeem Fee Flat " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE .chargeTimeType(15) // REDEEM .chargeCalculationType(1) // FLAT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); } - private PostChargesResponse createRedeemFeePercentCharge(double amount) { + private ChargeCreateResponse createRedeemFeePercentCharge(double amount) { String uniqueChargeName = "Share Account Redeem Fee Percent " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE + return chargesHelper.createCharges(new ChargeCreateRequest().name(uniqueChargeName).chargeAppliesTo(4) // SHARE .chargeTimeType(15) // REDEEM .chargeCalculationType(2) // PERCENT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java index 36c0e18d652..f544af93c80 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java @@ -43,7 +43,8 @@ import org.apache.fineract.client.feign.ObjectMapperFactory; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.AdvancedPaymentData; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.DeleteLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.DeleteLoansLoanIdResponse; import org.apache.fineract.client.models.DisbursementDetail; @@ -60,7 +61,6 @@ import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.LoanApprovedAmountHistoryData; import org.apache.fineract.client.models.LoanScheduleData; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest; @@ -286,11 +286,11 @@ protected PostLoansLoanIdChargesResponse addLoanCharge(Long loanId, PostLoansLoa return loanHelper.addLoanCharge(loanId, request); } - protected PostChargesResponse createCharge(Double amount) { + protected ChargeCreateResponse createCharge(Double amount) { return chargesHelper.createCharge(ChargeRequestBuilders.loanSpecifiedDueDateFee(amount)); } - protected PostChargesResponse createCharge(Double amount, String currencyCode) { + protected ChargeCreateResponse createCharge(Double amount, String currencyCode) { return chargesHelper.createCharge(ChargeRequestBuilders.loanSpecifiedDueDateFee(amount, currencyCode)); } @@ -1329,7 +1329,7 @@ protected PostLoansLoanIdTransactionsResponse closeLoan(String loanExternalId, P } protected Long addCharge(Long loanId, boolean isPenalty, double amount, String dueDate) { - ChargeRequest chargeRequest = ChargeRequestBuilders.loanSpecifiedDueDateFee(amount); + ChargeCreateRequest chargeRequest = ChargeRequestBuilders.loanSpecifiedDueDateFee(amount); if (isPenalty) { chargeRequest.penalty(true); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignChargesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignChargesHelper.java index 925746b9cdf..f49f3d14e54 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignChargesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignChargesHelper.java @@ -23,12 +23,13 @@ import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; -import org.apache.fineract.client.models.ChargeRequest; -import org.apache.fineract.client.models.DeleteChargesChargeIdResponse; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; +import org.apache.fineract.client.models.ChargeDeleteResponse; +import org.apache.fineract.client.models.ChargeUpdateRequest; import org.apache.fineract.client.models.DeleteClientsClientIdChargesChargeIdResponse; import org.apache.fineract.client.models.GetChargesResponse; import org.apache.fineract.client.models.GetClientsClientIdChargesResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostClientsClientIdChargesChargeIdRequest; import org.apache.fineract.client.models.PostClientsClientIdChargesChargeIdResponse; import org.apache.fineract.client.models.PostClientsClientIdChargesRequest; @@ -46,47 +47,47 @@ public FeignChargesHelper(FineractFeignClient fineractClient) { this.fineractClient = fineractClient; } - public PostChargesResponse createCharge(ChargeRequest request) { + public ChargeCreateResponse createCharge(ChargeCreateRequest request) { return ok(() -> fineractClient.charges().createCharge(request)); } public GetChargesResponse getCharge(Long chargeId) { - return ok(() -> fineractClient.charges().retrieveOneCharge(chargeId)); + return ok(() -> fineractClient.charges().retrieveOneCharge(chargeId, (Boolean) null)); } - public PutChargesChargeIdResponse updateCharge(Long chargeId, ChargeRequest request) { + public PutChargesChargeIdResponse updateCharge(Long chargeId, ChargeUpdateRequest request) { return ok(() -> fineractClient.charges().updateCharge(chargeId, request)); } - public DeleteChargesChargeIdResponse deleteCharge(Long chargeId) { + public ChargeDeleteResponse deleteCharge(Long chargeId) { return ok(() -> fineractClient.charges().deleteCharge(chargeId)); } public CallFailedRuntimeException getChargeExpectingError(Long chargeId) { - return fail(() -> fineractClient.charges().retrieveOneCharge(chargeId)); + return fail(() -> fineractClient.charges().retrieveOneCharge(chargeId, (Boolean) null)); } - public PostChargesResponse createLoanSpecifiedDueDateCharge(double amount) { + public ChargeCreateResponse createLoanSpecifiedDueDateCharge(double amount) { return createCharge(ChargeRequestBuilders.loanSpecifiedDueDateFee(amount)); } - public PostChargesResponse createLoanSpecifiedDueDateCharge(double amount, String currencyCode) { + public ChargeCreateResponse createLoanSpecifiedDueDateCharge(double amount, String currencyCode) { return createCharge(ChargeRequestBuilders.loanSpecifiedDueDateFee(amount, currencyCode)); } - public PostChargesResponse createLoanDisbursementCharge(double amount) { + public ChargeCreateResponse createLoanDisbursementCharge(double amount) { return createCharge(ChargeRequestBuilders.loanDisbursementFee(amount)); } - public PostChargesResponse createLoanSpecifiedDueDatePenalty(double amount) { + public ChargeCreateResponse createLoanSpecifiedDueDatePenalty(double amount) { return createCharge(ChargeRequestBuilders.loanSpecifiedDueDatePenalty(amount)); } - public PostChargesResponse createLoanSpecifiedDueDatePercentageAmountAndInterestFee(double amount) { + public ChargeCreateResponse createLoanSpecifiedDueDatePercentageAmountAndInterestFee(double amount) { return createCharge(ChargeRequestBuilders.loanSpecifiedDueDatePercentageAmountAndInterestFee(amount)); } - public PostChargesResponse createClientSpecifiedDueDateCharge(double amount) { + public ChargeCreateResponse createClientSpecifiedDueDateCharge(double amount) { return createCharge(ChargeRequestBuilders.clientSpecifiedDueDateFee(amount)); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignWorkingCapitalLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignWorkingCapitalLoanHelper.java index 6289f24bf3f..a523ff02ca0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignWorkingCapitalLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignWorkingCapitalLoanHelper.java @@ -28,7 +28,8 @@ import java.util.Objects; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.CommandProcessingResult; import org.apache.fineract.client.models.ExecuteWorkingCapitalLoanTransactionCommandRequest; import org.apache.fineract.client.models.ExecuteWorkingCapitalLoanTransactionCommandResponse; @@ -36,7 +37,6 @@ import org.apache.fineract.client.models.GetWorkingCapitalLoanTransactionsResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoansLoanIdResponse; import org.apache.fineract.client.models.InlineJobRequest; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.client.models.PostWorkingCapitalLoanTransactionsRequest; @@ -150,8 +150,8 @@ public void executeInlineWCCOB(Long loanId) { ok(() -> fineractClient.inlineJob().executeInlineJob("WC_LOAN_COB", new InlineJobRequest().addLoanIdsItem(loanId))); } - public Long createGlobalCharge(ChargeRequest request) { - PostChargesResponse response = ok(() -> fineractClient.charges().createCharge(request)); + public Long createGlobalCharge(ChargeCreateRequest request) { + ChargeCreateResponse response = ok(() -> fineractClient.charges().createCharge(request)); return response.getResourceId(); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/ChargeRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/ChargeRequestBuilders.java index caf50b1cad0..585da8704e0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/ChargeRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/ChargeRequestBuilders.java @@ -18,7 +18,7 @@ */ package org.apache.fineract.integrationtests.client.feign.modules; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; import org.apache.fineract.integrationtests.common.Utils; public final class ChargeRequestBuilders { @@ -43,67 +43,67 @@ public final class ChargeRequestBuilders { private ChargeRequestBuilders() {} - public static ChargeRequest loanDisbursementFee(double amount) { + public static ChargeCreateRequest loanDisbursementFee(double amount) { return loanDisbursementFee(amount, DEFAULT_CURRENCY); } - public static ChargeRequest loanDisbursementFee(double amount, String currencyCode) { + public static ChargeCreateRequest loanDisbursementFee(double amount, String currencyCode) { return baseLoanCharge(amount, currencyCode)// .chargeTimeType(CHARGE_TIME_TYPE_DISBURSEMENT); } - public static ChargeRequest loanDisbursementPercentageFee(double percentage) { + public static ChargeCreateRequest loanDisbursementPercentageFee(double percentage) { return loanDisbursementPercentageFee(percentage, DEFAULT_CURRENCY); } - public static ChargeRequest loanDisbursementPercentageFee(double percentage, String currencyCode) { + public static ChargeCreateRequest loanDisbursementPercentageFee(double percentage, String currencyCode) { return baseLoanCharge(percentage, currencyCode)// .chargeTimeType(CHARGE_TIME_TYPE_DISBURSEMENT)// .chargeCalculationType(CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT); } - public static ChargeRequest loanSpecifiedDueDateFee(double amount) { + public static ChargeCreateRequest loanSpecifiedDueDateFee(double amount) { return loanSpecifiedDueDateFee(amount, DEFAULT_CURRENCY); } - public static ChargeRequest loanSpecifiedDueDateFee(double amount, String currencyCode) { + public static ChargeCreateRequest loanSpecifiedDueDateFee(double amount, String currencyCode) { return baseLoanCharge(amount, currencyCode)// .chargeTimeType(CHARGE_TIME_TYPE_SPECIFIED_DUE_DATE); } - public static ChargeRequest loanSpecifiedDueDatePenalty(double amount) { + public static ChargeCreateRequest loanSpecifiedDueDatePenalty(double amount) { return loanSpecifiedDueDatePenalty(amount, DEFAULT_CURRENCY); } - public static ChargeRequest loanSpecifiedDueDatePenalty(double amount, String currencyCode) { + public static ChargeCreateRequest loanSpecifiedDueDatePenalty(double amount, String currencyCode) { return baseLoanCharge(amount, currencyCode)// .chargeTimeType(CHARGE_TIME_TYPE_SPECIFIED_DUE_DATE)// .penalty(true); } - public static ChargeRequest loanSpecifiedDueDatePercentageAmountAndInterestFee(double amount) { + public static ChargeCreateRequest loanSpecifiedDueDatePercentageAmountAndInterestFee(double amount) { return baseLoanCharge(amount, DEFAULT_CURRENCY)// .chargeTimeType(CHARGE_TIME_TYPE_SPECIFIED_DUE_DATE)// .chargeCalculationType(CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT_AND_INTEREST); } - public static ChargeRequest loanSpecifiedDueDateAccountTransferFee(double amount, boolean penalty) { + public static ChargeCreateRequest loanSpecifiedDueDateAccountTransferFee(double amount, boolean penalty) { return loanSpecifiedDueDateFee(amount).chargePaymentMode(CHARGE_PAYMENT_MODE_ACCOUNT_TRANSFER).penalty(penalty); } - public static ChargeRequest loanInstallmentFee(double amount) { + public static ChargeCreateRequest loanInstallmentFee(double amount) { return baseLoanCharge(amount, DEFAULT_CURRENCY)// .chargeTimeType(CHARGE_TIME_TYPE_INSTALLMENT_FEE); } - public static ChargeRequest loanOverdueFee(double amount) { + public static ChargeCreateRequest loanOverdueFee(double amount) { return baseLoanCharge(amount, DEFAULT_CURRENCY)// .chargeTimeType(CHARGE_TIME_TYPE_OVERDUE_INSTALLMENT_FEE)// .penalty(true); } - public static ChargeRequest clientSpecifiedDueDateFee(double amount) { - return new ChargeRequest()// + public static ChargeCreateRequest clientSpecifiedDueDateFee(double amount) { + return new ChargeCreateRequest()// .name(Utils.uniqueRandomStringGenerator("Charge_Client_", 6))// .chargeAppliesTo(CHARGE_APPLIES_TO_CLIENT)// .chargeTimeType(CHARGE_TIME_TYPE_SPECIFIED_DUE_DATE)// @@ -115,8 +115,8 @@ public static ChargeRequest clientSpecifiedDueDateFee(double amount) { .locale(DEFAULT_LOCALE); } - private static ChargeRequest baseLoanCharge(double amount, String currencyCode) { - return new ChargeRequest()// + private static ChargeCreateRequest baseLoanCharge(double amount, String currencyCode) { + return new ChargeCreateRequest()// .name(Utils.uniqueRandomStringGenerator("Charge_Loan_", 6))// .chargeAppliesTo(CHARGE_APPLIES_TO_LOAN)// .chargeCalculationType(CHARGE_CALCULATION_TYPE_FLAT)// diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/WorkingCapitalLoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/WorkingCapitalLoanRequestBuilders.java index 7e097681b83..f7cb4290858 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/WorkingCapitalLoanRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/WorkingCapitalLoanRequestBuilders.java @@ -19,7 +19,7 @@ package org.apache.fineract.integrationtests.client.feign.modules; import java.math.BigDecimal; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; import org.apache.fineract.client.models.ExecuteWorkingCapitalLoanTransactionCommandRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostWorkingCapitalLoanTransactionsRequest; @@ -107,8 +107,8 @@ public static ExecuteWorkingCapitalLoanTransactionCommandRequest undoTransaction return new ExecuteWorkingCapitalLoanTransactionCommandRequest(); } - public static ChargeRequest specifiedDueDateCharge(boolean penalty, double amount) { - return new ChargeRequest().chargeAppliesTo(CHARGE_APPLIES_TO_WORKING_CAPITAL_LOAN) + public static ChargeCreateRequest specifiedDueDateCharge(boolean penalty, double amount) { + return new ChargeCreateRequest().chargeAppliesTo(CHARGE_APPLIES_TO_WORKING_CAPITAL_LOAN) .chargeTimeType(CHARGE_TIME_TYPE_SPECIFIED_DUE_DATE).chargeCalculationType(CHARGE_CALCULATION_TYPE_FLAT) .name(Utils.uniqueRandomStringGenerator("WCL_CHARGE_", 8)).amount(amount).active(true).currencyCode(CHARGE_CURRENCY_CODE) .locale(LOCALE).penalty(penalty); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java index c67d89a06c3..f955979ed48 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java @@ -23,9 +23,9 @@ import io.restassured.specification.ResponseSpecification; import java.util.ArrayList; import java.util.HashMap; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetChargesResponse; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.util.Calls; import org.apache.fineract.client.util.JSON; import org.apache.fineract.integrationtests.common.CommonConstants; @@ -606,10 +606,10 @@ public static Integer createCharges(final RequestSpecification requestSpec, fina // Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long, // org.apache.fineract.client.models.PostLoansLoanIdRequest) @Deprecated(forRemoval = true) - public static PostChargesResponse createLoanCharge(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + public static ChargeCreateResponse createLoanCharge(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String payload) { final String response = Utils.performServerPost(requestSpec, responseSpec, CREATE_CHARGES_URL, payload, null); - return GSON.fromJson(response, PostChargesResponse.class); + return GSON.fromJson(response, ChargeCreateResponse.class); } // TODO: Rewrite to use fineract-client instead! @@ -804,11 +804,11 @@ public static String applyCharge(RequestSpecification requestSpec, ResponseSpeci } - public PostChargesResponse createCharges(ChargeRequest request) { + public ChargeCreateResponse createCharges(ChargeCreateRequest request) { return Calls.ok(FineractClientHelper.getFineractClient().charges.createCharge(request)); } public GetChargesResponse retrieveCharge(final Long chargeId) { - return Calls.ok(FineractClientHelper.getFineractClient().charges.retrieveOneCharge(chargeId)); + return Calls.ok(FineractClientHelper.getFineractClient().charges.retrieveOneCharge(chargeId, null)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java index 04b8eeb57da..0bf7efd19b1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java @@ -31,11 +31,11 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTemplateResponse; import org.apache.fineract.client.models.LoanScheduleData; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; @@ -116,7 +116,7 @@ public void test_LoanReAgeTransaction_Works() { // create charge double chargeAmount = 10.0; - PostChargesResponse chargeResult = createCharge(chargeAmount); + ChargeCreateResponse chargeResult = createCharge(chargeAmount); Long chargeId = chargeResult.getResourceId(); // add charge after maturity diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/savings/AccountTransferWithdrawalFeeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/savings/AccountTransferWithdrawalFeeTest.java index 821bae63082..9f3de2db7be 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/savings/AccountTransferWithdrawalFeeTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/savings/AccountTransferWithdrawalFeeTest.java @@ -22,9 +22,9 @@ import java.math.BigDecimal; import org.apache.fineract.client.models.AccountTransferRequest; -import org.apache.fineract.client.models.ChargeRequest; +import org.apache.fineract.client.models.ChargeCreateRequest; +import org.apache.fineract.client.models.ChargeCreateResponse; import org.apache.fineract.client.models.PaymentTypeCreateRequest; -import org.apache.fineract.client.models.PostChargesResponse; import org.apache.fineract.client.models.PostSavingsAccountsResponse; import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesRequest; import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesResponse; @@ -48,8 +48,8 @@ public class AccountTransferWithdrawalFeeTest extends BaseSavingsIntegrationTest public void testFromSavingsToSavingsAccountTransferWithWithdrawalFee() { // Create withdrawal fee charge (standard withdrawal fee without payment type binding) final ChargesHelper chargesHelper = new ChargesHelper(); - final PostChargesResponse withdrawalCharge = chargesHelper - .createCharges(new ChargeRequest().active(true).name(Utils.uniqueRandomStringGenerator("Charge_Savings_", 6)) + final ChargeCreateResponse withdrawalCharge = chargesHelper + .createCharges(new ChargeCreateRequest().active(true).name(Utils.uniqueRandomStringGenerator("Charge_Savings_", 6)) .currencyCode("USD").amount(100.0d).chargeAppliesTo(2).chargeTimeType(5).chargeCalculationType(1).locale("en")); Assertions.assertNotNull(withdrawalCharge.getResourceId()); @@ -117,7 +117,7 @@ public void testFromSavingsToSavingsAccountTransferWithPaymentTypeWithdrawalFee( // Create withdrawal fee charge WITH payment type binding final ChargesHelper chargesHelper = new ChargesHelper(); - final PostChargesResponse withdrawalCharge = chargesHelper.createCharges(new ChargeRequest().active(true) + final ChargeCreateResponse withdrawalCharge = chargesHelper.createCharges(new ChargeCreateRequest().active(true) .name(Utils.uniqueRandomStringGenerator("Charge_Savings_", 6)).currencyCode("USD").amount(100.0d).chargeAppliesTo(2) .chargeTimeType(5).chargeCalculationType(1).locale("en").enablePaymentType(true).paymentTypeId(paymentTypeId)); Assertions.assertNotNull(withdrawalCharge.getResourceId());