Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PAGOPA-1996] Paid Notice List: new path #87

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,781 changes: 1,895 additions & 1,886 deletions openapi/openapi.json

Large diffs are not rendered by default.

1,081 changes: 509 additions & 572 deletions openapi/openapi_ec.json

Large diffs are not rendered by default.

1,438 changes: 699 additions & 739 deletions openapi/openapi_helpdesk.json

Large diffs are not rendered by default.

1,379 changes: 651 additions & 728 deletions openapi/openapi_io.json

Large diffs are not rendered by default.

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

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.headers.Header;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -21,14 +22,24 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import it.gov.pagopa.bizeventsservice.model.ProblemJson;
import it.gov.pagopa.bizeventsservice.model.response.paidnotice.NoticeDetailResponse;
import it.gov.pagopa.bizeventsservice.model.filterandorder.Order;
import it.gov.pagopa.bizeventsservice.model.response.paidnotice.NoticeListWrapResponse;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;


@Tag(name = "Paid Notice REST APIs")
@RequestMapping("/paids")
@Validated
public interface IPaidNoticeController {
String X_FISCAL_CODE = "x-fiscal-code";

/**
* @param fiscalCode
* @param eventId
Expand All @@ -47,6 +58,39 @@ public interface IPaidNoticeController {
ResponseEntity<NoticeDetailResponse> getPaidNoticeDetail(
@RequestHeader("x-fiscal-code") @NotBlank String fiscalCode,
@Parameter(description = "The id of the paid event.", required = true) @NotBlank @PathVariable("event-id") String eventId);
String X_CONTINUATION_TOKEN = "x-continuation-token";
String PAGE_SIZE = "size";

/**
* recovers biz-event data for the paid notices list
*
* @param fiscalCode tokenized user fiscal code
* @param continuationToken continuation token for paginated query
* @param size optional parameter defining page size, defaults to 10
* @return the paid notices list
*/
@GetMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Obtained paid notices list.",
headers = @Header(name = X_CONTINUATION_TOKEN, description = "continuation token for paginated query", schema = @Schema(type = "string")),
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = NoticeListWrapResponse.class))),
@ApiResponse(responseCode = "401", description = "Wrong or missing function key.", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "404", description = "Not found the fiscal code.", 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)))})
@Operation(summary = "Retrieve the paged transaction list from biz events.", description = "This operation is deprecated. Use Paid Notice APIs instead", security = {
@SecurityRequirement(name = "ApiKey")})
ResponseEntity<NoticeListWrapResponse> getPaidNotices(
@RequestHeader(name = X_FISCAL_CODE) String fiscalCode,
@RequestHeader(name = X_CONTINUATION_TOKEN, required = false) String continuationToken,
@RequestParam(name = PAGE_SIZE, required = false, defaultValue = "10") Integer size,
@Valid @Parameter(description = "Filter by payer") @RequestParam(value = "is_payer", required = false) Boolean isPayer,
@Valid @Parameter(description = "Filter by debtor") @RequestParam(value = "is_debtor", required = false) Boolean isDebtor,
@RequestParam(required = false, name = "orderby", defaultValue = "TRANSACTION_DATE") @Parameter(description = "Order by TRANSACTION_DATE") Order.TransactionListOrder orderBy,
@RequestParam(required = false, name = "ordering", defaultValue = "DESC") @Parameter(description = "Direction of ordering") Sort.Direction ordering);




