Skip to content

Commit

Permalink
Prdp 359 feat add disable tx api (#39)
Browse files Browse the repository at this point in the history
* [PRDP-358] Added entities' models and moved classes

* [PRDP-358] Added collections repo interfaces and container name envs

* [PRDP-356] updated openapi definition as defined in documentation

* [PRDP-358] Added get biz-events-view-cart filtered by fiscal code

* [PRDP-358] Reworked transaction service getTransactionDetails and added errors

* [PRDP-358] Updated partially tests

* [PRDP-358] Completed unit test for transaction details

* [PRDP-358] Changed entity annotation

* [PRDP-358] Added id autogeneration to view entities

* [PRDP-359] feat: introduced transaction disable api

* [PRDP-359] feat: merged changes from main

---------

Co-authored-by: svariant <samuele.varianti@nttdata.com>
Co-authored-by: giomella <gioele.mella@emeal.nttdata.com>
  • Loading branch information
3 people authored Feb 1, 2024
1 parent b644418 commit d20cb5d
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Tag(name = "IO Transactions REST APIs")
Expand Down Expand Up @@ -73,6 +68,22 @@ ResponseEntity<List<TransactionListItem>> getTransactionList(
@ApiResponse(responseCode = "500", description = "Service unavailable.", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class)))})
@GetMapping(value = "/{transaction-id}", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<TransactionDetailResponse> getTransactionDetails(
@RequestHeader(X_FISCAL_CODE) @NotBlank String fiscalCode,
@RequestHeader("x-fiscal-code") @NotBlank String fiscalCode,
@Parameter(description = "The id of the transaction.", required = true) @NotBlank @PathVariable("transaction-id") String transactionId);

@Operation(summary = "Disable the transaction details given its id.", security = {
@SecurityRequirement(name = "ApiKey")}, operationId = "disableTransaction")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Disabled Transactions.",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)),
@ApiResponse(responseCode = "401", description = "Wrong or missing function key.", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "404", description = "Not found the transaction.", content = @Content(schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "422", description = "Unable to process the request.", content = @Content(schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "429", description = "Too many requests.", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "500", description = "Service unavailable.", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class)))})
@PostMapping(value = "/{transaction-id}/disable", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity disableTransaction(
@RequestHeader("x-fiscal-code") @NotBlank String fiscalCode,
@Parameter(description = "The id of the transaction.", required = true) @NotBlank @PathVariable("transaction-id") String transactionId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ public ResponseEntity<TransactionDetailResponse> getTransactionDetails(String fi
transactionService.getTransactionDetails(fiscalCode, eventReference),
HttpStatus.OK);
}

@Override
public ResponseEntity<Void> disableTransaction(String fiscalCode, String transactionId) {
transactionService.disableTransaction(fiscalCode, transactionId);
return new ResponseEntity<>(HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public enum AppError {
VIEW_GENERAL_NOT_FOUND_WITH_TRANSACTION_ID(HttpStatus.NOT_FOUND, VIEW_GENERAL_NOT_FOUND, "Not found a biz-events-view-general with id %s"),
VIEW_CART_NOT_FOUND_WITH_TRANSACTION_ID_AND_TAX_CODE(HttpStatus.NOT_FOUND, VIEW_CART_NOT_FOUND, "Not found a biz-events-view-cart with id %s for the given tax code"),

VIEW_USER_NOT_FOUND_WITH_TRANSACTION_ID(HttpStatus.NOT_FOUND, VIEW_USER_NOT_FOUND, "Not found a biz-events-view-user with id %s"),

VIEW_CART_NOT_FOUND_WITH_TRANSACTION_ID_FOR_USER(HttpStatus.NOT_FOUND, VIEW_CART_NOT_FOUND, "Not found a biz-events-view-cart with id %s for the given fiscal code"),

ERROR_MAPPING_BIZ_EVENT_TO_TRANSACTION_DETAIL(HttpStatus.INTERNAL_SERVER_ERROR, INVALID_DATA, "Error mapping bizEvent data to transaction details, missing property %s for bizEvent with id %s"),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Internal Server Error", "Something was wrong");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
public interface BizEventsViewUserRepository extends CosmosRepository<BizEventsViewUser, String> {
@Query("select * from c where c.taxCode = @taxCode")
Page<BizEventsViewUser> getBizEventsViewUserByTaxCode(@Param("taxCode") String taxCode, Pageable pageable);

@Query("select * from c where c.transactionId=@transactionId c.taxCode = @fiscalCode")
BizEventsViewUser getBizEventsViewUserByTaxCodeAndTransactionId(String fiscalCode, String transactionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionDetailResponse;
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionListResponse;


import java.util.List;

public interface ITransactionService {

/**
Expand All @@ -18,4 +15,5 @@ public interface ITransactionService {
TransactionListResponse getTransactionList(String fiscalCode, String continuationToken, Integer size);
TransactionDetailResponse getTransactionDetails(String fiscalCode, String transactionId);

void disableTransaction(String fiscalCode, String transactionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewCartRepository;
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewGeneralRepository;
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewUserRepository;
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewGeneralRepository;
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewCartRepository;
import it.gov.pagopa.bizeventsservice.repository.BizEventsViewUserRepository;
import it.gov.pagopa.bizeventsservice.service.ITransactionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -97,6 +100,22 @@ public TransactionDetailResponse getTransactionDetails(String taxCode, String ev
return ConvertViewsToTransactionDetailResponse.convertTransactionDetails(bizEventsViewGeneral.get(), listOfCartViews);
}

@Override
public void disableTransaction(String fiscalCode, String transactionId) {
if(isInvalidFiscalCode(fiscalCode)){
throw new AppException(AppError.INVALID_FISCAL_CODE, fiscalCode);
}

BizEventsViewUser bizEventsViewUser = this.bizEventsViewUserRepository
.getBizEventsViewUserByTaxCodeAndTransactionId(fiscalCode, transactionId);
if (bizEventsViewUser == null) {
throw new AppException(AppError.VIEW_GENERAL_NOT_FOUND_WITH_TRANSACTION_ID);
}

bizEventsViewUser.setHidden(true);
bizEventsViewUserRepository.save(bizEventsViewUser);
}

private boolean isInvalidFiscalCode(String fiscalCode) {
if (fiscalCode != null && !fiscalCode.isEmpty()) {
Pattern pattern = Pattern.compile("^[A-Z]{6}[0-9LMNPQRSTUV]{2}[ABCDEHLMPRST][0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{3}[A-Z]$");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

Expand All @@ -43,6 +44,8 @@ public class TransactionControllerTest {
public static final String CONTINUATION_TOKEN = "continuationToken";
public static final String SIZE_HEADER_KEY = "size";
public static final String SIZE = "10";
public static final String TRANSACTION_DISABLE_PATH = "/transactions/transaction-id/disable";

@Autowired
private MockMvc mvc;

Expand Down Expand Up @@ -126,5 +129,34 @@ void getTransactionDetailsWithInvalidFiscalCodeShouldReturnError() throws Except
.andReturn();
}

@Test
void getTransactionDisableShouldReturnOK() throws Exception {
mvc.perform(post(TRANSACTION_DISABLE_PATH)
.header(FISCAL_CODE_HEADER_KEY, VALID_FISCAL_CODE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
verify(transactionService).disableTransaction(any(), any());
}

@Test
void getTransactionDisableWithMissingFiscalCodeShouldReturnError() throws Exception {
mvc.perform(post(TRANSACTION_DISABLE_PATH)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andReturn();
}

@Test
void getTransactionDisableithInvalidFiscalCodeShouldReturnError() throws Exception {
doAnswer(x -> {
throw new AppException(AppError.INVALID_FISCAL_CODE, INVALID_FISCAL_CODE);
}).when(transactionService).disableTransaction(anyString(), anyString());;
mvc.perform(post(TRANSACTION_DISABLE_PATH)
.header(FISCAL_CODE_HEADER_KEY, INVALID_FISCAL_CODE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andReturn();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.util.*;

import static it.gov.pagopa.bizeventsservice.util.ViewGenerator.generateBizEventsViewUser;
import static org.mockito.Mockito.*;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
Expand Down Expand Up @@ -248,4 +249,35 @@ void transactionViewCartNotFoundThrowError() {

Assertions.assertEquals(HttpStatus.NOT_FOUND, appException.getHttpStatus());
}
@Test
public void transactionViewUserDisabled() {
BizEventsViewUser viewUser = generateBizEventsViewUser();
when(bizEventsViewUserRepository.getBizEventsViewUserByTaxCodeAndTransactionId(anyString(),anyString()))
.thenReturn(viewUser);
Assertions.assertDoesNotThrow(() -> transactionService.disableTransaction(
ViewGenerator.USER_TAX_CODE_WITH_TX, ViewGenerator.TRANSACTION_ID));
viewUser.setHidden(true);
verify(bizEventsViewUserRepository).save(viewUser);
}

@Test
public void transactionViewUserNotFoundThrowError() {
when(bizEventsViewUserRepository.getBizEventsViewUserByTaxCodeAndTransactionId(anyString(),anyString()))
.thenReturn(null);
AppException appException =
Assertions.assertThrows(AppException.class, () ->
transactionService.getTransactionDetails(
ViewGenerator.USER_TAX_CODE_WITH_TX, ViewGenerator.TRANSACTION_ID));
Assertions.assertEquals(HttpStatus.NOT_FOUND, appException.getHttpStatus());
}

@Test
void transactionUserViewThrowErrorForInvalidFiscalCode() {
AppException appException =
Assertions.assertThrows(AppException.class,() ->
transactionService.disableTransaction(
INVALID_FISCAL_CODE, ViewGenerator.TRANSACTION_ID));
verifyNoInteractions(bizEventsViewUserRepository);
Assertions.assertEquals(HttpStatus.BAD_REQUEST, appException.getHttpStatus());
}
}

0 comments on commit d20cb5d

Please sign in to comment.