vidakovic commented on code in PR #6034:
URL: https://github.com/apache/fineract/pull/6034#discussion_r3471835388
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java:
##########
@@ -39,110 +39,129 @@
import jakarta.ws.rs.core.UriInfo;
import java.time.LocalDate;
import java.util.Arrays;
-import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import lombok.RequiredArgsConstructor;
-import org.apache.fineract.batch.command.CommandHandlerRegistry;
-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.api.ApiParameterHelper;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import
org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
-import
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.CommandParameterUtil;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
-import
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.service.SqlValidator;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionCreateCommand;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionDeleteCommand;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionUpdateCommand;
import org.apache.fineract.portfolio.account.data.AccountTransferData;
import org.apache.fineract.portfolio.account.data.StandingInstructionDTO;
import org.apache.fineract.portfolio.account.data.StandingInstructionData;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionCreationRequest;
+import
org.apache.fineract.portfolio.account.data.request.StandingInstructionDeleteRequest;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionSearchParam;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionUpdatesRequest;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionCreateResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionDeleteResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionUpdateResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionWriteResponse;
import
org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
-import
org.apache.fineract.portfolio.account.service.StandingInstructionReadPlatformService;
+import
org.apache.fineract.portfolio.account.service.StandingInstructionReadService;
import org.springframework.stereotype.Component;
@Path("/v1/standinginstructions")
@Component
-@Tag(name = "Standing Instructions", description = "Standing instructions (or
standing orders) refer to instructions a bank account holder (\"the payer\")
gives to his or her bank to pay a set amount at regular intervals to another's
(\"the payee's\") account.\n"
- + "\n" + "Note: At present only savings account to savings account and
savings account to Loan account transfers are permitted.")
+@Produces({ MediaType.APPLICATION_JSON })
+@Tag(name = "Standing Instructions", description = """
+ Standing instructions (or standing orders) refer to instructions a
bank account holder ("the payer") gives to his or her bank to pay a set amount
at regular intervals to another's ("the payee's") account.
+
+ Note: At present only savings account to savings account and savings
account to Loan account transfers are permitted.""")
@RequiredArgsConstructor
public class StandingInstructionApiResource {
- private final PlatformSecurityContext context;
- private final DefaultToApiJsonSerializer<StandingInstructionData>
toApiJsonSerializer;
- private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
- private final StandingInstructionReadPlatformService
standingInstructionReadPlatformService;
+ private final StandingInstructionReadService
standingInstructionReadService;
private final AccountTransfersReadPlatformService
accountTransfersReadPlatformService;
private final SqlValidator sqlValidator;
-
- private static final CommandHandlerRegistry<String, Long, String,
CommandWrapper> COMMAND_HANDLER_REGISTRY = new CommandHandlerRegistry<>(
- Map.of(CommandParameterUtil.UPDATE_COMMAND_VALUE,
- (id, json) -> new
CommandWrapperBuilder().updateStandingInstruction(id).withJson(json).build(),
- CommandParameterUtil.DELETE_COMMAND_VALUE,
- (id, json) -> new
CommandWrapperBuilder().deleteStandingInstruction(id).withJson(json).build()));
+ private final CommandDispatcher dispatcher;
@GET
@Path("template")
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Retrieve Standing Instruction Template", operationId
= "retrieveTemplateStandingInstruction", 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:\n" + "\n"
+ "Field Defaults\n" + "Allowed Value Lists\n"
- + "Example Requests:\n" + "\n" +
"standinginstructions/template?fromAccountType=2&fromOfficeId=1\n" + "\n"
- +
"standinginstructions/template?fromAccountType=2&fromOfficeId=1&fromClientId=1&transferType=1\n"
+ "\n"
- +
"standinginstructions/template?fromClientId=1&fromAccountType=2&fromAccountId=1&transferType=1")
+ @Operation(summary = "Retrieve Standing Instruction Template", operationId
= "retrieveTemplateStandingInstruction", 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:
+
+ Field Defaults
+ Allowed Value Lists
+ Example Requests:
+
+ standinginstructions/template?fromAccountType=2&fromOfficeId=1
+
+
standinginstructions/template?fromAccountType=2&fromOfficeId=1&fromClientId=1&transferType=1
+
+
standinginstructions/template?fromClientId=1&fromAccountType=2&fromAccountId=1&transferType=1""")
@ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
StandingInstructionApiResourceSwagger.GetStandingInstructionsTemplateResponse.class)))
Review Comment:
1@Schema annotation not necessary when we have proper return types... All
these manually maintained dummy classes need to go.
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java:
##########
@@ -169,14 +186,15 @@ public Page<StandingInstructionData> retrieveAll(
StandingInstructionDTO standingInstructionDTO = new
StandingInstructionDTO(searchParameters, transferType, clientName, clientId,
Review Comment:
Let's call this StandingInstructionData... Suffix data... That's what we use
for DTO classes.
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java:
##########
@@ -39,110 +39,129 @@
import jakarta.ws.rs.core.UriInfo;
import java.time.LocalDate;
import java.util.Arrays;
-import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import lombok.RequiredArgsConstructor;
-import org.apache.fineract.batch.command.CommandHandlerRegistry;
-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.api.ApiParameterHelper;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import
org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
-import
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.CommandParameterUtil;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
-import
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.service.SqlValidator;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionCreateCommand;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionDeleteCommand;
+import
org.apache.fineract.portfolio.account.command.StandingInstructionUpdateCommand;
import org.apache.fineract.portfolio.account.data.AccountTransferData;
import org.apache.fineract.portfolio.account.data.StandingInstructionDTO;
import org.apache.fineract.portfolio.account.data.StandingInstructionData;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionCreationRequest;
+import
org.apache.fineract.portfolio.account.data.request.StandingInstructionDeleteRequest;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionSearchParam;
import
org.apache.fineract.portfolio.account.data.request.StandingInstructionUpdatesRequest;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionCreateResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionDeleteResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionUpdateResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionWriteResponse;
import
org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
-import
org.apache.fineract.portfolio.account.service.StandingInstructionReadPlatformService;
+import
org.apache.fineract.portfolio.account.service.StandingInstructionReadService;
import org.springframework.stereotype.Component;
@Path("/v1/standinginstructions")
@Component
-@Tag(name = "Standing Instructions", description = "Standing instructions (or
standing orders) refer to instructions a bank account holder (\"the payer\")
gives to his or her bank to pay a set amount at regular intervals to another's
(\"the payee's\") account.\n"
- + "\n" + "Note: At present only savings account to savings account and
savings account to Loan account transfers are permitted.")
+@Produces({ MediaType.APPLICATION_JSON })
+@Tag(name = "Standing Instructions", description = """
+ Standing instructions (or standing orders) refer to instructions a
bank account holder ("the payer") gives to his or her bank to pay a set amount
at regular intervals to another's ("the payee's") account.
+
+ Note: At present only savings account to savings account and savings
account to Loan account transfers are permitted.""")
@RequiredArgsConstructor
public class StandingInstructionApiResource {
- private final PlatformSecurityContext context;
- private final DefaultToApiJsonSerializer<StandingInstructionData>
toApiJsonSerializer;
- private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
- private final StandingInstructionReadPlatformService
standingInstructionReadPlatformService;
+ private final StandingInstructionReadService
standingInstructionReadService;
private final AccountTransfersReadPlatformService
accountTransfersReadPlatformService;
private final SqlValidator sqlValidator;
-
- private static final CommandHandlerRegistry<String, Long, String,
CommandWrapper> COMMAND_HANDLER_REGISTRY = new CommandHandlerRegistry<>(
- Map.of(CommandParameterUtil.UPDATE_COMMAND_VALUE,
- (id, json) -> new
CommandWrapperBuilder().updateStandingInstruction(id).withJson(json).build(),
- CommandParameterUtil.DELETE_COMMAND_VALUE,
- (id, json) -> new
CommandWrapperBuilder().deleteStandingInstruction(id).withJson(json).build()));
+ private final CommandDispatcher dispatcher;
@GET
@Path("template")
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Retrieve Standing Instruction Template", operationId
= "retrieveTemplateStandingInstruction", 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:\n" + "\n"
+ "Field Defaults\n" + "Allowed Value Lists\n"
- + "Example Requests:\n" + "\n" +
"standinginstructions/template?fromAccountType=2&fromOfficeId=1\n" + "\n"
- +
"standinginstructions/template?fromAccountType=2&fromOfficeId=1&fromClientId=1&transferType=1\n"
+ "\n"
- +
"standinginstructions/template?fromClientId=1&fromAccountType=2&fromAccountId=1&transferType=1")
+ @Operation(summary = "Retrieve Standing Instruction Template", operationId
= "retrieveTemplateStandingInstruction", 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:
+
+ Field Defaults
+ Allowed Value Lists
+ Example Requests:
+
+ standinginstructions/template?fromAccountType=2&fromOfficeId=1
+
+
standinginstructions/template?fromAccountType=2&fromOfficeId=1&fromClientId=1&transferType=1
+
+
standinginstructions/template?fromClientId=1&fromAccountType=2&fromAccountId=1&transferType=1""")
@ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
StandingInstructionApiResourceSwagger.GetStandingInstructionsTemplateResponse.class)))
public StandingInstructionData template(@BeanParam
StandingInstructionSearchParam instructionParam) {
-
context.authenticatedUser().validateHasReadPermission(StandingInstructionApiConstants.STANDING_INSTRUCTION_RESOURCE_NAME);
-
- return
standingInstructionReadPlatformService.retrieveTemplate(instructionParam.getFromOfficeId(),
- instructionParam.getFromClientId(),
instructionParam.getFromAccountId(), instructionParam.getFromAccountType(),
- instructionParam.getToOfficeId(),
instructionParam.getToClientId(), instructionParam.getToAccountId(),
- instructionParam.getToAccountType(),
instructionParam.getTransferType());
+ return
standingInstructionReadService.retrieveTemplate(instructionParam.getFromOfficeId(),
instructionParam.getFromClientId(),
+ instructionParam.getFromAccountId(),
instructionParam.getFromAccountType(), instructionParam.getToOfficeId(),
+ instructionParam.getToClientId(),
instructionParam.getToAccountId(), instructionParam.getToAccountType(),
+ instructionParam.getTransferType());
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create new Standing Instruction", operationId =
"createStandingInstruction", description = "Ability to create new instruction
for transfer of monetary funds from one account to another")
@RequestBody(required = true, content = @Content(schema =
@Schema(implementation = StandingInstructionCreationRequest.class)))
@ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
StandingInstructionApiResourceSwagger.PostStandingInstructionsResponse.class)))
- public CommandProcessingResult create(@Parameter(hidden = true)
StandingInstructionCreationRequest creationRequest) {
- final CommandWrapper commandRequest = new
CommandWrapperBuilder().createStandingInstruction()
-
.withJson(toApiJsonSerializer.serialize(creationRequest)).build();
+ public StandingInstructionCreateResponse create(@Parameter(hidden = true)
StandingInstructionCreationRequest creationRequest) {
+ final StandingInstructionCreateCommand command = new
StandingInstructionCreateCommand();
+ command.setPayload(creationRequest);
+
+ final Supplier<StandingInstructionCreateResponse> response =
dispatcher.dispatch(command);
- return
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ return response.get();
}
@PUT
@Path("{standingInstructionId}")
@Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Update Standing Instruction | Delete Standing
Instruction", operationId = "updateStandingInstruction", description = "Ability
to modify existing instruction for transfer of monetary funds from one account
to another.\n"
- + "\n" + "PUT
https://DomainName/api/v1/standinginstructions/1?command=update\n" + "\n\n"
- + "Ability to modify existing instruction for transfer of monetary
funds from one account to another.\n" + "\n"
- + "PUT
https://DomainName/api/v1/standinginstructions/1?command=delete")
+ @Operation(summary = "Update Standing Instruction | Delete Standing
Instruction", operationId = "updateStandingInstruction", description = """
+ Ability to modify existing instruction for transfer of monetary
funds from one account to another.
+
+ PUT https://DomainName/api/v1/standinginstructions/1?command=update
+
+
+ Ability to modify existing instruction for transfer of monetary
funds from one account to another.
+
+ PUT
https://DomainName/api/v1/standinginstructions/1?command=delete""")
@RequestBody(content = @Content(schema = @Schema(implementation =
StandingInstructionUpdatesRequest.class)))
@ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
StandingInstructionApiResourceSwagger.PutStandingInstructionsStandingInstructionIdResponse.class)))
- public CommandProcessingResult update(
+ public StandingInstructionWriteResponse update(
Review Comment:
Shouldn't this be StandingInstructionUpdateResponse?
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/request/StandingInstructionUpdatesRequest.java:
##########
@@ -18,30 +18,38 @@
*/
package org.apache.fineract.portfolio.account.data.request;
+import io.swagger.v3.oas.annotations.Hidden;
import java.io.Serial;
import java.io.Serializable;
+import java.math.BigDecimal;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+@Builder
@Data
@NoArgsConstructor
+@AllArgsConstructor
public class StandingInstructionUpdatesRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
- private String amount;
- private String validTill;
- private String dateFormat;
+ @Hidden
Review Comment:
Why hidden?
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/data/request/StandingInstructionUpdatesRequest.java:
##########
@@ -18,30 +18,38 @@
*/
package org.apache.fineract.portfolio.account.data.request;
+import io.swagger.v3.oas.annotations.Hidden;
import java.io.Serial;
import java.io.Serializable;
+import java.math.BigDecimal;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+@Builder
@Data
@NoArgsConstructor
+@AllArgsConstructor
public class StandingInstructionUpdatesRequest implements Serializable {
Review Comment:
StandingInstructionUpdateRequest... Singular, not "Updates"... Let's be
consistent.
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionWriteServiceImpl.java:
##########
@@ -0,0 +1,332 @@
+/**
+ * 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.account.service;
+
+import static
org.apache.fineract.portfolio.account.AccountDetailConstants.transferTypeParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.amountParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.instructionTypeParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.nameParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.priorityParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.recurrenceFrequencyParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.recurrenceIntervalParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.recurrenceOnMonthDayParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.recurrenceTypeParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.statusParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.validFromParamName;
+import static
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.validTillParamName;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.MonthDay;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+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.ErrorHandler;
+import
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.account.PortfolioAccountType;
+import
org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants;
+import
org.apache.fineract.portfolio.account.data.request.StandingInstructionCreationRequest;
+import
org.apache.fineract.portfolio.account.data.request.StandingInstructionDeleteRequest;
+import
org.apache.fineract.portfolio.account.data.request.StandingInstructionUpdatesRequest;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionCreateResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionDeleteResponse;
+import
org.apache.fineract.portfolio.account.data.response.StandingInstructionUpdateResponse;
+import
org.apache.fineract.portfolio.account.domain.AccountTransferDetailAssembler;
+import
org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
+import org.apache.fineract.portfolio.account.domain.AccountTransferDetails;
+import
org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType;
+import
org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstruction;
+import org.apache.fineract.portfolio.account.domain.AccountTransferType;
+import
org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
+import org.apache.fineract.portfolio.account.domain.StandingInstructionType;
+import
org.apache.fineract.portfolio.account.exception.StandingInstructionNotFoundException;
+import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.NonTransientDataAccessException;
+import org.springframework.orm.jpa.JpaSystemException;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+public class StandingInstructionWriteServiceImpl implements
StandingInstructionWriteService {
+
+ private final AccountTransferDetailAssembler
accountTransferDetailAssembler;
+ private final AccountTransferDetailRepository
accountTransferDetailRepository;
+ private final StandingInstructionRepository standingInstructionRepository;
+ private final SavingsAccountAssembler savingsAccountAssembler;
+ private final LoanAssembler loanAccountAssembler;
+
+ @Transactional
+ @Override
+ public StandingInstructionCreateResponse create(final
StandingInstructionCreationRequest request) {
+ final LocalDate validFrom = parseDate(request.getValidFrom(),
request.getDateFormat(), request.getLocale());
+ final LocalDate validTill = parseDate(request.getValidTill(),
request.getDateFormat(), request.getLocale());
+ final MonthDay recurrenceOnMonthDay =
parseMonthDay(request.getRecurrenceOnMonthDay(), request.getMonthDayFormat(),
+ request.getLocale());
+
+ validateForCreate(request, validFrom, validTill, recurrenceOnMonthDay);
+
+ final PortfolioAccountType fromAccountType =
PortfolioAccountType.fromInt(request.getFromAccountType());
+ final PortfolioAccountType toAccountType =
PortfolioAccountType.fromInt(request.getToAccountType());
+
+ Long standingInstructionId = null;
+ try {
+ final AccountTransferDetails details =
assembleAccountTransferDetails(request, fromAccountType, toAccountType);
+
+ BigDecimal amount = request.getAmount();
+ if (amount != null && details.fromSavingsAccount() != null) {
+ amount = Money.of(details.fromSavingsAccount().getCurrency(),
amount).getAmount();
+ }
+
+ final AccountTransferStandingInstruction standingInstruction =
AccountTransferStandingInstruction.create(details,
+ request.getName(), request.getPriority(),
request.getInstructionType(), request.getStatus(), amount, validFrom,
+ validTill, request.getRecurrenceType(),
request.getRecurrenceFrequency(), request.getRecurrenceInterval(),
+ recurrenceOnMonthDay);
+
details.updateAccountTransferStandingInstruction(standingInstruction);
+
+ this.accountTransferDetailRepository.saveAndFlush(details);
+ standingInstructionId =
details.accountTransferStandingInstruction().getId();
+ } catch (final JpaSystemException | DataIntegrityViolationException
dve) {
+ handleDataIntegrityIssues(request.getName(),
dve.getMostSpecificCause(), dve);
+ }
+
+ return
StandingInstructionCreateResponse.builder().resourceId(standingInstructionId).clientId(request.getFromClientId()).build();
+ }
+
+ @Transactional
+ @Override
+ public StandingInstructionUpdateResponse update(final
StandingInstructionUpdatesRequest request) {
+ final LocalDate validFrom = parseDate(request.getValidFrom(),
request.getDateFormat(), request.getLocale());
+ final LocalDate validTill = parseDate(request.getValidTill(),
request.getDateFormat(), request.getLocale());
+ final MonthDay recurrenceOnMonthDay =
parseMonthDay(request.getRecurrenceOnMonthDay(), request.getMonthDayFormat(),
+ request.getLocale());
+
+ validateForUpdate(request, validFrom, validTill);
+
+ final AccountTransferStandingInstruction standingInstruction =
this.standingInstructionRepository.findById(request.getId())
+ .orElseThrow(() -> new
StandingInstructionNotFoundException(request.getId()));
+
+ final Map<String, Object> changes =
standingInstruction.update(request.getAmount(), validFrom, validTill,
request.getStatus(),
+ request.getPriority(), request.getInstructionType(),
request.getRecurrenceType(), request.getRecurrenceFrequency(),
+ request.getRecurrenceInterval(), recurrenceOnMonthDay);
+
+ if (!changes.isEmpty()) {
+ this.standingInstructionRepository.save(standingInstruction);
+ }
+
+ return
StandingInstructionUpdateResponse.builder().resourceId(request.getId()).changes(changes).build();
+ }
+
+ @Transactional
+ @Override
+ public StandingInstructionDeleteResponse delete(final
StandingInstructionDeleteRequest request) {
+ final AccountTransferStandingInstruction standingInstruction =
this.standingInstructionRepository.findById(request.getId())
+ .orElseThrow(() -> new
StandingInstructionNotFoundException(request.getId()));
+ standingInstruction.delete();
+ this.standingInstructionRepository.save(standingInstruction);
+ return
StandingInstructionDeleteResponse.builder().resourceId(request.getId()).build();
+ }
+
+ private AccountTransferDetails assembleAccountTransferDetails(final
StandingInstructionCreationRequest request,
+ final PortfolioAccountType fromAccountType, final
PortfolioAccountType toAccountType) {
+ if (PortfolioAccountType.SAVINGS.equals(fromAccountType) &&
PortfolioAccountType.SAVINGS.equals(toAccountType)) {
+ final SavingsAccount fromSavingsAccount =
this.savingsAccountAssembler.assembleFrom(request.getFromAccountId(), false);
+ final SavingsAccount toSavingsAccount =
this.savingsAccountAssembler.assembleFrom(request.getToAccountId(), false);
+ return
this.accountTransferDetailAssembler.assembleSavingsToSavingsTransfer(fromSavingsAccount,
toSavingsAccount,
+ request.getTransferType());
+ } else if (PortfolioAccountType.SAVINGS.equals(fromAccountType) &&
PortfolioAccountType.LOAN.equals(toAccountType)) {
+ final SavingsAccount fromSavingsAccount =
this.savingsAccountAssembler.assembleFrom(request.getFromAccountId(), false);
+ final Loan toLoanAccount =
this.loanAccountAssembler.assembleFrom(request.getToAccountId());
+ return
this.accountTransferDetailAssembler.assembleSavingsToLoanTransfer(fromSavingsAccount,
toLoanAccount,
+ request.getTransferType());
+ } else if (PortfolioAccountType.LOAN.equals(fromAccountType) &&
PortfolioAccountType.SAVINGS.equals(toAccountType)) {
+ final Loan fromLoanAccount =
this.loanAccountAssembler.assembleFrom(request.getFromAccountId());
+ final SavingsAccount toSavingsAccount =
this.savingsAccountAssembler.assembleFrom(request.getToAccountId(), false);
+ return
this.accountTransferDetailAssembler.assembleLoanToSavingsTransfer(fromLoanAccount,
toSavingsAccount,
+ request.getTransferType());
+ }
+ throw new
PlatformDataIntegrityException("error.msg.standinginstruction.transfer.type.not.supported",
+ "Transfer between the given account types is not supported for
standing instructions");
+ }
+
+ private void validateForCreate(final StandingInstructionCreationRequest
request, final LocalDate validFrom, final LocalDate validTill,
Review Comment:
Could this be done using Jakarta Validation?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]