@Operation(summary = "Disable the paid notice details given its id.", security = {
@SecurityRequirement(name = "ApiKey")}, operationId = "disablePaidNotice")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public interface ITransactionController {
String PAGE_NUMBER = "page";

/**
* @deprecated
* recovers biz-event data for the transaction list
*
* @param fiscalCode tokenized user fiscal code
Expand All @@ -60,8 +61,9 @@ public interface ITransactionController {
@ApiResponse(responseCode = "404", description = "Not found the transaction.", 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)))})
@Operation(summary = "Retrieve the paged transaction list from biz events.", security = {
@SecurityRequirement(name = "ApiKey")}, operationId = "getTransactionList")
@Operation(summary = "Retrieve the paged transaction list from biz events.", description = "This operation is deprecated. Use Paid Notice APIs instead", security = {
@SecurityRequirement(name = "ApiKey")}, deprecated = true, operationId = "getTransactionList")
@Deprecated(forRemoval = false)
ResponseEntity<TransactionListWrapResponse> getTransactionList(
@RequestHeader(name = X_FISCAL_CODE) String fiscalCode,
@Valid @Parameter(description = "Filter by payer") @RequestParam(value = "is_payer", required = false) Boolean isPayer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package it.gov.pagopa.bizeventsservice.controller.impl;

import it.gov.pagopa.bizeventsservice.controller.IPaidNoticeController;
import it.gov.pagopa.bizeventsservice.model.filterandorder.Order;
import it.gov.pagopa.bizeventsservice.model.response.paidnotice.NoticeDetailResponse;
import it.gov.pagopa.bizeventsservice.model.response.paidnotice.NoticeListWrapResponse;
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionListResponse;
import it.gov.pagopa.bizeventsservice.service.ITransactionService;

import javax.validation.constraints.NotBlank;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;

import static it.gov.pagopa.bizeventsservice.mapper.ConvertViewsToTransactionDetailResponse.convertToNoticeList;

/**
* Implementation of {@link IPaidNoticeController} that contains the Rest Controller
* for events services
Expand All @@ -33,6 +38,23 @@ public ResponseEntity<NoticeDetailResponse> getPaidNoticeDetail(@NotBlank String
HttpStatus.OK);
}

@Override
public ResponseEntity<NoticeListWrapResponse> getPaidNotices(String fiscalCode,
String continuationToken,
Integer size,
Boolean isPayer,
Boolean isDebtor,
Order.TransactionListOrder orderBy,
Sort.Direction ordering) {
TransactionListResponse transactionListResponse = transactionService.getTransactionList(fiscalCode, isPayer, isDebtor,
continuationToken, size, orderBy, ordering);


return ResponseEntity.ok()
.header(X_CONTINUATION_TOKEN, transactionListResponse.getContinuationToken())
.body(NoticeListWrapResponse.builder().notices(convertToNoticeList(transactionListResponse)).build());
}

@Override
public ResponseEntity<Void> disablePaidNotice(String fiscalCode, String transactionId) {
transactionService.disableTransaction(fiscalCode, transactionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import it.gov.pagopa.bizeventsservice.entity.view.BizEventsViewCart;
import it.gov.pagopa.bizeventsservice.entity.view.BizEventsViewGeneral;
import it.gov.pagopa.bizeventsservice.entity.view.BizEventsViewUser;
import it.gov.pagopa.bizeventsservice.model.response.paidnotice.NoticeListItem;
import it.gov.pagopa.bizeventsservice.model.response.transaction.CartItem;
import it.gov.pagopa.bizeventsservice.model.response.transaction.InfoTransactionView;
import it.gov.pagopa.bizeventsservice.util.DateValidator;
Expand Down Expand Up @@ -123,6 +124,22 @@ public static NoticeDetailResponse convertPaidNoticeDetails(String taxCode, BizE
.build();
}

public static List<NoticeListItem> convertToNoticeList(TransactionListResponse transactionListResponse) {
return transactionListResponse.getTransactionList().stream()
.map(elem -> NoticeListItem.builder()
.eventId(elem.getTransactionId())
.payeeName(elem.getPayeeName())
.payeeTaxCode(elem.getPayeeTaxCode())
.amount(elem.getAmount())
.noticeDate(elem.getTransactionDate())
.isCart(elem.getIsCart())
.isPayer(elem.getIsPayer())
.isDebtor(elem.getIsDebtor())
.build())
.toList();
}


public static TransactionListItem convertTransactionListItem(BizEventsViewUser viewUser, List<BizEventsViewCart> listOfCartViews){
AtomicReference<BigDecimal> totalAmount = new AtomicReference<>(BigDecimal.ZERO);
for (BizEventsViewCart bizEventsViewCart : listOfCartViews) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package it.gov.pagopa.bizeventsservice.model.response.paidnotice;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;

import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
* Response model for transaction list API
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonInclude(Include.NON_NULL)
public class NoticeListItem implements Serializable {

@Schema(required = true)
@NotNull
private String eventId;

private String payeeName;

@Schema(required = true)
@NotNull
private String payeeTaxCode;

@Schema(required = true)
@NotNull
private String amount;

@Schema(required = true)
@NotNull
private String noticeDate;

@Schema(required = true)
@NotNull
private Boolean isCart;

@Schema(required = true)
@NotNull
private Boolean isPayer;

@Schema(required = true)
@NotNull
@Builder.Default
private Boolean isDebtor = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package it.gov.pagopa.bizeventsservice.model.response.paidnotice;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.util.List;

@Builder
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class NoticeListWrapResponse {

@Schema(required = true)
@NotNull
private List<NoticeListItem> notices;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@
import java.io.IOException;
import java.util.List;

import com.fasterxml.jackson.core.type.TypeReference;
import it.gov.pagopa.bizeventsservice.client.IReceiptGeneratePDFClient;
import it.gov.pagopa.bizeventsservice.client.IReceiptGetPDFClient;
import it.gov.pagopa.bizeventsservice.exception.AppError;
import it.gov.pagopa.bizeventsservice.exception.AppException;
import it.gov.pagopa.bizeventsservice.model.response.Attachment;
import it.gov.pagopa.bizeventsservice.model.response.AttachmentsDetailsResponse;
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionDetailResponse;
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionListItem;
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionListResponse;
import it.gov.pagopa.bizeventsservice.service.ITransactionService;
import it.gov.pagopa.bizeventsservice.util.Utility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -35,6 +47,18 @@
import it.gov.pagopa.bizeventsservice.model.response.transaction.TransactionListResponse;
import it.gov.pagopa.bizeventsservice.service.ITransactionService;
import it.gov.pagopa.bizeventsservice.util.Utility;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

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.*;
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;

@SpringBootTest
@AutoConfigureMockMvc
Expand All @@ -45,10 +69,22 @@ public class PaidNoticeControllerTest {
public static final String FISCAL_CODE_HEADER_KEY = "x-fiscal-code";
public static final String PAIDS_EVENT_ID_DISABLE_PATH = "/paids/1234321234/disable";
public static final String PAIDS_EVENT_DETAILS_PATH = "/paids/event-id";
public static final String PAIDS_PATH = "/paids";
public static final String SIZE = "10";
public static final String SIZE_HEADER_KEY = "size";
private static final String CONTINUATION_TOKEN_HEADER_KEY = "x-continuation-token";
public static final String CONTINUATION_TOKEN = "continuationToken";


@Autowired
private MockMvc mvc;

@MockBean
private IReceiptGetPDFClient receiptClient;

@MockBean
private IReceiptGeneratePDFClient generateReceiptClient;

@MockBean
private ITransactionService transactionService;

Expand All @@ -58,12 +94,52 @@ public class PaidNoticeControllerTest {
@BeforeEach
void setUp() throws IOException {
// precondition
List<TransactionListItem> transactionListItems = Utility.readModelFromFile("biz-events/getTransactionList.json", List.class);
List<TransactionListItem> transactionListItems = Utility.readModelFromFile("biz-events/getTransactionList.json", new TypeReference<List<TransactionListItem>>(){});
TransactionListResponse transactionListResponse = TransactionListResponse.builder().transactionList(transactionListItems).build();
NoticeDetailResponse noticeDetailResponse = Utility.readModelFromFile("biz-events/paidNoticeDetails.json", NoticeDetailResponse.class);
when(transactionService.getTransactionList(eq(VALID_FISCAL_CODE), any(), any(), anyString(), anyInt(), any(), any())).thenReturn(transactionListResponse);
when(transactionService.getPaidNoticeDetail(anyString(), anyString())).thenReturn(noticeDetailResponse);
when(transactionService.getPDFReceipt(anyString(), anyString())).thenReturn(receipt);
Attachment attachmentDetail = mock (Attachment.class);
AttachmentsDetailsResponse attachments = AttachmentsDetailsResponse.builder().attachments(Arrays.asList(attachmentDetail)).build();
when(receiptClient.getAttachments(anyString(), anyString())).thenReturn(attachments);
when(receiptClient.getReceipt(anyString(), anyString(), any())).thenReturn(receipt);
when(generateReceiptClient.generateReceipt(anyString(), anyString(), any())).thenReturn("OK");
}

@Test
void getPaidNoticesListShouldReturnData() throws Exception {
MvcResult result = mvc.perform(get(PAIDS_PATH)
.header(FISCAL_CODE_HEADER_KEY, VALID_FISCAL_CODE)
.header(CONTINUATION_TOKEN_HEADER_KEY, CONTINUATION_TOKEN)
.queryParam(SIZE_HEADER_KEY, SIZE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
assertNotNull(result.getResponse().getContentAsString());
assertTrue(result.getResponse().getContentAsString().contains("b77d4987-a3e4-48d4-a2fd-af504f8b79e9"));
assertTrue(result.getResponse().getContentAsString().contains("100.0"));
}

@Test
void getPaidNoticesListWithMissingFiscalCodeShouldReturnError() throws Exception {
mvc.perform(get(PAIDS_PATH)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andReturn();
}

@Test
void getPaidNoticesListWithInvalidFiscalCodeShouldReturnError() throws Exception {
when(transactionService.getTransactionList(eq(INVALID_FISCAL_CODE), any(), any(), any(), anyInt(), any(), any())).thenAnswer(x -> {
throw new AppException(AppError.INVALID_FISCAL_CODE, INVALID_FISCAL_CODE);
});
mvc.perform(get(PAIDS_PATH)
.header(FISCAL_CODE_HEADER_KEY, INVALID_FISCAL_CODE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andReturn();
}

@Test
Expand Down Expand Up @@ -95,7 +171,7 @@ void getPaidNoticeDisableWithInvalidFiscalCodeShouldReturnError() throws Excepti
.andExpect(status().isBadRequest())
.andReturn();
}

@Test
void getPaidNoticeDetailShouldReturnData() throws Exception {
MvcResult result = mvc.perform(get(PAIDS_EVENT_DETAILS_PATH)
Expand Down
Loading
Loading