FINERACT-1927: Incorrect exception info in BatchAPI response

This commit is contained in:
jmarta
2023-09-27 19:13:26 +02:00
committed by Adam Saghy
parent f452ce2cad
commit 32da7db35d
55 changed files with 1399 additions and 1134 deletions
@@ -48,23 +48,11 @@ public class ApplySavingsCommandStrategy implements CommandStrategy {
@Override
public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) {
// Calls 'submitApplication' function from 'SavingsAccountsApiResource' to Apply Savings to an existing client
String responseBody = savingsAccountsApiResource.submitApplication(request.getBody());
final BatchResponse response = new BatchResponse();
final String responseBody;
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
// Calls 'submitApplication' function from
// 'SavingsAccountsApiResource' to Apply Savings to an existing
// client
responseBody = savingsAccountsApiResource.submitApplication(request.getBody());
response.setStatusCode(HttpStatus.SC_OK);
// Sets the body of the response after savings is successfully
// applied
response.setBody(responseBody);
return response;
// Sets the body of the response after savings is successfully applied
return new BatchResponse().setRequestId(request.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody)
.setHeaders(request.getHeaders());
}
}
@@ -0,0 +1,74 @@
/**
* 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.batch.command.internal;
import static org.apache.fineract.batch.command.CommandStrategyUtils.relativeUrlWithoutVersion;
import com.google.common.base.Splitter;
import jakarta.ws.rs.core.UriInfo;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
* Implements {@link CommandStrategy} and deletes a new datatable entry for a given entity. It passes the contents of
* the body from the BatchRequest to {@link DatatablesApiResource} and gets back the response. This class will also
* catch any errors raised by {@link DatatablesApiResource} and map those errors to appropriate status codes in
* BatchResponse.
*
* @see CommandStrategy
* @see BatchRequest
* @see BatchResponse
*/
@Component
@RequiredArgsConstructor
public class DeleteDatatableEntryOneToManyCommandStrategy implements CommandStrategy {
private final DatatablesApiResource datatablesApiResource;
@Override
public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) {
final BatchResponse response = new BatchResponse();
final String responseBody;
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
final List<String> pathParameters = Splitter.on('/').splitToList(relativeUrlWithoutVersion(request));
// Pluck out the datatable name & entityId out of the relative path
final String datatableName = pathParameters.get(1);
final Long entityId = Long.parseLong(pathParameters.get(2));
final Long entryId = Long.parseLong(pathParameters.get(3));
// Calls 'deleteDatatableEntry' function from 'DatatablesApiResource' to delete a datatable entry on an existing
// entity
responseBody = datatablesApiResource.deleteDatatableEntry(datatableName, entityId, entryId);
response.setStatusCode(HttpStatus.SC_OK);
// Sets the body of the response after datatable entry is successfully deleted created
response.setBody(responseBody);
return response;
}
}
@@ -0,0 +1,73 @@
/**
* 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.batch.command.internal;
import static org.apache.fineract.batch.command.CommandStrategyUtils.relativeUrlWithoutVersion;
import com.google.common.base.Splitter;
import jakarta.ws.rs.core.UriInfo;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
* Implements {@link CommandStrategy} and deletes a new datatable entry for a given entity. It passes the contents of
* the body from the BatchRequest to {@link DatatablesApiResource} and gets back the response. This class will also
* catch any errors raised by {@link DatatablesApiResource} and map those errors to appropriate status codes in
* BatchResponse.
*
* @see CommandStrategy
* @see BatchRequest
* @see BatchResponse
*/
@Component
@RequiredArgsConstructor
public class DeleteDatatableEntryOneToOneCommandStrategy implements CommandStrategy {
private final DatatablesApiResource datatablesApiResource;
@Override
public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) {
final BatchResponse response = new BatchResponse();
final String responseBody;
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
final List<String> pathParameters = Splitter.on('/').splitToList(relativeUrlWithoutVersion(request));
// Pluck out the datatable name & entityId out of the relative path
final String datatableName = pathParameters.get(1);
final Long entityId = Long.parseLong(pathParameters.get(2));
// Calls 'deleteDatatableEntry' function from 'DatatablesApiResource' to delete a datatable entry on an existing
// entity
responseBody = datatablesApiResource.deleteDatatableEntries(datatableName, entityId);
response.setStatusCode(HttpStatus.SC_OK);
// Sets the body of the response after datatable entry is successfully deleted created
response.setBody(responseBody);
return response;
}
}
@@ -43,14 +43,9 @@ public class GetSavingsAccountByIdCommandStrategy implements CommandStrategy {
@Override
public BatchResponse execute(BatchRequest batchRequest, UriInfo uriInfo) {
final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo);
final BatchResponse response = new BatchResponse();
response.setRequestId(batchRequest.getRequestId());
response.setHeaders(batchRequest.getHeaders());
final String relativeUrl = relativeUrlWithoutVersion(batchRequest);
final Long savingsAccountId;
final long savingsAccountId;
Map<String, String> queryParameters = new HashMap<>();
if (relativeUrl.indexOf('?') > 0) {
savingsAccountId = Long.parseLong(StringUtils.substringBetween(relativeUrl, "/", "?"));
@@ -74,10 +69,7 @@ public class GetSavingsAccountByIdCommandStrategy implements CommandStrategy {
final String responseBody = savingsAccountsApiResource.retrieveOne(savingsAccountId,
Boolean.parseBoolean(staffInSelectedOfficeOnly), chargeStatus, uriInfo);
response.setStatusCode(HttpStatus.SC_OK);
response.setBody(responseBody);
return response;
return new BatchResponse().setRequestId(batchRequest.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody)
.setHeaders(batchRequest.getHeaders());
}
}
@@ -42,10 +42,6 @@ public class SavingsAccountAdjustTransactionCommandStrategy implements CommandSt
@Override
public BatchResponse execute(BatchRequest batchRequest, UriInfo uriInfo) {
final BatchResponse response = new BatchResponse();
response.setRequestId(batchRequest.getRequestId());
response.setHeaders(batchRequest.getHeaders());
String relativeUrl = relativeUrlWithoutVersion(batchRequest);
final List<String> pathParameters;
String command = null;
@@ -63,10 +59,7 @@ public class SavingsAccountAdjustTransactionCommandStrategy implements CommandSt
final String responseBody = savingsAccountTransactionsApiResource.adjustTransaction(savingsAccountId, transactionId, command,
batchRequest.getBody());
response.setStatusCode(HttpStatus.SC_OK);
response.setBody(responseBody);
return response;
return new BatchResponse().setRequestId(batchRequest.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody)
.setHeaders(batchRequest.getHeaders());
}
}
@@ -41,10 +41,6 @@ public class SavingsAccountTransactionCommandStrategy implements CommandStrategy
@Override
public BatchResponse execute(BatchRequest batchRequest, UriInfo uriInfo) {
final BatchResponse response = new BatchResponse();
response.setRequestId(batchRequest.getRequestId());
response.setHeaders(batchRequest.getHeaders());
String relativeUrl = relativeUrlWithoutVersion(batchRequest);
final List<String> pathParameters = Splitter.on('/').splitToList(relativeUrl);
String command = null;
@@ -56,10 +52,7 @@ public class SavingsAccountTransactionCommandStrategy implements CommandStrategy
Long savingsAccountId = Long.parseLong(pathParameters.get(1));
final String responseBody = savingsAccountTransactionsApiResource.transaction(savingsAccountId, command, batchRequest.getBody());
response.setStatusCode(HttpStatus.SC_OK);
response.setBody(responseBody);
return response;
return new BatchResponse().setRequestId(batchRequest.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody)
.setHeaders(batchRequest.getHeaders());
}
}
@@ -126,7 +126,7 @@ public class DocumentManagementApiResource {
final DocumentCommand documentCommand = new DocumentCommand(null, null, entityType, entityId, name, fileDetails.getFileName(),
fileSize, bodyPart.getMediaType().toString(), description, null);
final Long documentId = this.documentWritePlatformService.createDocument(documentCommand, inputStream);
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(documentId, null));
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(documentId));
}
@PUT
@@ -201,7 +201,7 @@ public class ImagesApiResource {
public String deleteClientImage(@PathParam("entity") final String entityName, @PathParam("entityId") final Long entityId) {
validateEntityTypeforImage(entityName);
this.imageWritePlatformService.deleteImage(entityName, entityId);
return this.toApiJsonSerializer.serialize(new CommandProcessingResult(entityId));
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(entityId));
}
/*** Entities for document Management **/
@@ -133,7 +133,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
this.documentRepository.saveAndFlush(documentForUpdate);
return new CommandProcessingResult(documentForUpdate.getId());
return CommandProcessingResult.resourceResult(documentForUpdate.getId());
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
LOG.error("Error occured.", dve);
throw new PlatformDataIntegrityException("error.msg.document.unknown.data.integrity.issue",
@@ -158,7 +158,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(document.storageType());
contentRepository.deleteFile(document.getLocation());
return new CommandProcessingResult(document.getId());
return CommandProcessingResult.resourceResult(document.getId());
}
private void validateParentEntityType(final DocumentCommand documentCommand) {
@@ -103,7 +103,7 @@ public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePla
this.imageRepository.delete(image);
}
return new CommandProcessingResult(clientId);
return CommandProcessingResult.resourceResult(clientId);
}
/**
@@ -151,7 +151,7 @@ public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePla
}
this.imageRepository.save(image);
return new CommandProcessingResult(clientId);
return CommandProcessingResult.resourceResult(clientId);
}
private Image createImage(Image image, final String imageLocation, final StorageType storageType) {
@@ -164,7 +164,7 @@ public class ClientIdentifierWritePlatformServiceJpaRepositoryImpl implements Cl
.build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, throwable, dve);
@@ -138,7 +138,7 @@ public class CollateralWritePlatformServiceJpaRepositoryImpl implements Collater
.build();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
handleCollateralDataIntegrityViolation(dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.resourceResult(-1L);
}
}
@@ -40,6 +40,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.batch.exception.ErrorHandler;
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException;
import org.apache.fineract.cob.service.LoanAccountLockService;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
@@ -193,7 +194,6 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.transfer.api.TransferApiConstants;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -247,7 +247,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final ExternalIdFactory externalIdFactory;
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
private final LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService;
private final JdbcTemplate jdbcTemplate;
private final ErrorHandler errorHandler;
@Transactional
@Override
@@ -2426,13 +2426,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@SuppressWarnings("unused")
private void fallbackRecalculateInterest(Throwable t) {
// NOTE: allow caller to catch the exceptions
if (t instanceof RuntimeException re) {
throw re;
}
// NOTE: wrap throwable only if really necessary
throw new RuntimeException(t);
throw errorHandler.getMappable(t, null, null, "loan.recalculateinterest");
}
@Override
@@ -255,7 +255,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
} catch (final DataIntegrityViolationException | JpaSystemException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult((long) -1);
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
@@ -125,7 +125,7 @@ public class RateWriteServiceImpl implements RateWriteService {
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
handleRateDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult((long) -1);
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleRateDataIntegrityIssues(command, throwable, dve);
@@ -50,7 +50,6 @@ import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformS
import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
@@ -66,10 +65,8 @@ import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformS
import org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionSearchService;
import org.apache.fineract.portfolio.search.data.AdvancedQueryRequest;
import org.apache.fineract.portfolio.search.data.TransactionSearchRequest;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Component;
@Path("/v1/savingsaccounts/{savingsId}/transactions")
@@ -185,42 +182,33 @@ public class SavingsAccountTransactionsApiResource {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SavingsAccountTransactionsApiResourceSwagger.PostSavingsAccountTransactionsResponse.class))) })
public String transaction(@PathParam("savingsId") final Long savingsId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
try {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "deposit")) {
final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "gsimDeposit")) {
final CommandWrapper commandRequest = builder.gsimSavingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrawal")) {
final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "postInterestAsOn")) {
final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, SavingsApiConstants.COMMAND_HOLD_AMOUNT)) {
final CommandWrapper commandRequest = builder.holdAmount(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) {
//
throw new UnrecognizedQueryParamException("command", commandParam,
new Object[] { "deposit", "withdrawal", SavingsApiConstants.COMMAND_HOLD_AMOUNT });
}
return this.toApiJsonSerializer.serialize(result);
} catch (ObjectOptimisticLockingFailureException lockingFailureException) {
throw new PlatformDataIntegrityException("error.msg.savings.concurrent.operations",
"Concurrent Transactions being made on this savings account: " + lockingFailureException.getMessage(),
lockingFailureException);
} catch (CannotAcquireLockException cannotAcquireLockException) {
throw new PlatformDataIntegrityException("error.msg.savings.concurrent.operations.unable.to.acquire.lock",
"Unable to acquir lock for this transaction: " + cannotAcquireLockException.getMessage(), cannotAcquireLockException);
CommandProcessingResult result = null;
if (is(commandParam, "deposit")) {
final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "gsimDeposit")) {
final CommandWrapper commandRequest = builder.gsimSavingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrawal")) {
final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "postInterestAsOn")) {
final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, SavingsApiConstants.COMMAND_HOLD_AMOUNT)) {
final CommandWrapper commandRequest = builder.holdAmount(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) {
//
throw new UnrecognizedQueryParamException("command", commandParam,
new Object[] { "deposit", "withdrawal", SavingsApiConstants.COMMAND_HOLD_AMOUNT });
}
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -450,11 +450,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
} catch (final DataAccessException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult((long) -1);
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
return new CommandProcessingResult((long) -1);
return CommandProcessingResult.resourceResult(-1L);
}
}
@@ -521,11 +521,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
} catch (final DataAccessException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.resourceResult(-1L);
}
}
@@ -51,6 +51,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.batch.exception.ErrorHandler;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -165,6 +166,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final BusinessEventNotifierService businessEventNotifierService;
private final GSIMRepositoy gsimRepository;
private final SavingsAccountInterestPostingService savingsAccountInterestPostingService;
private final ErrorHandler errorHandler;
@Transactional
@Override
@@ -233,7 +235,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public void processPostActiveActions(final SavingsAccount account, final DateTimeFormatter fmt, final Set<Long> existingTransactionIds,
final Set<Long> existingReversedTransactionIds) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -264,7 +265,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult gsimDeposit(final Long gsimId, final JsonCommand command) {
Long parentSavingId = gsimId;
// GroupSavingsIndividualMonitoringparentSavings=gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepositoryWrapper.findByGsimId(gsimId);
@@ -276,7 +276,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
CommandProcessingResult result = null;
for (JsonElement element : savingsArray) {
result = deposit(element.getAsJsonObject().get("childAccountId").getAsLong(),
JsonCommand.fromExistingCommand(command, element));
}
@@ -286,7 +285,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult deposit(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
this.savingsAccountTransactionDataValidator.validate(command);
@@ -347,7 +345,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
.withSavingsId(savingsId) //
.with(changes) //
.build();
}
private Long saveTransactionToGenerateTransactionId(final SavingsAccountTransaction transaction) {
@@ -420,7 +417,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId) {
AppUser user = getAppUserIfPresent();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
@@ -445,7 +441,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult calculateInterest(final Long savingsId) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -480,7 +475,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
@Transactional
public CommandProcessingResult postInterest(final JsonCommand command) {
Long savingsId = command.getSavingsId();
final boolean postInterestAs = command.booleanPrimitiveValueOfParameterNamed("isPostInterestAsOn");
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
@@ -491,13 +485,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transactionDate, account);
if (postInterestAs == true) {
if (postInterestAs) {
if (transactionDate == null) {
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.VALID_DATE);
}
if (transactionDate.isBefore(account.accountSubmittedOrActivationDate())) {
if (DateUtils.isBefore(transactionDate, account.accountSubmittedOrActivationDate())) {
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.ACTIVATION_DATE);
}
@@ -509,16 +501,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
for (SavingsAccountTransaction savingTransaction : savingTransactions) {
if (transactionDate.isBefore(savingTransaction.getDateOf())) {
if (DateUtils.isBefore(transactionDate, savingTransaction.getDateOf())) {
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.LAST_TRANSACTION_DATE);
}
}
LocalDate today = DateUtils.getBusinessLocalDate();
if (transactionDate.isAfter(today)) {
if (DateUtils.isDateInTheFuture(transactionDate)) {
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.FUTURE_DATE);
}
}
postInterest(account, postInterestAs, transactionDate, backdatedTxnsAllowedTill);
@@ -536,7 +526,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public void postInterest(final SavingsAccount account, final boolean postInterestAs, final LocalDate transactionDate,
final boolean backdatedTxnsAllowedTill) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -757,7 +746,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -939,12 +927,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
List<SavingsAccountTransaction> savingTransactions = account.getTransactions();
for (SavingsAccountTransaction savingTransaction : savingTransactions) {
if (savingTransaction.isInterestPosting() && savingTransaction.isNotReversed()
&& closedDate.isEqual(savingTransaction.getTransactionLocalDate())) {
&& DateUtils.isEqual(closedDate, savingTransaction.getTransactionLocalDate())) {
postInterestOnClosingDate = true;
break;
}
}
if (postInterestOnClosingDate == false) {
if (!postInterestOnClosingDate) {
throw new PostInterestClosingDateException();
}
}
@@ -997,7 +985,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction initiateSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -1032,7 +1019,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -1072,7 +1058,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction acceptSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -1108,7 +1093,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult addSavingsAccountCharge(final JsonCommand command) {
this.context.authenticatedUser();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
@@ -1233,7 +1217,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -1325,7 +1308,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
AppUser user = getAppUserIfPresent();
this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
@@ -1393,7 +1375,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy").withZone(DateUtils.getDateTimeZoneOfTenant());
while (transactionDate.isAfter(savingsAccountCharge.getDueLocalDate()) && savingsAccountCharge.isNotFullyPaid()) {
while (savingsAccountCharge.isNotFullyPaid() && DateUtils.isBeforeBusinessDate(savingsAccountCharge.getDueLocalDate())) {
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, user, false);
}
}
@@ -1402,13 +1384,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private SavingsAccountData fallbackPostInterest(SavingsAccountData savingsAccountData, boolean postInterestAs,
LocalDate transactionDate, boolean backdatedTxnsAllowedTill, Throwable t) {
// NOTE: allow caller to catch the exceptions
if (t instanceof RuntimeException re) {
throw re;
}
// NOTE: wrap throwable only if really necessary
throw new RuntimeException(t);
throw errorHandler.getMappable(t, null, null, "savings.postinterest");
}
@Transactional
@@ -1817,7 +1794,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult releaseAmount(final Long savingsId, final Long savingsTransactionId) {
final AppUser submittedBy = this.context.authenticatedUser();
SavingsAccountTransaction holdTransaction = this.savingsAccountTransactionRepository
.findOneByIdAndSavingsAccountId(savingsTransactionId, savingsId);
@@ -1935,16 +1911,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
private void validateTransactionsForTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
for (SavingsAccountTransaction transaction : savingsAccount.getTransactions()) {
if ((transaction.getTransactionLocalDate().isEqual(transferDate) && transaction.getTransactionLocalDate().isAfter(transferDate))
|| transaction.getTransactionLocalDate().isAfter(transferDate)) {
if ((DateUtils.isEqual(transferDate, transaction.getTransactionLocalDate())
&& DateUtils.isEqual(transferDate, transaction.getSubmittedOnDate()))
|| DateUtils.isBefore(transferDate, transaction.getTransactionLocalDate())) {
throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientSavingsException,
TransferApiConstants.transferClientSavingsException, transaction.getCreatedDate(), transferDate);
}
}
}
private void validateReasonForHold(String reasonForBlock) {
@@ -397,7 +397,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
} catch (final DataAccessException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.resourceResult(-1L);
} catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
@@ -53,7 +53,7 @@ public class SelfServiceRegistrationApiResource {
@Produces({ MediaType.APPLICATION_JSON })
public String createSelfServiceUser(final String apiRequestBodyAsJson) {
AppUser user = this.selfServiceRegistrationWritePlatformService.createUser(apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(user.getId(), null));
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(user.getId()));
}
}
@@ -287,7 +287,7 @@ resilience4j.retry.instances.executeCommand.max-attempts=${FINERACT_COMMAND_PROC
resilience4j.retry.instances.executeCommand.wait-duration=${FINERACT_COMMAND_PROCESSING_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.executeCommand.enable-exponential-backoff=${FINERACT_COMMAND_PROCESSING_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.executeCommand.exponential-backoff-multiplier=${FINERACT_COMMAND_PROCESSING_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.executeCommand.retryExceptions=${FINERACT_COMMAND_PROCESSING_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException}
resilience4j.retry.instances.executeCommand.retryExceptions=${FINERACT_COMMAND_PROCESSING_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException,org.eclipse.persistence.exceptions.OptimisticLockException}
resilience4j.retry.instances.processJobDetailForExecution.max-attempts=${FINERACT_PROCESS_JOB_DETAIL_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.processJobDetailForExecution.wait-duration=${FINERACT_PROCESS_JOB_DETAIL_RETRY_WAIT_DURATION:1s}
@@ -298,10 +298,10 @@ resilience4j.retry.instances.recalculateInterest.max-attempts=${FINERACT_PROCESS
resilience4j.retry.instances.recalculateInterest.wait-duration=${FINERACT_PROCESS_RECALCULATE_INTEREST_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.recalculateInterest.enable-exponential-backoff=${FINERACT_PROCESS_RECALCULATE_INTEREST_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.recalculateInterest.exponential-backoff-multiplier=${FINERACT_PROCESS_RECALCULATE_INTEREST_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.recalculateInterest.retryExceptions=${FINERACT_PROCESS_RECALCULATE_INTEREST_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException}
resilience4j.retry.instances.recalculateInterest.retryExceptions=${FINERACT_PROCESS_RECALCULATE_INTEREST_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException,org.eclipse.persistence.exceptions.OptimisticLockException}
resilience4j.retry.instances.postInterest.max-attempts=${FINERACT_PROCESS_POST_INTEREST_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.postInterest.wait-duration=${FINERACT_PROCESS_POST_INTEREST_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.postInterest.enable-exponential-backoff=${FINERACT_PROCESS_POST_INTEREST_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.postInterest.exponential-backoff-multiplier=${FINERACT_PROCESS_POST_INTEREST_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.postInterest.retryExceptions=${FINERACT_PROCESS_POST_INTEREST_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException}
resilience4j.retry.instances.postInterest.retryExceptions=${FINERACT_PROCESS_POST_INTEREST_RETRY_EXCEPTIONS:org.springframework.dao.CannotAcquireLockException,org.springframework.orm.ObjectOptimisticLockingFailureException,org.eclipse.persistence.exceptions.OptimisticLockException}
@@ -20,6 +20,7 @@ package org.apache.fineract.commands.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import io.cucumber.java8.En;
import io.github.resilience4j.retry.RetryRegistry;
@@ -33,11 +34,14 @@ import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.test.util.ReflectionTestUtils;
public class CommandServiceStepDefinitions implements En {
@@ -55,16 +59,24 @@ public class CommandServiceStepDefinitions implements En {
private RetryEvent retryEvent;
private AtomicInteger counter = new AtomicInteger();
public CommandServiceStepDefinitions() {
Given("/^A command source write service$/", () -> {
this.commandSourceWritePlatformService = new DummyCommandSourceWriteService(processAndLogCommandService);
this.command = new DummyCommand();
FineractRequestContextHolder contextHolder = Mockito.spy(FineractRequestContextHolder.class);
ReflectionTestUtils.setField(processAndLogCommandService, "fineractRequestContextHolder", contextHolder);
Mockito.when(contextHolder.getAttribute(any(), any())).thenThrow(new CannotAcquireLockException("BLOW IT UP!!!"))
.thenThrow(new ObjectOptimisticLockingFailureException("Dummy", new RuntimeException("BLOW IT UP!!!")))
.thenThrow(new RollbackTransactionAsCommandIsNotApprovedByCheckerException(new DummyCommandSource()));
this.retryRegistry.retry("executeCommand").getEventPublisher().onRetry(event -> {
log.warn("... retry event: {}", event);
counter.incrementAndGet();
CommandServiceStepDefinitions.this.retryEvent = event;
});
});
When("/^The user executes the command via a command write service with exceptions$/", () -> {
@@ -84,47 +96,21 @@ public class CommandServiceStepDefinitions implements En {
});
Then("/^The command processing service execute function should be called 3 times$/", () -> {
assertEquals(3, command.getCount());
assertEquals(2, counter.get());
});
}
public static class DummyCommand extends CommandWrapper {
private AtomicInteger counter = new AtomicInteger();
public DummyCommand() {
super(null, null, null, null, null, null, null, null, null, null, "{}", null, null, null, null, null, null,
UUID.randomUUID().toString());
}
@Override
public String taskPermissionName() {
// NOTE: simulating a failure scenario that triggers retries; using this function, because it is the first
// called in the command processing service
int step = counter.incrementAndGet();
log.warn("Round: {}", step);
if (step == 1) {
throw new CannotAcquireLockException("BLOW IT UP!!!");
} else if (step == 2) {
throw new ObjectOptimisticLockingFailureException("Dummy", new RuntimeException("BLOW IT UP!!!"));
} else if (step == 3) {
throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(new DummyCommandSource());
}
return "dummy";
}
@Override
public String actionName() {
return "dummy";
}
public int getCount() {
return counter.get();
}
}
public static class DummyCommandSourceWriteService implements PortfolioCommandSourceWritePlatformService {
@@ -74,7 +74,7 @@ public class CommandSourceServiceTest {
ThreadLocalContextUtil.setTenant(ft);
String idk = "idk";
underTest.saveInitial(wrapper, jsonCommand, appUser, idk);
underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, idk);
ArgumentCaptor<CommandSource> commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class);
Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture());
@@ -97,7 +97,7 @@ public class CommandSourceServiceTest {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "t1", "n1", ZoneId.systemDefault().toString(), null));
CommandSource actual = underTest.saveInitial(wrapper, jsonCommand, appUser, "idk");
CommandSource actual = underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, "idk");
ArgumentCaptor<CommandSource> commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class);
Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture());
@@ -108,9 +108,10 @@ public class CommandSourceServiceTest {
@Test
public void testGenerateErrorException() {
Mockito.when(errorHandler.getMappable(any())).thenAnswer(i -> i.getArguments()[0]);
Mockito.when(errorHandler.handle(any(CodeNotFoundException.class)))
.thenReturn(new ErrorInfo(404, 1001, "Code with name `foo` does not exist"));
ErrorInfo result = underTest.generateErrorException(new CodeNotFoundException("foo"));
.thenReturn(new ErrorInfo(404, 1001, "Code with name `foo` does not exist", null));
ErrorInfo result = underTest.generateErrorInfo(new CodeNotFoundException("foo"));
Assertions.assertEquals(404, result.getStatusCode());
Assertions.assertEquals(1001, result.getErrorCode());
Assertions.assertTrue(result.getMessage().contains("Code with name `foo` does not exist"));
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.commands.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -85,7 +86,6 @@ public class SynchronousCommandProcessingServiceTest {
@Test
public void testExecuteCommandSuccess() {
CommandWrapper commandWrapper = Mockito.mock(CommandWrapper.class);
when(commandWrapper.isDatatableResource()).thenReturn(false);
when(commandWrapper.isNoteResource()).thenReturn(false);
@@ -103,19 +103,24 @@ public class SynchronousCommandProcessingServiceTest {
String idk = "idk";
when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk);
CommandSource commandSource = Mockito.mock(CommandSource.class);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null).thenReturn(commandSource);
long commandId = 1L;
when(commandSource.getId()).thenReturn(commandId);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null);
when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource);
AppUser appUser = Mockito.mock(AppUser.class);
when(commandSourceService.saveInitial(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveResultSameTransaction(commandSource)).thenReturn(commandSource);
when(commandSource.getStatus()).thenReturn(CommandProcessingResultType.PROCESSED.getValue());
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
CommandProcessingResult actualCommandProcessingResult = underTest.executeCommand(commandWrapper, jsonCommand, false);
verify(commandSourceService).saveInitial(commandWrapper, jsonCommand, appUser, idk);
verify(commandSource).setStatus(CommandProcessingResultType.PROCESSED.getValue());
verify(commandSourceService).saveResult(commandSource);
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
assertEquals(CommandProcessingResultType.PROCESSED.getValue(), commandSource.getStatus());
verify(commandSourceService).saveResultSameTransaction(commandSource);
Assertions.assertEquals(commandProcessingResult, actualCommandProcessingResult);
assertEquals(commandProcessingResult, actualCommandProcessingResult);
}
@Test
@@ -142,7 +147,7 @@ public class SynchronousCommandProcessingServiceTest {
AppUser appUser = Mockito.mock(AppUser.class);
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
when(commandSourceService.saveInitial(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
CommandSource initialCommandSource = Mockito.mock(CommandSource.class);
@@ -152,7 +157,7 @@ public class SynchronousCommandProcessingServiceTest {
underTest.executeCommand(commandWrapper, jsonCommand, false);
});
verify(commandSourceService).saveInitial(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).generateErrorException(runtimeException);
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).generateErrorInfo(runtimeException);
}
}
@@ -47,7 +47,7 @@ public class InvalidInstanceTypeMethodExceptionMapperTest {
assertEquals(Response.Status.METHOD_NOT_ALLOWED.getStatusCode(), response.getStatus());
assertNotNull(response.getEntity());
final ApiGlobalErrorResponse errorResponse = (ApiGlobalErrorResponse) response.getEntity();
assertEquals(String.valueOf(Response.Status.METHOD_NOT_ALLOWED.getReasonPhrase()), errorResponse.getHttpStatusCode());
assertEquals(String.valueOf(Response.Status.METHOD_NOT_ALLOWED.getStatusCode()), errorResponse.getHttpStatusCode());
assertEquals("Invalid instance type called in api request for the method POST", errorResponse.getDeveloperMessage());
assertEquals("error.msg.invalid.instance.type", errorResponse.getUserMessageGlobalisationCode());
assertEquals("Invalid method POST used with request to this instance type.", errorResponse.getDefaultUserMessage());