FINERACT-2169: Refactor account transfer api controller;

This commit is contained in:
viktorpavlenko
2025-03-27 11:45:35 +01:00
committed by Adam Saghy
parent e584e26c39
commit bb5078b5da
8 changed files with 305 additions and 218 deletions
@@ -53,7 +53,7 @@ import org.springframework.stereotype.Component;
@Path("/v1/runreports")
@Component
@Tag(name = "Run Reports", description = "")
@Tag(name = "Run Reports")
@RequiredArgsConstructor
public class RunreportsApiResource {
@@ -69,7 +69,7 @@ public class RunreportsApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Return all available export types for the specific report", description = "Returns the list of all available export types.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ReportExportType.class)))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ReportExportType.class)))) })
public Response retrieveAllAvailableExports(@PathParam("reportName") @Parameter(description = "reportName") final String reportName,
@Context final UriInfo uriInfo,
@DefaultValue("false") @QueryParam(IS_SELF_SERVICE_USER_REPORT_PARAMETER) @Parameter(description = IS_SELF_SERVICE_USER_REPORT_PARAMETER) final boolean isSelfServiceUserReport) {
@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
@@ -33,22 +34,19 @@ import jakarta.ws.rs.Path;
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 lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.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.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.data.AccountTransferData;
import org.apache.fineract.portfolio.account.data.request.AccountTransSearchParam;
import org.apache.fineract.portfolio.account.data.request.AccountTransferRequest;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
import org.springframework.stereotype.Component;
@@ -61,9 +59,7 @@ public class AccountTransfersApiResource {
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<AccountTransferData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
private final SqlValidator sqlValidator;
@GET
@Path("template")
@@ -76,38 +72,28 @@ public class AccountTransfersApiResource {
+ "accounttransfers/template?fromClientId=1&fromAccountType=2&fromAccountId=1")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.GetAccountTransfersTemplateResponse.class))) })
public String template(@QueryParam("fromOfficeId") @Parameter(description = "fromOfficeId") final Long fromOfficeId,
@QueryParam("fromClientId") @Parameter(description = "fromClientId") final Long fromClientId,
@QueryParam("fromAccountId") @Parameter(description = "fromAccountId") final Long fromAccountId,
@QueryParam("fromAccountType") @Parameter(description = "fromAccountType") final Integer fromAccountType,
@QueryParam("toOfficeId") @Parameter(description = "toOfficeId") final Long toOfficeId,
@QueryParam("toClientId") @Parameter(description = "toClientId") final Long toClientId,
@QueryParam("toAccountId") @Parameter(description = "toAccountId") final Long toAccountId,
@QueryParam("toAccountType") @Parameter(description = "toAccountType") final Integer toAccountType,
@Context final UriInfo uriInfo) {
public AccountTransferData template(@BeanParam AccountTransSearchParam accountTransSearchParam) {
this.context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
final AccountTransferData transferData = this.accountTransfersReadPlatformService.retrieveTemplate(fromOfficeId, fromClientId,
fromAccountId, fromAccountType, toOfficeId, toClientId, toAccountId, toAccountType);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, transferData, AccountTransfersApiConstants.RESPONSE_DATA_PARAMETERS);
return accountTransfersReadPlatformService.retrieveTemplate(accountTransSearchParam.getFromAccountId(),
accountTransSearchParam.getFromClientId(), accountTransSearchParam.getFromAccountId(),
accountTransSearchParam.getFromAccountType(), accountTransSearchParam.getToOfficeId(),
accountTransSearchParam.getToClientId(), accountTransSearchParam.getToAccountId(),
accountTransSearchParam.getToAccountType());
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create new Transfer", description = "Ability to create new transfer of monetary funds from one account to another.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.PostAccountTransfersRequest.class)))
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = AccountTransferRequest.class)))
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.PostAccountTransfersResponse.class)))
public String create(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
public CommandProcessingResult create(@Parameter(hidden = true) AccountTransferRequest accountTransferRequest) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createAccountTransfer()
.withJson(toApiJsonSerializer.serialize(accountTransferRequest)).build();
final CommandWrapper commandRequest = new CommandWrapperBuilder().createAccountTransfer().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
return commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
@GET
@@ -117,26 +103,19 @@ public class AccountTransfersApiResource {
+ "accounttransfers")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.GetAccountTransfersResponse.class))) })
public String retrieveAll(@Context final UriInfo uriInfo,
@QueryParam("externalId") @Parameter(description = "externalId") final String externalId,
public Page<AccountTransferData> retrieveAll(@QueryParam("externalId") @Parameter(description = "externalId") final String externalId,
@QueryParam("offset") @Parameter(description = "offset") final Integer offset,
@QueryParam("limit") @Parameter(example = "limit") final Integer limit,
@QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy,
@QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder,
@QueryParam("accountDetailId") @Parameter(description = "accountDetailId") final Long accountDetailId) {
this.context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
sqlValidator.validate(orderBy);
sqlValidator.validate(sortOrder);
sqlValidator.validate(externalId);
final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
.orderBy(orderBy).sortOrder(sortOrder).build();
final Page<AccountTransferData> transfers = this.accountTransfersReadPlatformService.retrieveAll(searchParameters, accountDetailId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, transfers, AccountTransfersApiConstants.RESPONSE_DATA_PARAMETERS);
return accountTransfersReadPlatformService.retrieveAll(searchParameters, accountDetailId);
}
@GET
@@ -147,15 +126,9 @@ public class AccountTransfersApiResource {
+ "accounttransfers/1")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.GetAccountTransfersResponse.GetAccountTransfersPageItems.class))) })
public String retrieveOne(@PathParam("transferId") @Parameter(description = "transferId") final Long transferId,
@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
final AccountTransferData transfer = this.accountTransfersReadPlatformService.retrieveOne(transferId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, transfer, AccountTransfersApiConstants.RESPONSE_DATA_PARAMETERS);
public AccountTransferData retrieveOne(@PathParam("transferId") @Parameter(description = "transferId") final Long transferId) {
context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
return accountTransfersReadPlatformService.retrieveOne(transferId);
}
@GET
@@ -167,23 +140,13 @@ public class AccountTransfersApiResource {
+ "accounttransfers/templateRefundByTransfer?fromAccountId=2&fromAccountType=1& toAccountId=1&toAccountType=2&toClientId=1&toOfficeId=1")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.GetAccountTransfersTemplateRefundByTransferResponse.class))) })
public String templateRefundByTransfer(@QueryParam("fromOfficeId") @Parameter(description = "fromOfficeId") final Long fromOfficeId,
@QueryParam("fromClientId") @Parameter(description = "fromClientId") final Long fromClientId,
@QueryParam("fromAccountId") @Parameter(description = "fromAccountId") final Long fromAccountId,
@QueryParam("fromAccountType") @Parameter(description = "fromAccountType") final Integer fromAccountType,
@QueryParam("toOfficeId") @Parameter(description = "toOfficeId") final Long toOfficeId,
@QueryParam("toClientId") @Parameter(description = "toClientId") final Long toClientId,
@QueryParam("toAccountId") @Parameter(description = "toAccountId") final Long toAccountId,
@QueryParam("toAccountType") @Parameter(description = "toAccountType") final Integer toAccountType,
@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
final AccountTransferData transferData = this.accountTransfersReadPlatformService.retrieveRefundByTransferTemplate(fromOfficeId,
fromClientId, fromAccountId, fromAccountType, toOfficeId, toClientId, toAccountId, toAccountType);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, transferData, AccountTransfersApiConstants.RESPONSE_DATA_PARAMETERS);
public AccountTransferData templateRefundByTransfer(@BeanParam AccountTransSearchParam accountTransSearchParam) {
context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
return accountTransfersReadPlatformService.retrieveRefundByTransferTemplate(accountTransSearchParam.getFromAccountId(),
accountTransSearchParam.getFromClientId(), accountTransSearchParam.getFromAccountId(),
accountTransSearchParam.getFromAccountType(), accountTransSearchParam.getToOfficeId(),
accountTransSearchParam.getToClientId(), accountTransSearchParam.getToAccountId(),
accountTransSearchParam.getToAccountType());
}
@POST
@@ -191,15 +154,12 @@ public class AccountTransfersApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Refund of an Active Loan by Transfer", description = "Ability to refund an active loan by transferring to a savings account.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.PostAccountTransfersRefundByTransferRequest.class)))
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = AccountTransferRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountTransfersApiResourceSwagger.PostAccountTransfersRefundByTransferResponse.class))) })
public String templateRefundByTransferPost(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().refundByTransfer().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
public CommandProcessingResult templateRefundByTransferPost(@Parameter(hidden = true) AccountTransferRequest accountTransferRequest) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().refundByTransfer()
.withJson(toApiJsonSerializer.serialize(accountTransferRequest)).build();
return commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
}
@@ -0,0 +1,52 @@
/**
* 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.data.request;
import jakarta.ws.rs.QueryParam;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AccountTransSearchParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@QueryParam("fromOfficeId")
private Long fromOfficeId;
@QueryParam("fromClientId")
private Long fromClientId;
@QueryParam("fromAccountId")
private Long fromAccountId;
@QueryParam("fromAccountType")
private Integer fromAccountType;
@QueryParam("toOfficeId")
private Long toOfficeId;
@QueryParam("toClientId")
private Long toClientId;
@QueryParam("toAccountId")
private Long toAccountId;
@QueryParam("toAccountType")
private Integer toAccountType;
}
@@ -0,0 +1,46 @@
/**
* 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.data.request;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class AccountTransferRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String transferDescription;
private String toOfficeId;
private String toAccountType;
private String dateFormat;
private String transferAmount;
private String toAccountId;
private String fromClientId;
private String locale;
private String transferDate;
private String fromAccountType;
private String toClientId;
private String fromAccountId;
private String fromOfficeId;
}
@@ -0,0 +1,153 @@
/**
* 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.mapper;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.data.AccountTransferData;
import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
import org.apache.fineract.portfolio.account.service.AccountTransferEnumerations;
import org.apache.fineract.portfolio.client.data.ClientData;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
@Component
public final class AccountTransfersMapper implements RowMapper<AccountTransferData> {
private final String schemaSql;
public AccountTransfersMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("att.id as id, att.is_reversed as isReversed,");
sqlBuilder.append("att.transaction_date as transferDate, att.amount as transferAmount,");
sqlBuilder.append("att.description as transferDescription,");
sqlBuilder.append("att.currency_code as currencyCode, att.currency_digits as currencyDigits,");
sqlBuilder.append("att.currency_multiplesof as inMultiplesOf, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder.append("fromoff.id as fromOfficeId, fromoff.name as fromOfficeName,");
sqlBuilder.append("tooff.id as toOfficeId, tooff.name as toOfficeName,");
sqlBuilder.append("fromclient.id as fromClientId, fromclient.display_name as fromClientName,");
sqlBuilder.append("toclient.id as toClientId, toclient.display_name as toClientName,");
sqlBuilder.append("fromsavacc.id as fromSavingsAccountId, fromsavacc.account_no as fromSavingsAccountNo,");
sqlBuilder.append("fromloanacc.id as fromLoanAccountId, fromloanacc.account_no as fromLoanAccountNo,");
sqlBuilder.append("tosavacc.id as toSavingsAccountId, tosavacc.account_no as toSavingsAccountNo,");
sqlBuilder.append("toloanacc.id as toLoanAccountId, toloanacc.account_no as toLoanAccountNo,");
sqlBuilder.append("fromsavtran.id as fromSavingsAccountTransactionId,");
sqlBuilder.append("fromsavtran.transaction_type_enum as fromSavingsAccountTransactionType,");
sqlBuilder.append("tosavtran.id as toSavingsAccountTransactionId,");
sqlBuilder.append("tosavtran.transaction_type_enum as toSavingsAccountTransactionType");
sqlBuilder.append(" FROM m_account_transfer_transaction att ");
sqlBuilder.append("left join m_account_transfer_details atd on atd.id = att.account_transfer_details_id ");
sqlBuilder.append("join m_currency curr on curr.code = att.currency_code ");
sqlBuilder.append("join m_office fromoff on fromoff.id = atd.from_office_id ");
sqlBuilder.append("join m_office tooff on tooff.id = atd.to_office_id ");
sqlBuilder.append("join m_client fromclient on fromclient.id = atd.from_client_id ");
sqlBuilder.append("join m_client toclient on toclient.id = atd.to_client_id ");
sqlBuilder.append("left join m_savings_account fromsavacc on fromsavacc.id = atd.from_savings_account_id ");
sqlBuilder.append("left join m_loan fromloanacc on fromloanacc.id = atd.from_loan_account_id ");
sqlBuilder.append("left join m_savings_account tosavacc on tosavacc.id = atd.to_savings_account_id ");
sqlBuilder.append("left join m_loan toloanacc on toloanacc.id = atd.to_loan_account_id ");
sqlBuilder.append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = att.from_savings_transaction_id ");
sqlBuilder.append("left join m_savings_account_transaction tosavtran on tosavtran.id = att.to_savings_transaction_id ");
sqlBuilder.append("left join m_loan_transaction fromloantran on fromloantran.id = att.from_savings_transaction_id ");
sqlBuilder.append("left join m_loan_transaction toloantran on toloantran.id = att.to_savings_transaction_id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public AccountTransferData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final boolean reversed = rs.getBoolean("isReversed");
final LocalDate transferDate = JdbcSupport.getLocalDate(rs, "transferDate");
final BigDecimal transferAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transferAmount");
final String transferDescription = rs.getString("transferDescription");
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
currencyNameCode);
final Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId");
final String fromOfficeName = rs.getString("fromOfficeName");
final OfficeData fromOffice = OfficeData.dropdown(fromOfficeId, fromOfficeName, null);
final Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId");
final String toOfficeName = rs.getString("toOfficeName");
final OfficeData toOffice = OfficeData.dropdown(toOfficeId, toOfficeName, null);
final Long fromClientId = JdbcSupport.getLong(rs, "fromClientId");
final String fromClientName = rs.getString("fromClientName");
final ClientData fromClient = ClientData.lookup(fromClientId, fromClientName, fromOfficeId, fromOfficeName);
final Long toClientId = JdbcSupport.getLong(rs, "toClientId");
final String toClientName = rs.getString("toClientName");
final ClientData toClient = ClientData.lookup(toClientId, toClientName, toOfficeId, toOfficeName);
final Long fromSavingsAccountId = JdbcSupport.getLong(rs, "fromSavingsAccountId");
final String fromSavingsAccountNo = rs.getString("fromSavingsAccountNo");
final Long fromLoanAccountId = JdbcSupport.getLong(rs, "fromLoanAccountId");
final String fromLoanAccountNo = rs.getString("fromLoanAccountNo");
PortfolioAccountData fromAccount = null;
EnumOptionData fromAccountType = null;
if (fromSavingsAccountId != null) {
fromAccount = PortfolioAccountData.lookup(fromSavingsAccountId, fromSavingsAccountNo);
fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS);
} else if (fromLoanAccountId != null) {
fromAccount = PortfolioAccountData.lookup(fromLoanAccountId, fromLoanAccountNo);
fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN);
}
PortfolioAccountData toAccount = null;
EnumOptionData toAccountType = null;
final Long toSavingsAccountId = JdbcSupport.getLong(rs, "toSavingsAccountId");
final String toSavingsAccountNo = rs.getString("toSavingsAccountNo");
final Long toLoanAccountId = JdbcSupport.getLong(rs, "toLoanAccountId");
final String toLoanAccountNo = rs.getString("toLoanAccountNo");
if (toSavingsAccountId != null) {
toAccount = PortfolioAccountData.lookup(toSavingsAccountId, toSavingsAccountNo);
toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS);
} else if (toLoanAccountId != null) {
toAccount = PortfolioAccountData.lookup(toLoanAccountId, toLoanAccountNo);
toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN);
}
return AccountTransferData.instance(id, reversed, transferDate, currency, transferAmount, transferDescription, fromOffice, toOffice,
fromClient, toClient, fromAccountType, fromAccount, toAccountType, toAccount);
}
}
@@ -19,22 +19,21 @@
package org.apache.fineract.portfolio.account.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.SqlValidator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
@@ -43,13 +42,14 @@ import org.apache.fineract.portfolio.account.data.PortfolioAccountDTO;
import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
import org.apache.fineract.portfolio.account.domain.AccountTransferType;
import org.apache.fineract.portfolio.account.exception.AccountTransferNotFoundException;
import org.apache.fineract.portfolio.account.mapper.AccountTransfersMapper;
import org.apache.fineract.portfolio.client.data.ClientData;
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;
@RequiredArgsConstructor
public class AccountTransfersReadPlatformServiceImpl implements AccountTransfersReadPlatformService {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@@ -63,20 +63,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
private final AccountTransfersMapper accountTransfersMapper;
// pagination
private final PaginationHelper paginationHelper;
public AccountTransfersReadPlatformServiceImpl(final JdbcTemplate jdbcTemplate,
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = jdbcTemplate;
this.clientReadPlatformService = clientReadPlatformService;
this.officeReadPlatformService = officeReadPlatformService;
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformService;
this.columnValidator = columnValidator;
this.sqlGenerator = sqlGenerator;
this.accountTransfersMapper = new AccountTransfersMapper();
this.paginationHelper = paginationHelper;
}
private final SqlValidator sqlValidator;
@Override
public AccountTransferData retrieveTemplate(final Long fromOfficeId, final Long fromClientId, final Long fromAccountId,
@@ -208,7 +195,8 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
@Override
public Page<AccountTransferData> retrieveAll(final SearchParameters searchParameters, final Long accountDetailId) {
Stream.of(searchParameters.getOrderBy(), searchParameters.getSortOrder(), searchParameters.getExternalId())
.forEach(sqlValidator::validate);
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.accountTransfersMapper.schema());
@@ -434,122 +422,4 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), BigDecimal.class, DATE_TIME_FORMATTER.format(transactionDate),
accountType, accountId, accountId);
}
private static final class AccountTransfersMapper implements RowMapper<AccountTransferData> {
private final String schemaSql;
AccountTransfersMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("att.id as id, att.is_reversed as isReversed,");
sqlBuilder.append("att.transaction_date as transferDate, att.amount as transferAmount,");
sqlBuilder.append("att.description as transferDescription,");
sqlBuilder.append("att.currency_code as currencyCode, att.currency_digits as currencyDigits,");
sqlBuilder.append("att.currency_multiplesof as inMultiplesOf, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder.append("fromoff.id as fromOfficeId, fromoff.name as fromOfficeName,");
sqlBuilder.append("tooff.id as toOfficeId, tooff.name as toOfficeName,");
sqlBuilder.append("fromclient.id as fromClientId, fromclient.display_name as fromClientName,");
sqlBuilder.append("toclient.id as toClientId, toclient.display_name as toClientName,");
sqlBuilder.append("fromsavacc.id as fromSavingsAccountId, fromsavacc.account_no as fromSavingsAccountNo,");
sqlBuilder.append("fromloanacc.id as fromLoanAccountId, fromloanacc.account_no as fromLoanAccountNo,");
sqlBuilder.append("tosavacc.id as toSavingsAccountId, tosavacc.account_no as toSavingsAccountNo,");
sqlBuilder.append("toloanacc.id as toLoanAccountId, toloanacc.account_no as toLoanAccountNo,");
sqlBuilder.append("fromsavtran.id as fromSavingsAccountTransactionId,");
sqlBuilder.append("fromsavtran.transaction_type_enum as fromSavingsAccountTransactionType,");
sqlBuilder.append("tosavtran.id as toSavingsAccountTransactionId,");
sqlBuilder.append("tosavtran.transaction_type_enum as toSavingsAccountTransactionType");
sqlBuilder.append(" FROM m_account_transfer_transaction att ");
sqlBuilder.append("left join m_account_transfer_details atd on atd.id = att.account_transfer_details_id ");
sqlBuilder.append("join m_currency curr on curr.code = att.currency_code ");
sqlBuilder.append("join m_office fromoff on fromoff.id = atd.from_office_id ");
sqlBuilder.append("join m_office tooff on tooff.id = atd.to_office_id ");
sqlBuilder.append("join m_client fromclient on fromclient.id = atd.from_client_id ");
sqlBuilder.append("join m_client toclient on toclient.id = atd.to_client_id ");
sqlBuilder.append("left join m_savings_account fromsavacc on fromsavacc.id = atd.from_savings_account_id ");
sqlBuilder.append("left join m_loan fromloanacc on fromloanacc.id = atd.from_loan_account_id ");
sqlBuilder.append("left join m_savings_account tosavacc on tosavacc.id = atd.to_savings_account_id ");
sqlBuilder.append("left join m_loan toloanacc on toloanacc.id = atd.to_loan_account_id ");
sqlBuilder.append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = att.from_savings_transaction_id ");
sqlBuilder.append("left join m_savings_account_transaction tosavtran on tosavtran.id = att.to_savings_transaction_id ");
sqlBuilder.append("left join m_loan_transaction fromloantran on fromloantran.id = att.from_savings_transaction_id ");
sqlBuilder.append("left join m_loan_transaction toloantran on toloantran.id = att.to_savings_transaction_id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public AccountTransferData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final boolean reversed = rs.getBoolean("isReversed");
final LocalDate transferDate = JdbcSupport.getLocalDate(rs, "transferDate");
final BigDecimal transferAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transferAmount");
final String transferDescription = rs.getString("transferDescription");
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
currencyNameCode);
final Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId");
final String fromOfficeName = rs.getString("fromOfficeName");
final OfficeData fromOffice = OfficeData.dropdown(fromOfficeId, fromOfficeName, null);
final Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId");
final String toOfficeName = rs.getString("toOfficeName");
final OfficeData toOffice = OfficeData.dropdown(toOfficeId, toOfficeName, null);
final Long fromClientId = JdbcSupport.getLong(rs, "fromClientId");
final String fromClientName = rs.getString("fromClientName");
final ClientData fromClient = ClientData.lookup(fromClientId, fromClientName, fromOfficeId, fromOfficeName);
final Long toClientId = JdbcSupport.getLong(rs, "toClientId");
final String toClientName = rs.getString("toClientName");
final ClientData toClient = ClientData.lookup(toClientId, toClientName, toOfficeId, toOfficeName);
final Long fromSavingsAccountId = JdbcSupport.getLong(rs, "fromSavingsAccountId");
final String fromSavingsAccountNo = rs.getString("fromSavingsAccountNo");
final Long fromLoanAccountId = JdbcSupport.getLong(rs, "fromLoanAccountId");
final String fromLoanAccountNo = rs.getString("fromLoanAccountNo");
PortfolioAccountData fromAccount = null;
EnumOptionData fromAccountType = null;
if (fromSavingsAccountId != null) {
fromAccount = PortfolioAccountData.lookup(fromSavingsAccountId, fromSavingsAccountNo);
fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS);
} else if (fromLoanAccountId != null) {
fromAccount = PortfolioAccountData.lookup(fromLoanAccountId, fromLoanAccountNo);
fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN);
}
PortfolioAccountData toAccount = null;
EnumOptionData toAccountType = null;
final Long toSavingsAccountId = JdbcSupport.getLong(rs, "toSavingsAccountId");
final String toSavingsAccountNo = rs.getString("toSavingsAccountNo");
final Long toLoanAccountId = JdbcSupport.getLong(rs, "toLoanAccountId");
final String toLoanAccountNo = rs.getString("toLoanAccountNo");
if (toSavingsAccountId != null) {
toAccount = PortfolioAccountData.lookup(toSavingsAccountId, toSavingsAccountNo);
toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS);
} else if (toLoanAccountId != null) {
toAccount = PortfolioAccountData.lookup(toLoanAccountId, toLoanAccountNo);
toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN);
}
return AccountTransferData.instance(id, reversed, transferDate, currency, transferAmount, transferDescription, fromOffice,
toOffice, fromClient, toClient, fromAccountType, fromAccount, toAccountType, toAccount);
}
}
}
@@ -23,6 +23,7 @@ import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.SqlValidator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.portfolio.account.data.AccountTransfersDataValidator;
@@ -32,6 +33,7 @@ import org.apache.fineract.portfolio.account.domain.AccountTransferDetailReposit
import org.apache.fineract.portfolio.account.domain.AccountTransferRepository;
import org.apache.fineract.portfolio.account.domain.StandingInstructionAssembler;
import org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
import org.apache.fineract.portfolio.account.mapper.AccountTransfersMapper;
import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService;
import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformServiceImpl;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
@@ -74,9 +76,10 @@ public class AccountConfiguration {
public AccountTransfersReadPlatformService accountTransfersReadPlatformService(JdbcTemplate jdbcTemplate,
ClientReadPlatformService clientReadPlatformService, OfficeReadPlatformService officeReadPlatformService,
PortfolioAccountReadPlatformService portfolioAccountReadPlatformService, ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
DatabaseSpecificSQLGenerator sqlGenerator, AccountTransfersMapper accountTransfersMapper, PaginationHelper paginationHelper,
SqlValidator sqlValidator) {
return new AccountTransfersReadPlatformServiceImpl(jdbcTemplate, clientReadPlatformService, officeReadPlatformService,
portfolioAccountReadPlatformService, columnValidator, sqlGenerator, paginationHelper);
portfolioAccountReadPlatformService, columnValidator, sqlGenerator, accountTransfersMapper, paginationHelper, sqlValidator);
}
@Bean
@@ -43,10 +43,12 @@ import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
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.account.api.AccountTransfersApiResource;
import org.apache.fineract.portfolio.account.data.request.AccountTransferRequest;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
import org.apache.fineract.portfolio.self.account.data.SelfAccountTemplateData;
import org.apache.fineract.portfolio.self.account.data.SelfAccountTransferData;
@@ -105,13 +107,14 @@ public class SelfAccountTransferApiResource {
+ "\n" + "\n" + "Example Requests:\n" + "\n" + " self/accounttransfers/\n")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = SelfAccountTransferApiResourceSwagger.PostNewTransferResponse.class)))) })
public String create(@DefaultValue("") @QueryParam("type") @Parameter(name = "type") final String type,
final String apiRequestBodyAsJson) {
public CommandProcessingResult create(@DefaultValue("") @QueryParam("type") @Parameter(name = "type") final String type,
AccountTransferRequest accountTransferRequest) {
final String apiRequestBodyAsJson = toApiJsonSerializer.serialize(accountTransferRequest);
Map<String, Object> params = this.dataValidator.validateCreate(type, apiRequestBodyAsJson);
if (type.equals("tpt")) {
checkForLimits(params);
}
return this.accountTransfersApiResource.create(apiRequestBodyAsJson);
return this.accountTransfersApiResource.create(accountTransferRequest);
}
private void checkForLimits(Map<String, Object> params) {