diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml index 9eb43ee3..c02bb0e6 100644 --- a/helm/values-dev.yaml +++ b/helm/values-dev.yaml @@ -111,11 +111,14 @@ microservice-chart: OTEL_TRACES_SAMPLER: "always_on" MAX_DATE_DIFF_MILLIS: "1800000" # 30min MAX_DATE_DIFF_NOTIFY_MILLIS: "1800000" # 30nin + MAX_DATE_DIFF_CART_MILLIS: "1800000" # 30nin TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */2 * * *" RECOVER_FAILED_CRON: "0 0 */2 * * *" + RECOVER_FAILED_CART_CRON: "0 0 */2 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" FAILED_AUTORECOVER_ENABLED: "true" NOT_NOTIFIED_AUTORECOVER_ENABLED: "true" + FAILED_CART_AUTORECOVER_ENABLED: "true" RECOVER_FAILED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_RECORDS: "200" diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml index cfbde027..f7635b96 100644 --- a/helm/values-prod.yaml +++ b/helm/values-prod.yaml @@ -111,11 +111,14 @@ microservice-chart: OTEL_TRACES_SAMPLER: "always_on" MAX_DATE_DIFF_MILLIS: "1800000" # 30min MAX_DATE_DIFF_NOTIFY_MILLIS: "1800000" # 30nin + MAX_DATE_DIFF_CART_MILLIS: "1800000" # 30nin TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */1 * * *" RECOVER_FAILED_CRON: "0 0 */1 * * *" + RECOVER_FAILED_CART_CRON: "0 0 */1 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" FAILED_AUTORECOVER_ENABLED: "true" NOT_NOTIFIED_AUTORECOVER_ENABLED: "true" + FAILED_CART_AUTORECOVER_ENABLED: "false" RECOVER_FAILED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_RECORDS: "200" diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml index 89b42de0..b524cd23 100644 --- a/helm/values-uat.yaml +++ b/helm/values-uat.yaml @@ -111,11 +111,14 @@ microservice-chart: OTEL_TRACES_SAMPLER: "always_on" MAX_DATE_DIFF_MILLIS: "1800000" # 30min MAX_DATE_DIFF_NOTIFY_MILLIS: "1800000" # 30nin + MAX_DATE_DIFF_CART_MILLIS: "1800000" # 30nin TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */1 * * *" RECOVER_FAILED_CRON: "0 0 */1 * * *" + RECOVER_FAILED_CART_CRON: "0 0 */1 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" FAILED_AUTORECOVER_ENABLED: "true" NOT_NOTIFIED_AUTORECOVER_ENABLED: "true" + FAILED_CART_AUTORECOVER_ENABLED: "false" RECOVER_FAILED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_DAYS: "0" RECOVER_NOT_NOTIFIED_MASSIVE_MAX_RECORDS: "200" diff --git a/openapi/openapi.json b/openapi/openapi.json index 43afe56b..3344f411 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -535,6 +535,15 @@ "type": "string" }, "required": true + }, + { + "in": "query", + "name": "isCart", + "description": "Boolean to determine if the id refers to a cart", + "schema": { + "type": "string" + }, + "required": false } ], "responses": { @@ -886,6 +895,241 @@ } ] }, + "/carts/{cart-id}/recover-failed": { + "post": { + "tags": [ + "API-recoverFailedCart" + ], + "summary": "Recover a cart in FAILED or INSERTED status", + "operationId": "RecoverFailedCart", + "parameters": [ + { + "in": "path", + "name": "cart-id", + "description": "Cart id.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": {} + }, + "required": false + }, + "responses": { + "200": { + "description": "Successful Calls.", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "Receipt with eventId 76abb1f1-c9f9-4ead-9e66-12fec4d51042 recovered" + } + } + } + }, + "400": { + "description": "Bad request.", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "404": { + "description": "Receipt or BizEvent not found", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "500": { + "description": "Error processing the request", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "default": { + "description": "Unexpected error.", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "ApiKey": [] + } + ] + }, + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "schema": { + "type": "string" + } + } + ] + }, + "/carts/recover-failed": { + "post": { + "tags": [ + "API-recoverCartFailed" + ], + "summary": "Recover a group of cart in FAILED, or INSERTED status", + "operationId": "RecoverFailedCartMassive", + "parameters": [ + { + "in": "query", + "name": "status", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": {} + }, + "required": false + }, + "responses": { + "200": { + "description": "Successful Calls.", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "Recovered 10 carts" + } + } + } + }, + "400": { + "description": "Bad request", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "500": { + "description": "Error processing the request", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "default": { + "description": "Unexpected error.", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "ApiKey": [] + } + ] + }, + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "schema": { + "type": "string" + } + } + ] + }, "/receipts/{event-id}/recover-failed": { "post": { "tags": [ @@ -902,6 +1146,15 @@ "type": "string" }, "required": true + }, + { + "in": "query", + "name": "isCart", + "description": "Boolean to determine if the id refers to a cart", + "schema": { + "type": "string" + }, + "required": false } ], "requestBody": { @@ -1137,6 +1390,15 @@ "type": "string" }, "required": true + }, + { + "in": "query", + "name": "isCart", + "description": "Boolean to determine if the id refers to a cart", + "schema": { + "type": "string" + }, + "required": false } ], "requestBody": { @@ -1372,6 +1634,15 @@ "type": "string" }, "required": true + }, + { + "in": "query", + "name": "isCart", + "description": "Boolean to determine if the id refers to a cart", + "schema": { + "type": "string" + }, + "required": false } ], "requestBody": { diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewed.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewed.java index 6280ac54..0be97d64 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewed.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewed.java @@ -6,6 +6,7 @@ import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReceiptError; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptErrorStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; import org.slf4j.Logger; diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCart.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCart.java new file mode 100644 index 00000000..f660850c --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCart.java @@ -0,0 +1,193 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.microsoft.azure.functions.*; +import com.microsoft.azure.functions.annotation.*; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.CartReceiptsCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; +import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.ReceiptCosmosServiceImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.isReceiptStatusValid; + +/** + * Azure Functions with Azure Http trigger. + */ +public class RecoverFailedCart { + + private final Logger logger = LoggerFactory.getLogger(RecoverFailedCart.class); + + private final BizEventToReceiptService bizEventToReceiptService; + private final CartReceiptsCosmosClient cartReceiptsCosmosClient; + + public RecoverFailedCart(){ + this.bizEventToReceiptService = new BizEventToReceiptServiceImpl(); + this.cartReceiptsCosmosClient = CartReceiptsCosmosClientImpl.getInstance(); + } + + RecoverFailedCart(BizEventToReceiptService bizEventToReceiptService, + CartReceiptsCosmosClient cartReceiptsCosmosClient){ + this.bizEventToReceiptService = bizEventToReceiptService; + this.cartReceiptsCosmosClient = cartReceiptsCosmosClient; + } + + /** + * This function will be invoked when a Http Trigger occurs. + *

+ * It recovers the receipt with the specified biz event id that has the following status: + * - ({@link ReceiptStatusType#INSERTED}) + * - ({@link ReceiptStatusType#FAILED}) + * - ({@link ReceiptStatusType#NOT_QUEUE_SENT}) + *

+ * It creates the receipts if not exist and send on queue the event in order to proceed with the receipt generation. + * + * @return response with {@link HttpStatus#OK} if the operation succeeded + */ + @FunctionName("RecoverFailedCart") + public HttpResponseMessage run ( + @HttpTrigger(name = "RecoverFailedCartTrigger", + methods = {HttpMethod.POST}, + route = "cart/{cart-id}/recover-failed", + authLevel = AuthorizationLevel.ANONYMOUS) + HttpRequestMessage> request, + @BindingName("cart-id") String cartId, + @CosmosDBOutput( + name = "CartReceiptDatastore", + databaseName = "db", + collectionName = "cart-for-receipt", + connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING") + OutputBinding cartForReceiptDocumentdb, + final ExecutionContext context) { + logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); + + if (cartId == null || cartId.isBlank()) { + return request + .createResponseBuilder(HttpStatus.BAD_REQUEST) + .body(ProblemJson.builder() + .title(HttpStatus.BAD_REQUEST.name()) + .detail("Please pass a valid transaction id") + .status(HttpStatus.BAD_REQUEST.value()) + .build()) + .build(); + } + + try { + + CartForReceipt cartForReceipt = cartReceiptsCosmosClient.getCartItem(cartId); + + if (!cartForReceipt.getStatus().equals(CartStatusType.FAILED) && !cartForReceipt.getStatus().equals(CartStatusType.INSERTED)) { + String responseMsg = String.format("The requested cart with transaction ID %s is not in the expected status", + cartForReceipt.getId()); + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title(HttpStatus.INTERNAL_SERVER_ERROR.name()) + .detail(responseMsg) + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .build()) + .build(); + } + + if (cartForReceipt.getTotalNotice() != cartForReceipt.getCartPaymentId().size()) { + logger.info("[{}] Not all items collected for cart with id {}, this event will be skipped", + context.getFunctionName(), cartForReceipt.getId()); + return request + .createResponseBuilder(HttpStatus.BAD_REQUEST) + .body(ProblemJson.builder() + .title(HttpStatus.BAD_REQUEST.name()) + .detail("Items not found on cart for the id") + .status(HttpStatus.BAD_REQUEST.value()) + .build()) + .build(); + } + + List bizEventList = this.bizEventToReceiptService.getCartBizEvents(cartForReceipt.getId()); + Receipt receipt = this.bizEventToReceiptService.createCartReceipt(bizEventList); + + if (!isReceiptStatusValid(receipt)) { + logger.error("[{}] Failed to process cart with id {}: fail to tokenize fiscal codes", + context.getFunctionName(), cartForReceipt.getId()); + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title(HttpStatus.INTERNAL_SERVER_ERROR.name()) + .detail("Failed to process cart: fail to tokenize fiscal codes") + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .build()) + .build(); + } + + // Add receipt to items to be saved on CosmosDB + this.bizEventToReceiptService.handleSaveReceipt(receipt); + + if (!isReceiptStatusValid(receipt)) { + logger.error("[{}] Failed to process cart with id {}: fail to save receipt", + context.getFunctionName(), cartForReceipt.getId()); + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title(HttpStatus.INTERNAL_SERVER_ERROR.name()) + .detail("Failed to process cart: fail to save receipt") + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .build()) + .build(); + } + + // Send biz event as message to queue (to be processed from the other function) + this.bizEventToReceiptService.handleSendMessageToQueue(bizEventList, receipt); + + + if (!isReceiptStatusValid(receipt)) { + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title(HttpStatus.INTERNAL_SERVER_ERROR.name()) + .detail("Failed to process cart: fail to send message queue") + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .build()) + .build(); + } + cartForReceipt.setStatus(CartStatusType.SENT); + logger.info("[{}] Cart with id {} processes successfully. Cart with status: {} and receipt with status: {}", + context.getFunctionName(), cartForReceipt.getId(), cartForReceipt.getStatus(), receipt.getStatus()); + cartForReceiptDocumentdb.setValue(cartForReceipt); + String responseMsg = String.format("Cart with id %s recovered", cartId); + return request.createResponseBuilder(HttpStatus.OK) + .body(responseMsg) + .build(); + + } catch (CartNotFoundException exception) { + String msg = String.format("Unable to retrieve the cart with id %s", cartId); + logger.error(msg, exception); + return request + .createResponseBuilder(HttpStatus.NOT_FOUND) + .body(ProblemJson.builder() + .title(HttpStatus.NOT_FOUND.name()) + .detail(msg) + .status(HttpStatus.NOT_FOUND.value()) + .build()) + .build(); + } + + } +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassive.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassive.java new file mode 100644 index 00000000..08eb9465 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassive.java @@ -0,0 +1,137 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.microsoft.azure.functions.*; +import com.microsoft.azure.functions.annotation.AuthorizationLevel; +import com.microsoft.azure.functions.annotation.CosmosDBOutput; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.HttpTrigger; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.CartReceiptsCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverCartResult; +import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.massiveRecoverCartByStatus; + +/** + * Azure Functions with Azure Http trigger. + */ +public class RecoverFailedCartMassive { + + private final Logger logger = LoggerFactory.getLogger(RecoverFailedCartMassive.class); + + private final BizEventToReceiptService bizEventToReceiptService; + private final CartReceiptsCosmosClient cartReceiptsCosmosClient; + + public RecoverFailedCartMassive() { + this.bizEventToReceiptService = new BizEventToReceiptServiceImpl(); + this.cartReceiptsCosmosClient = CartReceiptsCosmosClientImpl.getInstance(); + } + + RecoverFailedCartMassive(BizEventToReceiptService bizEventToReceiptService, + CartReceiptsCosmosClient cartReceiptsCosmosClient) { + this.bizEventToReceiptService = bizEventToReceiptService; + this.cartReceiptsCosmosClient = cartReceiptsCosmosClient; + } + + /** + * This function will be invoked when a Http Trigger occurs. + *

+ * It recovers all the carts with the specified status that has to be one of: + * - ({@link it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType#INSERTED}) + * - ({@link it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType#FAILED}) + *

+ * It attempts to recreate and send receipt data based on cart having a failed or stuck status. + * + * @return response with {@link HttpStatus#OK} if the operation succeeded + */ + @FunctionName("RecoverFailedCartMassive") + public HttpResponseMessage run( + @HttpTrigger(name = "RecoverFailedCartMassiveTrigger", + methods = {HttpMethod.POST}, + route = "carts/recover-failed", + authLevel = AuthorizationLevel.ANONYMOUS) + HttpRequestMessage> request, + @CosmosDBOutput( + name = "CartReceiptDatastore", + databaseName = "db", + collectionName = "cart-for-receipt", + connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING") + OutputBinding> cartForReceiptDocumentdb, + final ExecutionContext context) { + logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); + + // Get named parameter + String status = request.getQueryParameters().get("status"); + if (status == null) { + return request + .createResponseBuilder(HttpStatus.BAD_REQUEST) + .body(ProblemJson.builder() + .title(HttpStatus.BAD_REQUEST.name()) + .detail("Please pass a status to recover") + .status(HttpStatus.BAD_REQUEST.value()) + .build()) + .build(); + } + + CartStatusType statusType; + try { + statusType = CartStatusType.valueOf(status); + } catch (IllegalArgumentException e) { + return request + .createResponseBuilder(HttpStatus.BAD_REQUEST) + .body(ProblemJson.builder() + .title(HttpStatus.BAD_REQUEST.name()) + .detail("Please pass a valid status to recover") + .status(HttpStatus.BAD_REQUEST.value()) + .build()) + .build(); + } + + MassiveRecoverCartResult recoverResult; + try { + recoverResult = massiveRecoverCartByStatus( + context, bizEventToReceiptService, cartReceiptsCosmosClient, logger, statusType); + } catch (Exception e) { + logger.error("[{}] Unexpected error during recover of failed cart", context.getFunctionName(), e); + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title(HttpStatus.INTERNAL_SERVER_ERROR.name()) + .detail(e.getMessage()) + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .build()) + .build(); + } + List cartItems = recoverResult.getCartItems(); + int errorCounter = recoverResult.getErrorCounter(); + + cartForReceiptDocumentdb.setValue(cartItems); + if (errorCounter > 0) { + String msg = String.format("Recovered %s carts but %s encountered an error.", cartItems.size(), errorCounter); + return request + .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ProblemJson.builder() + .title("Partial OK") + .detail(msg) + .status(HttpStatus.MULTI_STATUS.value()) + .build()) + .build(); + } + String responseMsg = String.format("Recovered %s carts", cartItems.size()); + return request.createResponseBuilder(HttpStatus.OK) + .body(responseMsg) + .build(); + } + +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartScheduled.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartScheduled.java new file mode 100644 index 00000000..e55686f6 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartScheduled.java @@ -0,0 +1,104 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.OutputBinding; +import com.microsoft.azure.functions.annotation.CosmosDBOutput; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.TimerTrigger; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.CartReceiptsCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverCartResult; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverResult; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.ReceiptCosmosServiceImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.massiveRecoverByStatus; +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.massiveRecoverCartByStatus; + +/** + * Azure Functions with Timer trigger. + */ +public class RecoverFailedCartScheduled { + + private final Logger logger = LoggerFactory.getLogger(RecoverFailedCartScheduled.class); + + private final boolean isEnabled = Boolean.parseBoolean(System.getenv().getOrDefault("FAILED_CART_AUTORECOVER_ENABLED", "true")); + + private final BizEventToReceiptService bizEventToReceiptService; + + private final CartReceiptsCosmosClient cartReceiptsCosmosClient; + + public RecoverFailedCartScheduled() { + this.bizEventToReceiptService = new BizEventToReceiptServiceImpl(); + this.cartReceiptsCosmosClient = CartReceiptsCosmosClientImpl.getInstance(); + } + + RecoverFailedCartScheduled(BizEventToReceiptService bizEventToReceiptService, + CartReceiptsCosmosClient cartReceiptsCosmosClient) { + this.bizEventToReceiptService = bizEventToReceiptService; + this.cartReceiptsCosmosClient = cartReceiptsCosmosClient; + } + + /** + * This function will be invoked periodically according to the specified schedule. + *

+ * It recovers all the receipts with the following status: + * - ({@link it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType#INSERTED}) + * - ({@link it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType#FAILED}) + *

+ * It creates the receipts if not exist and send on queue the event in order to proceed with the receipt generation. + */ + @FunctionName("RecoverFailedCartScheduled") + public void run( + @TimerTrigger(name = "timerInfo", schedule = "%RECOVER_FAILED_CART_CRON%") String timerInfo, + @CosmosDBOutput( + name = "CartReceiptDatastore", + databaseName = "db", + collectionName = "cart-for-receipt", + connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING") + OutputBinding> cartForReceiptDocumentdb, + final ExecutionContext context + ) { + if (isEnabled) { + logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); + List cartForReceipts = new ArrayList<>(); + + cartForReceipts.addAll(recover(context, CartStatusType.INSERTED)); + cartForReceipts.addAll(recover(context, CartStatusType.FAILED)); + + cartForReceiptDocumentdb.setValue(cartForReceipts); + } + } + + private List recover(ExecutionContext context, CartStatusType statusType) { + try { + MassiveRecoverCartResult recoverResult = massiveRecoverCartByStatus( + context, bizEventToReceiptService, cartReceiptsCosmosClient, logger, statusType); + if (recoverResult.getErrorCounter() > 0) { + logger.error("[{}] Error recovering {} failed cart for status {}", + context.getFunctionName(), recoverResult.getErrorCounter(), statusType); + } + return recoverResult.getCartItems(); + } catch (Exception e) { + logger.error("[{}] Unexpected error during recover of failed cart for status {}", + context.getFunctionName(), statusType, e); + return Collections.emptyList(); + } + } +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java index f36b8441..3e86c87e 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java @@ -95,9 +95,12 @@ public HttpResponseMessage run ( .build(); } + Boolean isCart = Boolean.parseBoolean(request.getQueryParameters().getOrDefault( + "isCart", "false")); + try { Receipt receipt = BizEventToReceiptUtils.getEvent(eventId, context, this.bizEventToReceiptService, - this.bizEventCosmosClient, this.receiptCosmosService, null, logger); + this.bizEventCosmosClient, this.receiptCosmosService, null, logger, isCart); documentdb.setValue(receipt); String responseMsg = String.format("Receipt with eventId %s recovered", eventId); diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java index 70a49fb3..b0ed5b64 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java @@ -11,8 +11,10 @@ import com.microsoft.azure.functions.annotation.CosmosDBOutput; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RegenerateReceiptPdf.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RegenerateReceiptPdf.java index 1f4cfc61..a5be8265 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RegenerateReceiptPdf.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RegenerateReceiptPdf.java @@ -23,6 +23,8 @@ import java.io.IOException; import java.nio.file.Path; import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; import java.util.Optional; import static it.gov.pagopa.receipt.pdf.helpdesk.utils.GenerateReceiptUtils.*; @@ -85,7 +87,18 @@ public HttpResponseMessage run ( try { - BizEvent bizEvent = bizEventCosmosClient.getBizEventDocument(eventId); + Boolean isCart = Boolean.parseBoolean(request.getQueryParameters().getOrDefault( + "isCart", "false")); + + BizEvent bizEvent; + List listBizEvent = null; + + if (isCart) { + listBizEvent = bizEventToReceiptService.getCartBizEvents(eventId); + bizEvent = listBizEvent.get(0); + } else { + bizEvent = bizEventCosmosClient.getBizEventDocument(eventId); + } //Retrieve receipt's data from CosmosDB Receipt receipt = getReceipt(context, bizEvent, receiptCosmosClient, logger); @@ -107,7 +120,8 @@ && isHasAllAttachments(receipt) if (receipt.getEventData().getDebtorFiscalCode() == null || receipt.getEventData().getPayerFiscalCode() == null) { - BizEventToReceiptUtils.tokenizeReceipt(bizEventToReceiptService, bizEvent, receipt); + BizEventToReceiptUtils.tokenizeReceipt(bizEventToReceiptService, isCart ? + listBizEvent : Collections.singletonList(bizEvent), receipt); documentdb.setValue(receipt); } @@ -117,7 +131,8 @@ && isHasAllAttachments(receipt) documentdb.setValue(receipt); } - pdfGeneration = generateReceiptPdfService.generateReceipts(receipt, bizEvent, workingDirPath); + pdfGeneration = generateReceiptPdfService.generateReceipts(receipt, isCart ? + listBizEvent : Collections.singletonList(bizEvent), workingDirPath); //Verify PDF generation success boolean success = true; diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/BizEventCosmosClient.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/BizEventCosmosClient.java index d9422a71..f9905f17 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/BizEventCosmosClient.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/BizEventCosmosClient.java @@ -1,5 +1,6 @@ package it.gov.pagopa.receipt.pdf.helpdesk.client; +import com.azure.cosmos.models.FeedResponse; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; @@ -23,4 +24,14 @@ public interface BizEventCosmosClient { * @throws BizEventNotFoundException in case no biz-event has been found with the given idEvent */ BizEvent getBizEventDocumentByOrganizationFiscalCodeAndIUV(String organizationFiscalCode, String iuv) throws BizEventNotFoundException; + + /** + * Retrieve all biz-event documents related to a specific cart from CosmosDB database + * + * @param transactionId id that identifies the cart + * @param continuationToken Paged query continuation token + * @param pageSize the page size + * @return a list of biz-event document + */ + Iterable> getAllBizEventDocument(String transactionId, String continuationToken, Integer pageSize); } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/CartReceiptsCosmosClient.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/CartReceiptsCosmosClient.java new file mode 100644 index 00000000..69489ec1 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/CartReceiptsCosmosClient.java @@ -0,0 +1,18 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.client; + +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedResponse; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; + +public interface CartReceiptsCosmosClient { + + CartForReceipt getCartItem(String eventId) throws CartNotFoundException; + + CosmosItemResponse saveCart(CartForReceipt receipt); + + Iterable> getFailedCarts(String continuationToken, int size); + + Iterable> getInsertedCarts(String continuationToken, int size); +} diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/BizEventCosmosClientImpl.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/BizEventCosmosClientImpl.java index a71dcd34..0cdff8ff 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/BizEventCosmosClientImpl.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/BizEventCosmosClientImpl.java @@ -5,6 +5,7 @@ import com.azure.cosmos.CosmosContainer; import com.azure.cosmos.CosmosDatabase; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.util.CosmosPagedIterable; import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; @@ -84,4 +85,23 @@ public BizEvent getBizEventDocumentByOrganizationFiscalCodeAndIUV(String organiz } throw new BizEventNotFoundException("Document not found in the defined container"); } + + /** + * {@inheritDoc} + */ + @Override + public Iterable> getAllBizEventDocument(String transactionId, String continuationToken, Integer pageSize) { + CosmosDatabase cosmosDatabase = this.cosmosClient.getDatabase(databaseId); + CosmosContainer cosmosContainer = cosmosDatabase.getContainer(containerId); + + //Build query + String query = String.format("SELECT * FROM c WHERE c.transactionDetails.transaction.transactionId = '%s'", + transactionId); + + //Query the container + return cosmosContainer + .queryItems(query, new CosmosQueryRequestOptions(), BizEvent.class) + .iterableByPage(continuationToken, pageSize); + } + } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImpl.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImpl.java new file mode 100644 index 00000000..0f1be3a9 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImpl.java @@ -0,0 +1,131 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.client.impl; + +import com.azure.cosmos.*; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedResponse; +import com.azure.cosmos.util.CosmosPagedIterable; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; + +public class CartReceiptsCosmosClientImpl implements CartReceiptsCosmosClient { + + private static CartReceiptsCosmosClientImpl instance; + private final String databaseId = System.getenv("COSMOS_RECEIPT_DB_NAME"); + private final String cartForReceiptContainerName = System.getenv("CART_FOR_RECEIPT_CONTAINER_NAME"); + + private final String millisDiff = System.getenv("MAX_DATE_DIFF_CART_MILLIS"); + + private final String numDaysCartNotSent = System.getenv().getOrDefault("RECOVER_CART_MASSIVE_MAX_DAYS", "0"); + + + private final CosmosClient cosmosClient; + + private CartReceiptsCosmosClientImpl() { + String azureKey = System.getenv("COSMOS_RECEIPT_KEY"); + String serviceEndpoint = System.getenv("COSMOS_RECEIPT_SERVICE_ENDPOINT"); + + this.cosmosClient = new CosmosClientBuilder() + .endpoint(serviceEndpoint) + .key(azureKey) + .consistencyLevel(ConsistencyLevel.STRONG) + .buildClient(); + } + + public CartReceiptsCosmosClientImpl(CosmosClient cosmosClient) { + this.cosmosClient = cosmosClient; + } + + public static CartReceiptsCosmosClientImpl getInstance() { + if (instance == null) { + instance = new CartReceiptsCosmosClientImpl(); + } + + return instance; + } + + /** + * Retrieve receipt document from CosmosDB database + * + * @param eventId Biz-event id + * @return receipt document + * @throws ReceiptNotFoundException in case no receipt has been found with the given idEvent + */ + @Override + public CartForReceipt getCartItem(String eventId) throws CartNotFoundException { + CosmosDatabase cosmosDatabase = this.cosmosClient.getDatabase(databaseId); + + CosmosContainer cosmosContainer = cosmosDatabase.getContainer(cartForReceiptContainerName); + + //Build query + String query = "SELECT * FROM c WHERE c.id = " + "'" + eventId + "'"; + + //Query the container + CosmosPagedIterable queryResponse = cosmosContainer + .queryItems(query, new CosmosQueryRequestOptions(), CartForReceipt.class); + + if (queryResponse.iterator().hasNext()) { + return queryResponse.iterator().next(); + } else { + throw new CartNotFoundException("Document not found in the defined container"); + } + + } + + /** + * Save Cart For Receipt on CosmosDB database + * + * @param receipt Cart Data to save + * @return cart-to-receipts documents + */ + @Override + public CosmosItemResponse saveCart(CartForReceipt receipt) { + CosmosDatabase cosmosDatabase = this.cosmosClient.getDatabase(databaseId); + CosmosContainer cosmosContainer = cosmosDatabase.getContainer(cartForReceiptContainerName); + return cosmosContainer.createItem(receipt); + } + + @Override + public Iterable> getFailedCarts(String continuationToken, int size) { + CosmosDatabase cosmosDatabase = this.cosmosClient.getDatabase(databaseId); + CosmosContainer cosmosContainer = cosmosDatabase.getContainer(cartForReceiptContainerName); + + //Build query + String query = String.format("SELECT * FROM c WHERE (c.status = '%s') AND c._ts >= %s", + CartStatusType.FAILED, + OffsetDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays( + Long.parseLong(numDaysCartNotSent)).toInstant().toEpochMilli()); + + //Query the container + return cosmosContainer + .queryItems(query, new CosmosQueryRequestOptions(), CartForReceipt.class) + .iterableByPage(continuationToken,size); + } + + @Override + public Iterable> getInsertedCarts(String continuationToken, int size) { + CosmosDatabase cosmosDatabase = this.cosmosClient.getDatabase(databaseId); + CosmosContainer cosmosContainer = cosmosDatabase.getContainer(cartForReceiptContainerName); + + //Build query + String query = String.format("SELECT * FROM c WHERE (c.status = '%s' AND c._ts >= %s " + + "AND ( %s - c._ts) >= %s)", + ReceiptStatusType.INSERTED, + OffsetDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays( + Long.parseLong(numDaysCartNotSent)).toInstant().toEpochMilli(), + OffsetDateTime.now().toInstant().toEpochMilli(), millisDiff); + + //Query the container + return cosmosContainer + .queryItems(query, new CosmosQueryRequestOptions(), CartForReceipt.class) + .iterableByPage(continuationToken,100); + } + +} diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/entity/cart/CartForReceipt.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/entity/cart/CartForReceipt.java index 444cfb5e..78c4c496 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/entity/cart/CartForReceipt.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/entity/cart/CartForReceipt.java @@ -13,10 +13,9 @@ @Builder @Data public class CartForReceipt { - private String id; private Set cartPaymentId; private Integer totalNotice; private CartStatusType status; private ReasonError reasonError; -} \ No newline at end of file +} diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverCartResult.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverCartResult.java new file mode 100644 index 00000000..9f47f668 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverCartResult.java @@ -0,0 +1,17 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.model; + +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class MassiveRecoverCartResult { + + private List cartItems; + private int errorCounter; +} diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BizEventToReceiptService.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BizEventToReceiptService.java index ad494ef1..ae9b0055 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BizEventToReceiptService.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BizEventToReceiptService.java @@ -7,16 +7,17 @@ import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; +import java.util.List; + public interface BizEventToReceiptService { /** * Handles sending biz-events as message to queue and updates receipt's status * - * @param bizEvent Biz-event from CosmosDB + * @param bizEventList Biz-event list from CosmosDB * @param receipt Receipt to update */ - void handleSendMessageToQueue(BizEvent bizEvent, Receipt receipt); - + void handleSendMessageToQueue(List bizEventList, Receipt receipt); /** * Retrieve conditionally the transaction creation date from biz-event @@ -36,4 +37,23 @@ public interface BizEventToReceiptService { * @throws PDVTokenizerException if an error occur when invoking the PDV Tokenizer */ void tokenizeFiscalCodes(BizEvent bizEvent, Receipt receipt, EventData eventData) throws JsonProcessingException, PDVTokenizerException; + + void handleSaveReceipt(Receipt receipt); + + /** + * Retrieve all events that are associated to the cart with the specified id + * + * @param cartId the id of the cart + * @return a list of biz-events + */ + List getCartBizEvents(String cartId); + + /** + * Creates the receipt for a cart, using the tokenizer service to mask the PII, based on + * the provided list of BizEvent + * + * @param bizEventList a list og BizEvent + * @return a receipt + */ + Receipt createCartReceipt(List bizEventList); } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BuildTemplateService.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BuildTemplateService.java index b2206fbd..b833bb07 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BuildTemplateService.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/BuildTemplateService.java @@ -5,18 +5,20 @@ import it.gov.pagopa.receipt.pdf.helpdesk.exception.TemplateDataMappingException; import it.gov.pagopa.receipt.pdf.helpdesk.model.template.ReceiptPDFTemplate; +import java.util.List; + public interface BuildTemplateService { /** * Maps a bizEvent to the json needed to compile the template * - * @param bizEvent Biz-event from queue message + * @param bizEvents Biz-events from queue message * @param partialTemplate boolean that indicates the type of template * @param receipt Receipt from CosmosDB * @return {@link ReceiptPDFTemplate} compiled template * @throws {@link TemplateDataMappingException} when mandatory fields are missing */ - ReceiptPDFTemplate buildTemplate(BizEvent bizEvent, boolean partialTemplate, Receipt receipt) throws TemplateDataMappingException; + ReceiptPDFTemplate buildTemplate(List bizEvents, boolean partialTemplate, Receipt receipt) throws TemplateDataMappingException; } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/GenerateReceiptPdfService.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/GenerateReceiptPdfService.java index 7ed5ba6c..799a7751 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/GenerateReceiptPdfService.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/GenerateReceiptPdfService.java @@ -6,6 +6,7 @@ import it.gov.pagopa.receipt.pdf.helpdesk.model.PdfGeneration; import java.nio.file.Path; +import java.util.List; public interface GenerateReceiptPdfService { @@ -13,10 +14,10 @@ public interface GenerateReceiptPdfService { * Handles conditionally the generation of the PDF's receipts based on the provided bizEvent * * @param receipt the Receipt that hold the status of the elaboration - * @param bizEvent Biz-event from queue message + * @param bizEvents Biz-events from queue message * @return {@link PdfGeneration} object with the result of the PDF generation and store or the relatives error messages */ - PdfGeneration generateReceipts(Receipt receipt, BizEvent bizEvent, Path workingDirPath); + PdfGeneration generateReceipts(Receipt receipt, List bizEvents, Path workingDirPath); /** * Verifies if the PDF generation process succeeded or not, and update the receipt with the result diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImpl.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImpl.java index a4896615..a8337a2d 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImpl.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImpl.java @@ -2,14 +2,18 @@ import com.azure.core.http.rest.Response; import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedResponse; import com.azure.storage.queue.models.SendMessageResult; import com.fasterxml.jackson.core.JsonProcessingException; import com.microsoft.azure.functions.HttpStatus; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptCosmosClient; import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptQueueClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptQueueClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.EventData; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReasonError; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; @@ -22,9 +26,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Objects; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.getItemSubject; public class BizEventToReceiptServiceImpl implements BizEventToReceiptService { @@ -33,35 +40,48 @@ public class BizEventToReceiptServiceImpl implements BizEventToReceiptService { private final PDVTokenizerServiceRetryWrapper pdvTokenizerService; private final ReceiptQueueClient queueClient; + private final BizEventCosmosClient bizEventCosmosClient; + + private final ReceiptCosmosClient receiptCosmosClient; + public BizEventToReceiptServiceImpl() { this.pdvTokenizerService = new PDVTokenizerServiceRetryWrapperImpl(); this.queueClient = ReceiptQueueClientImpl.getInstance(); + this.bizEventCosmosClient = BizEventCosmosClientImpl.getInstance(); + this.receiptCosmosClient = ReceiptCosmosClientImpl.getInstance(); } - public BizEventToReceiptServiceImpl(PDVTokenizerServiceRetryWrapper pdvTokenizerService, ReceiptQueueClient queueClient) { + public BizEventToReceiptServiceImpl(PDVTokenizerServiceRetryWrapper pdvTokenizerService, + ReceiptQueueClient queueClient, BizEventCosmosClient bizEventCosmosClient, + ReceiptCosmosClient receiptCosmosClient) { this.pdvTokenizerService = pdvTokenizerService; this.queueClient = queueClient; + this.bizEventCosmosClient = bizEventCosmosClient; + this.receiptCosmosClient = receiptCosmosClient; } /** * {@inheritDoc} */ @Override - public void handleSendMessageToQueue(BizEvent bizEvent, Receipt receipt) { + public void handleSendMessageToQueue(List bizEventList, Receipt receipt) { //Encode biz-event to base64 string String messageText = Base64.getMimeEncoder().encodeToString( - Objects.requireNonNull(ObjectMapperUtils.writeValueAsString(bizEvent)).getBytes(StandardCharsets.UTF_8) - ); + Objects.requireNonNull(ObjectMapperUtils.writeValueAsString(bizEventList)).getBytes(StandardCharsets.UTF_8)); //Add message to the queue int statusCode; try { Response sendMessageResult = queueClient.sendMessageToQueue(messageText); - statusCode = sendMessageResult.getStatusCode(); } catch (Exception e) { statusCode = ReasonErrorCode.ERROR_QUEUE.getCode(); - logger.error(String.format("Sending BizEvent with id %s to queue failed", bizEvent.getId()), e); + if (bizEventList.size() == 1) { + logger.error("Sending BizEvent with id {} to queue failed", bizEventList.get(0).getId(), e); + } else { + logger.error("Failed to enqueue cart with id {}", + bizEventList.get(0).getTransactionDetails().getTransaction().getIdTransaction(), e); + } } if (statusCode != HttpStatus.CREATED.value()) { @@ -131,6 +151,34 @@ public void tokenizeFiscalCodes(BizEvent bizEvent, Receipt receipt, EventData ev } } + /** + * {@inheritDoc} + */ + @Override + public void handleSaveReceipt(Receipt receipt) { + int statusCode; + + try { + receipt.setStatus(ReceiptStatusType.INSERTED); + receipt.setInsertedAt(System.currentTimeMillis()); + CosmosItemResponse response = receiptCosmosClient.saveReceipts(receipt); + + statusCode = response.getStatusCode(); + } catch (Exception e) { + statusCode = ReasonErrorCode.ERROR_COSMOS.getCode(); + logger.error("Save receipt with eventId {} on cosmos failed", receipt.getEventId(), e); + } + + if (statusCode != (HttpStatus.CREATED.value())) { + String errorString = String.format( + "[BizEventToReceiptService] Error saving receipt to cosmos for receipt with eventId %s, cosmos client responded with status %s", + receipt.getEventId(), statusCode); + handleError(receipt, ReceiptStatusType.FAILED, errorString, statusCode); + //Error info + logger.error(errorString); + } + } + /** * Handles errors for PDV tokenizer and updates receipt's status accordingly * @@ -143,4 +191,82 @@ private void handleTokenizerException(Receipt receipt, String errorMessage, int ReasonError reasonError = new ReasonError(statusCode, errorMessage); receipt.setReasonErr(reasonError); } + + /** + * {@inheritDoc} + */ + @Override + public List getCartBizEvents(String cartId) { + List bizEventList = new ArrayList<>(); + String continuationToken = null; + do { + Iterable> feedResponseIterator = + this.bizEventCosmosClient.getAllBizEventDocument(cartId, continuationToken, 100); + + for (FeedResponse page : feedResponseIterator) { + bizEventList.addAll(page.getResults()); + continuationToken = page.getContinuationToken(); + } + } while (continuationToken != null); + return bizEventList; + } + + /** + * {@inheritDoc} + */ + @Override + public Receipt createCartReceipt(List bizEventList) { + Receipt receipt = new Receipt(); + BizEvent firstBizEvent = bizEventList.get(0); + String carId = firstBizEvent.getTransactionDetails().getTransaction().getTransactionId(); + + // Insert biz-event data into receipt + receipt.setId(String.format("%s-%s", carId, UUID.randomUUID())); + receipt.setEventId(carId); + receipt.setIsCart(true); + + EventData eventData = new EventData(); + try { + this.tokenizeFiscalCodes(firstBizEvent, receipt, eventData); + } catch (Exception e) { + logger.error("Error tokenizing receipt for cart with id {}", carId, e); + receipt.setStatus(ReceiptStatusType.FAILED); + return receipt; + } + + eventData.setTransactionCreationDate(this.getTransactionCreationDate(firstBizEvent)); + + AtomicReference amount = new AtomicReference<>(BigDecimal.ZERO); + List cartItems = new ArrayList<>(); + bizEventList.forEach(bizEvent -> { + BigDecimal amountExtracted = getAmount(bizEvent); + amount.updateAndGet(v -> v.add(amountExtracted)); + cartItems.add( + CartItem.builder() + .payeeName(bizEvent.getCreditor() != null ? bizEvent.getCreditor().getCompanyName() : null) + .subject(getItemSubject(bizEvent)) + .build()); + }); + + if (!amount.get().equals(BigDecimal.ZERO)) { + eventData.setAmount(amount.get().toString()); + } + + eventData.setCart(cartItems); + + receipt.setEventData(eventData); + return receipt; + } + + public static BigDecimal getAmount(BizEvent bizEvent) { + if (bizEvent.getTransactionDetails() != null && bizEvent.getTransactionDetails().getTransaction() != null + && bizEvent.getTransactionDetails().getTransaction().getGrandTotal() != 0) { + return new BigDecimal(bizEvent.getTransactionDetails().getTransaction().getGrandTotal()); + } + if (bizEvent.getPaymentInfo() != null && bizEvent.getPaymentInfo().getAmount() != null) { + return new BigDecimal(bizEvent.getPaymentInfo().getAmount()); + } + return BigDecimal.ZERO; + } + } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImpl.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImpl.java index 119631eb..e6e57edd 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImpl.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImpl.java @@ -33,8 +33,6 @@ public class BuildTemplateServiceImpl implements BuildTemplateService { private static final String BRAND_LOGO_MAP_ENV_KEY = "BRAND_LOGO_MAP"; private static final String PSP_CONFIG_FILE_JSON_FILE_NAME = "psp_config_file.json"; - private static final String PAGO_PA_CHANNEL_IO = "IO"; - private static final String PAGO_PA_CHANNEL_IO_PAY = "IO-PAY"; private static final String RECEIPT_DATE_FORMAT = "dd MMMM yyyy, HH:mm:ss"; /** @@ -45,6 +43,7 @@ public class BuildTemplateServiceImpl implements BuildTemplateService { private static final Map pspMap; public static final String MODEL_TYPE_IUV = "1"; public static final String MODEL_TYPE_NOTICE = "2"; + public static final String DEBTOR_ANONIMO_CF = "ANONIMO"; static { try { @@ -70,14 +69,15 @@ public class BuildTemplateServiceImpl implements BuildTemplateService { * {@inheritDoc} */ @Override - public ReceiptPDFTemplate buildTemplate(BizEvent bizEvent, boolean isGeneratingDebtor, Receipt receipt) throws TemplateDataMappingException { + public ReceiptPDFTemplate buildTemplate(List listOfBizEvents, boolean isGeneratingDebtor, Receipt receipt) throws TemplateDataMappingException { + BizEvent bizEvent = listOfBizEvents.get(0); boolean requestedByDebtor = getRequestByDebtor(isGeneratingDebtor, bizEvent); return ReceiptPDFTemplate.builder() - .serviceCustomerId(getServiceCustomerId(bizEvent)) + .serviceCustomerId(getServiceCustomerId(receipt)) .transaction(Transaction.builder() .timestamp(getTimestamp(bizEvent)) - .amount(getAmount(bizEvent)) + .amount(getAmount(receipt)) .psp(getPsp(bizEvent)) .rrn(getRnn(bizEvent)) .paymentMethod(PaymentMethod.builder() @@ -98,37 +98,52 @@ public ReceiptPDFTemplate buildTemplate(BizEvent bizEvent, boolean isGeneratingD .build()) .build()) .cart(Cart.builder() - .items(Collections.singletonList( - Item.builder() - .refNumber(RefNumber.builder() - .type(getRefNumberType(bizEvent)) - .value(getRefNumberValue(bizEvent)) - .build()) - .debtor("ANONIMO".equals(receipt.getEventData().getDebtorFiscalCode()) ? - null : - Debtor.builder() - .fullName(getDebtorFullName(bizEvent)) - .taxCode(getDebtorTaxCode(bizEvent)) - .build()) - .payee(Payee.builder() - .name(getPayeeName(bizEvent)) - .taxCode(getPayeeTaxCode(bizEvent)) - .build()) - .subject(getItemSubject(receipt)) - .amount(getItemAmount(bizEvent)) - .build() - )) - //Cart items total amount w/o fee, TODO change it with multiple cart items implementation - .amountPartial(getItemAmount(bizEvent)) + .items(getCartItems(listOfBizEvents, receipt)) + .amountPartial(getCartAmountPartial(listOfBizEvents)) .build()) .build(); } - private String getServiceCustomerId(BizEvent event) throws TemplateDataMappingException { - if (event.getId() != null) { - return event.getId(); + private List getCartItems(List listOfBizEvents, Receipt receipt) throws TemplateDataMappingException { + List cartItems = new ArrayList<>(); + for (int i = 0; i < listOfBizEvents.size(); i++) { + BizEvent bizEvent = listOfBizEvents.get(i); + cartItems.add( + Item.builder() + .refNumber(RefNumber.builder() + .type(getRefNumberType(bizEvent)) + .value(getRefNumberValue(bizEvent)) + .build()) + .debtor(DEBTOR_ANONIMO_CF.equals(receipt.getEventData().getDebtorFiscalCode()) ? + null :Debtor.builder() + .fullName(getDebtorFullName(bizEvent)) + .taxCode(getDebtorTaxCode(bizEvent)) + .build()) + .payee(Payee.builder() + .name(getPayeeName(bizEvent)) + .taxCode(getPayeeTaxCode(bizEvent)) + .build()) + .subject(getItemSubject(receipt, i)) + .amount(getItemAmount(bizEvent, true)) + .build() + ); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.SERVICE_CUSTOMER_ID), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + return cartItems; + } + + private String getCartAmountPartial(List listOfBizEvents) throws TemplateDataMappingException { + double amountPartial = 0; + for (BizEvent bizEvent : listOfBizEvents) { + amountPartial = amountPartial + Double.parseDouble(getItemAmount(bizEvent, false)); + } + return currencyFormat(String.valueOf(amountPartial)); + } + + private String getServiceCustomerId(Receipt receipt) throws TemplateDataMappingException { + if (receipt.getEventId() != null) { + return receipt.getEventId(); + } + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.SERVICE_CUSTOMER_ID, receipt.getId(), false), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getTimestamp(BizEvent event) throws TemplateDataMappingException { @@ -142,22 +157,15 @@ private String getTimestamp(BizEvent event) throws TemplateDataMappingException if (event.getPaymentInfo() != null && event.getPaymentInfo().getPaymentDateTime() != null) { return dateFormat(event.getPaymentInfo().getPaymentDateTime()); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_TIMESTAMP), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_TIMESTAMP, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } - private String getAmount(BizEvent event) throws TemplateDataMappingException { - if ( - event.getTransactionDetails() != null && - event.getTransactionDetails().getTransaction() != null && - event.getTransactionDetails().getTransaction().getGrandTotal() != 0L - ) { - // Amount in transactionDetails is defined in cents (es. 25500 not 255.00) - return currencyFormat(String.valueOf(event.getTransactionDetails().getTransaction().getGrandTotal() / 100.00)); + private String getAmount(Receipt receipt) throws TemplateDataMappingException { + if(receipt.getEventData() != null && + receipt.getEventData().getAmount() != null){ + return receipt.getEventData().getAmount(); } - if (event.getPaymentInfo() != null && event.getPaymentInfo().getAmount() != null) { - return currencyFormat(event.getPaymentInfo().getAmount()); - } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_AMOUNT), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_AMOUNT, receipt.getId(), false), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getRnn(BizEvent event) throws TemplateDataMappingException { @@ -176,7 +184,7 @@ private String getRnn(BizEvent event) throws TemplateDataMappingException { return event.getPaymentInfo().getIUR(); } } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_RRN), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_RRN, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getAuthCode(BizEvent event) { @@ -228,7 +236,7 @@ private String getUserFullName(BizEvent event) throws TemplateDataMappingExcepti if (event.getPayer() != null && event.getPayer().getFullName() != null) { return event.getPayer().getFullName(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.USER_DATA_FULL_NAME), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.USER_DATA_FULL_NAME, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getUserTaxCode(BizEvent event) throws TemplateDataMappingException { @@ -242,7 +250,7 @@ private String getUserTaxCode(BizEvent event) throws TemplateDataMappingExceptio if (event.getPayer() != null && event.getPayer().getEntityUniqueIdentifierValue() != null) { return event.getPayer().getEntityUniqueIdentifierValue(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.USER_DATA_TAX_CODE), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.USER_DATA_TAX_CODE, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getRefNumberType(BizEvent event) throws TemplateDataMappingException { @@ -254,7 +262,7 @@ private String getRefNumberType(BizEvent event) throws TemplateDataMappingExcept return REF_TYPE_NOTICE; } } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_REF_NUMBER_TYPE), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_REF_NUMBER_TYPE, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getRefNumberValue(BizEvent event) throws TemplateDataMappingException { @@ -266,7 +274,7 @@ private String getRefNumberValue(BizEvent event) throws TemplateDataMappingExcep return event.getDebtorPosition().getNoticeNumber(); } } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_REF_NUMBER_VALUE), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_REF_NUMBER_VALUE, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getDebtorFullName(BizEvent event) { @@ -277,7 +285,7 @@ private String getDebtorTaxCode(BizEvent event) throws TemplateDataMappingExcept if (event.getDebtor() != null && event.getDebtor().getEntityUniqueIdentifierValue() != null) { return event.getDebtor().getEntityUniqueIdentifierValue(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_DEBTOR_TAX_CODE), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_DEBTOR_TAX_CODE, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getPayeeName(BizEvent event) { @@ -288,25 +296,25 @@ private String getPayeeTaxCode(BizEvent event) throws TemplateDataMappingExcepti if (event.getCreditor() != null && event.getCreditor().getIdPA() != null) { return event.getCreditor().getIdPA(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_PAYEE_TAX_CODE), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_PAYEE_TAX_CODE, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } - private String getItemSubject(Receipt receipt) throws TemplateDataMappingException { + private String getItemSubject(Receipt receipt, int index) throws TemplateDataMappingException { if (receipt.getEventData() != null && !receipt.getEventData().getCart().isEmpty() && - receipt.getEventData().getCart().get(0) != null + receipt.getEventData().getCart().get(index) != null && + receipt.getEventData().getCart().get(index).getSubject() != null ) { - return receipt.getEventData().getCart().get(0).getSubject(); + return receipt.getEventData().getCart().get(index).getSubject(); } - - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_SUBJECT), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_SUBJECT, receipt.getId(), false), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } - private String getItemAmount(BizEvent event) throws TemplateDataMappingException { + private String getItemAmount(BizEvent event, boolean currencyFormatted) throws TemplateDataMappingException { if (event.getPaymentInfo() != null && event.getPaymentInfo().getAmount() != null) { - return currencyFormat(event.getPaymentInfo().getAmount()); + return currencyFormatted ? currencyFormat(event.getPaymentInfo().getAmount()) : event.getPaymentInfo().getAmount(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_AMOUNT), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.CART_ITEM_AMOUNT, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } private String getPspFee(BizEvent event) { @@ -327,26 +335,26 @@ private PSP getPsp(BizEvent event) throws TemplateDataMappingException { .getOrDefault(event.getPsp().getIdPsp(), new LinkedHashMap<>()); String pspFee = getPspFee(event); return PSP.builder() - .name(getOrThrow(info, "name", TemplateDataField.TRANSACTION_PSP_NAME)) + .name(getOrThrow(info, "name", TemplateDataField.TRANSACTION_PSP_NAME, event.getId())) .fee(PSPFee.builder() .amount(pspFee) .build()) - .companyName(getOrThrow(info, "companyName", TemplateDataField.TRANSACTION_PSP_COMPANY_NAME)) - .address(getOrThrow(info, "address", TemplateDataField.TRANSACTION_PSP_ADDRESS)) - .city(getOrThrow(info, "city", TemplateDataField.TRANSACTION_PSP_CITY)) - .province(getOrThrow(info, "province", TemplateDataField.TRANSACTION_PSP_PROVINCE)) - .buildingNumber(getOrThrow(info, "buildingNumber", TemplateDataField.TRANSACTION_PSP_BUILDING_NUMBER)) - .postalCode(getOrThrow(info, "postalCode", TemplateDataField.TRANSACTION_PSP_POSTAL_CODE)) - .logo(pspFee != null ? getOrThrow(info, "logo", TemplateDataField.TRANSACTION_PSP_LOGO) : info.get("logo")) + .companyName(getOrThrow(info, "companyName", TemplateDataField.TRANSACTION_PSP_COMPANY_NAME, event.getId())) + .address(getOrThrow(info, "address", TemplateDataField.TRANSACTION_PSP_ADDRESS, event.getId())) + .city(getOrThrow(info, "city", TemplateDataField.TRANSACTION_PSP_CITY, event.getId())) + .province(getOrThrow(info, "province", TemplateDataField.TRANSACTION_PSP_PROVINCE, event.getId())) + .buildingNumber(getOrThrow(info, "buildingNumber", TemplateDataField.TRANSACTION_PSP_BUILDING_NUMBER, event.getId())) + .postalCode(getOrThrow(info, "postalCode", TemplateDataField.TRANSACTION_PSP_POSTAL_CODE, event.getId())) + .logo(pspFee != null ? getOrThrow(info, "logo", TemplateDataField.TRANSACTION_PSP_LOGO, event.getId()) : info.get("logo")) .build(); } - throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_PSP), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(TemplateDataField.TRANSACTION_PSP, event.getId(), true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } - private String getOrThrow(LinkedHashMap map, String key, String errorKey) throws TemplateDataMappingException { + private String getOrThrow(LinkedHashMap map, String key, String errorKey, String eventId) throws TemplateDataMappingException { String value = map.get(key); if (value == null) { - throw new TemplateDataMappingException(formatErrorMessage(errorKey), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); + throw new TemplateDataMappingException(formatErrorMessage(errorKey, eventId, true), ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode()); } return value; } @@ -354,11 +362,11 @@ private String getOrThrow(LinkedHashMap map, String key, String private boolean getProcessedByPagoPA(BizEvent event) { if (event.getTransactionDetails() != null) { if (event.getTransactionDetails().getTransaction() != null && - event.getTransactionDetails().getTransaction().getOrigin() != null) { + event.getTransactionDetails().getTransaction().getOrigin() != null) { return true; } if (event.getTransactionDetails().getInfo() != null && - event.getTransactionDetails().getInfo().getClientId() != null) { + event.getTransactionDetails().getInfo().getClientId() != null) { return true; } } @@ -419,8 +427,9 @@ private String dateFormat(String date) throws TemplateDataMappingException { } } - private String formatErrorMessage(String missingProperty) { - return String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, missingProperty); + private String formatErrorMessage(String missingProperty, String id, Boolean isEvent) { + String object = Boolean.TRUE.equals(isEvent) ? "bizEvent" : "receipt"; + return String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, object, missingProperty, object, id); } private String formatFullName(String fullName, String fiscalCode) { diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImpl.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImpl.java index 9ce925e5..400f52d6 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImpl.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImpl.java @@ -28,6 +28,7 @@ import java.io.FileInputStream; import java.net.URL; import java.nio.file.Path; +import java.util.List; import java.util.Objects; import static org.apache.http.HttpStatus.SC_OK; @@ -58,7 +59,7 @@ public GenerateReceiptPdfServiceImpl() { * {@inheritDoc} */ @Override - public PdfGeneration generateReceipts(Receipt receipt, BizEvent bizEvent, Path workingDirPath) { + public PdfGeneration generateReceipts(Receipt receipt, List listOfBizEvents, Path workingDirPath) { PdfGeneration pdfGeneration = new PdfGeneration(); String debtorCF = receipt.getEventData().getDebtorFiscalCode(); @@ -69,13 +70,13 @@ public PdfGeneration generateReceipts(Receipt receipt, BizEvent bizEvent, Path w if (payerCF.equals(debtorCF)) { pdfGeneration.setGenerateOnlyDebtor(true); //Generate debtor's complete PDF - PdfMetadata generationResult = generateAndSavePDFReceipt(bizEvent, receipt, receipt.getMdAttach().getName(), false, workingDirPath); + PdfMetadata generationResult = generateAndSavePDFReceipt(listOfBizEvents, receipt, receipt.getMdAttach().getName(), false, workingDirPath); pdfGeneration.setDebtorMetadata(generationResult); return pdfGeneration; } //Generate payer's complete PDF - PdfMetadata generationResult = generateAndSavePDFReceipt(bizEvent, receipt, receipt.getMdAttachPayer().getName(), false, workingDirPath); + PdfMetadata generationResult = generateAndSavePDFReceipt(listOfBizEvents, receipt, receipt.getMdAttachPayer().getName(), false, workingDirPath); pdfGeneration.setPayerMetadata(generationResult); } else { @@ -84,7 +85,7 @@ public PdfGeneration generateReceipts(Receipt receipt, BizEvent bizEvent, Path w //Generate debtor's partial PDF if (!"ANONIMO".equals(debtorCF)) { - PdfMetadata generationResult = generateAndSavePDFReceipt(bizEvent, receipt, receipt.getMdAttach().getName(), true, workingDirPath); + PdfMetadata generationResult = generateAndSavePDFReceipt(listOfBizEvents, receipt, receipt.getMdAttach().getName(), true, workingDirPath); pdfGeneration.setDebtorMetadata(generationResult); } @@ -132,13 +133,13 @@ public boolean verifyAndUpdateReceipt(Receipt receipt, PdfGeneration pdfGenerati return result; } - private PdfMetadata generateAndSavePDFReceipt(BizEvent bizEvent, Receipt receipt, String blobName, boolean isGeneratingDebtor, Path workingDirPath) { + private PdfMetadata generateAndSavePDFReceipt(List listOfBizEvents, Receipt receipt, String blobName, boolean isGeneratingDebtor, Path workingDirPath) { try { - ReceiptPDFTemplate template = buildTemplateService.buildTemplate(bizEvent, isGeneratingDebtor, receipt); + ReceiptPDFTemplate template = buildTemplateService.buildTemplate(listOfBizEvents, isGeneratingDebtor, receipt); PdfEngineResponse pdfEngineResponse = generatePDFReceipt(template, workingDirPath); return saveToBlobStorage(pdfEngineResponse, blobName); } catch (PDFReceiptGenerationException e) { - logger.error("An error occurred when generating or saving the PDF receipt for biz-event {}. Error: {}", bizEvent.getId(), e.getMessage(), e); + logger.error("An error occurred when generating or saving the PDF receipt with eventId {}. Error: {}", receipt.getEventId(), e.getMessage(), e); return PdfMetadata.builder().statusCode(e.getStatusCode()).errorMessage(e.getMessage()).build(); } } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java index 8343ad81..1a43daf7 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java @@ -3,7 +3,11 @@ import com.azure.cosmos.models.FeedResponse; import com.fasterxml.jackson.core.JsonProcessingException; import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpStatus; import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.Transfer; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; @@ -14,18 +18,24 @@ import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverCartResult; import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverResult; +import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; import org.slf4j.Logger; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl.getAmount; + public class BizEventToReceiptUtils { private static final String REMITTANCE_INFORMATION_REGEX = "/TXT/(.*)"; @@ -37,19 +47,62 @@ public static Receipt getEvent( BizEventCosmosClient bizEventCosmosClient, ReceiptCosmosService receiptCosmosService, Receipt receipt, - Logger logger + Logger logger, + Boolean isCart ) throws BizEventNotFoundException, PDVTokenizerException, JsonProcessingException { - BizEvent bizEvent = bizEventCosmosClient.getBizEventDocument(eventId); - if (isBizEventInvalid(bizEvent, context, logger)) { + List listCart = null; + BizEvent bizEvent; + + if (isCart) { + listCart = bizEventToReceiptService.getCartBizEvents(eventId); + bizEvent = listCart.get(0); + } else { + bizEvent = bizEventCosmosClient.getBizEventDocument(eventId); + } + + if (isCart) { + Integer intTotalNotice = Integer.parseInt(bizEvent.getPaymentInfo().getTotalNotice()); + if (!intTotalNotice.equals(listCart.size())) { + return null; + } + for (BizEvent event : listCart) { + if (isBizEventInvalid(event, context, logger)) { + return null; + } + } + } else if (isBizEventInvalid(bizEvent, context, logger)) { return null; } + + if (receipt == null) { try { receipt = receiptCosmosService.getReceipt(eventId); } catch (ReceiptNotFoundException e) { receipt = BizEventToReceiptUtils.createReceipt(bizEvent, bizEventToReceiptService, logger); + EventData eventData = receipt.getEventData(); + if (isCart) { + AtomicReference amount = new AtomicReference<>(BigDecimal.ZERO); + List cartItems = new ArrayList<>(); + listCart.forEach(event -> { + BigDecimal amountExtracted = getAmount(bizEvent); + amount.updateAndGet(v -> v.add(amountExtracted)); + cartItems.add( + CartItem.builder() + .payeeName(bizEvent.getCreditor() != null ? + bizEvent.getCreditor().getCompanyName() : null) + .subject(getItemSubject(bizEvent)) + .build()); + }); + + if (!amount.get().equals(BigDecimal.ZERO)) { + eventData.setAmount(amount.get().toString()); + } + + eventData.setCart(cartItems); + } receipt.setStatus(ReceiptStatusType.FAILED); } } @@ -60,10 +113,11 @@ public static Receipt getEvent( receipt.getStatus().equals(ReceiptStatusType.NOT_QUEUE_SENT) )) { if (receipt.getEventData() == null || receipt.getEventData().getDebtorFiscalCode() == null) { - tokenizeReceipt(bizEventToReceiptService, bizEvent, receipt); + tokenizeReceipt(bizEventToReceiptService, isCart ? listCart : Collections.singletonList(bizEvent), receipt); } receipt.setStatus(ReceiptStatusType.INSERTED); - bizEventToReceiptService.handleSendMessageToQueue(bizEvent, receipt); + bizEventToReceiptService.handleSendMessageToQueue(isCart ? listCart : + Collections.singletonList(bizEvent), receipt); if (receipt.getStatus() != ReceiptStatusType.NOT_QUEUE_SENT) { receipt.setInsertedAt(System.currentTimeMillis()); receipt.setReasonErr(null); @@ -92,7 +146,8 @@ public static MassiveRecoverResult massiveRecoverByStatus( for (Receipt receipt : page.getResults()) { try { Receipt restored = getEvent(receipt.getEventId(), context, bizEventToReceiptService, - bizEventCosmosClient, receiptCosmosService, receipt, logger); + bizEventCosmosClient, receiptCosmosService, receipt, logger, receipt.getIsCart() != null ? + receipt.getIsCart() : false); receiptList.add(restored); } catch (Exception e) { logger.error(e.getMessage(), e); @@ -135,10 +190,17 @@ public static Receipt createReceipt(BizEvent bizEvent, BizEventToReceiptService eventData.setTransactionCreationDate( service.getTransactionCreationDate(bizEvent)); - eventData.setAmount(bizEvent.getPaymentInfo() != null ? - bizEvent.getPaymentInfo().getAmount() : null); + eventData.setAmount( + bizEvent.getTransactionDetails() != null && bizEvent + .getTransactionDetails().getTransaction() != null ? + String.valueOf(bizEvent.getTransactionDetails().getTransaction().getGrandTotal()) : + bizEvent.getPaymentInfo() != null ? bizEvent.getPaymentInfo().getAmount() : null + ); - List cartItems = getCartItems(bizEvent); + CartItem item = new CartItem(); + item.setPayeeName(bizEvent.getCreditor() != null ? bizEvent.getCreditor().getCompanyName() : null); + item.setSubject(getItemSubject(bizEvent)); + List cartItems = Collections.singletonList(item); eventData.setCart(cartItems); receipt.setEventData(eventData); @@ -212,28 +274,37 @@ public static boolean isBizEventInvalid(BizEvent bizEvent, ExecutionContext cont return false; } - public static void tokenizeReceipt(BizEventToReceiptService service, BizEvent bizEvent, Receipt receipt) + public static void tokenizeReceipt(BizEventToReceiptService service, List bizEvents, Receipt receipt) throws PDVTokenizerException, JsonProcessingException { + BizEvent firstEvent = bizEvents.get(0); if (receipt.getEventData() == null) { EventData eventData = new EventData(); receipt.setEventData(eventData); eventData.setTransactionCreationDate( - service.getTransactionCreationDate(bizEvent)); - eventData.setAmount(bizEvent.getPaymentInfo() != null ? - bizEvent.getPaymentInfo().getAmount() : null); + service.getTransactionCreationDate(firstEvent)); + + AtomicReference amount = new AtomicReference<>(BigDecimal.ZERO); + List cartItems = new ArrayList<>(); + bizEvents.forEach(bizEvent -> { + BigDecimal amountExtracted = getAmount(bizEvent); + amount.updateAndGet(v -> v.add(amountExtracted)); + cartItems.add( + CartItem.builder() + .payeeName(bizEvent.getCreditor() != null ? bizEvent.getCreditor().getCompanyName() : null) + .subject(getItemSubject(bizEvent)) + .build()); + }); + + if (!amount.get().equals(BigDecimal.ZERO)) { + eventData.setAmount(amount.get().toString()); + } + + eventData.setCart(cartItems); - createCart(bizEvent, eventData); } - service.tokenizeFiscalCodes(bizEvent, receipt, receipt.getEventData()); + service.tokenizeFiscalCodes(firstEvent, receipt, receipt.getEventData()); } - private static void createCart(BizEvent bizEvent, EventData eventData) { - CartItem item = new CartItem(); - item.setPayeeName(bizEvent.getCreditor() != null ? bizEvent.getCreditor().getCompanyName() : null); - item.setSubject(getItemSubject(bizEvent)); - List cartItems = Collections.singletonList(item); - eventData.setCart(cartItems); - } /** * Retrieve RemittanceInformation from BizEvent @@ -241,7 +312,7 @@ private static void createCart(BizEvent bizEvent, EventData eventData) { * @param bizEvent BizEvent from which retrieve the data * @return the remittance information */ - private static String getItemSubject(BizEvent bizEvent) { + public static String getItemSubject(BizEvent bizEvent) { if (bizEvent.getPaymentInfo() != null && bizEvent.getPaymentInfo().getRemittanceInformation() != null) { return bizEvent.getPaymentInfo().getRemittanceInformation(); } @@ -277,5 +348,67 @@ private static String formatRemittanceInformation(String remittanceInformation) return remittanceInformation; } + public static boolean isReceiptStatusValid(Receipt receipt) { + return receipt.getStatus() != ReceiptStatusType.FAILED && receipt.getStatus() != ReceiptStatusType.NOT_QUEUE_SENT; + } + + public static MassiveRecoverCartResult massiveRecoverCartByStatus( + ExecutionContext context, BizEventToReceiptService bizEventToReceiptService, + CartReceiptsCosmosClient cartReceiptsCosmosClient, + Logger logger, CartStatusType statusType) { + int errorCounter = 0; + List cartItems = new ArrayList<>(); + String continuationToken = null; + if (statusType == null) { + throw new IllegalArgumentException("at least one status must be specified"); + } + do { + Iterable> feedResponseIterator = null; + + if (statusType.equals(CartStatusType.FAILED)) { + feedResponseIterator = cartReceiptsCosmosClient.getFailedCarts(continuationToken, 100); + } + if (statusType.equals(CartStatusType.INSERTED)) { + feedResponseIterator = cartReceiptsCosmosClient.getInsertedCarts(continuationToken, 100); + } + + assert feedResponseIterator != null; + for (FeedResponse page : feedResponseIterator) { + for (CartForReceipt cart : page.getResults()) { + try { + List bizEventList = bizEventToReceiptService.getCartBizEvents(cart.getId()); + Receipt receipt = bizEventToReceiptService.createCartReceipt(bizEventList); + + if (!isReceiptStatusValid(receipt)) { + logger.error("[{}] Failed to process cart with id {}: fail to tokenize fiscal codes", + context.getFunctionName(), cart.getId()); + throw new Exception("receipt status not valid"); + } + + // Add receipt to items to be saved on CosmosDB + bizEventToReceiptService.handleSaveReceipt(receipt); + + if (!isReceiptStatusValid(receipt)) { + throw new Exception("receipt not valid"); + } + + // Send biz event as message to queue (to be processed from the other function) + bizEventToReceiptService.handleSendMessageToQueue(bizEventList, receipt); + cart.setStatus(CartStatusType.SENT); + cartItems.add(cart); + } catch (Exception e) { + logger.error(e.getMessage(), e); + errorCounter++; + } + } + continuationToken = page.getContinuationToken(); + } + } while (continuationToken != null); + return MassiveRecoverCartResult.builder() + .cartItems(cartItems) + .errorCounter(errorCounter) + .build(); + } + private BizEventToReceiptUtils() {} } diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/GenerateReceiptUtils.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/GenerateReceiptUtils.java index bf32a680..d04f6aea 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/GenerateReceiptUtils.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/GenerateReceiptUtils.java @@ -25,16 +25,6 @@ public class GenerateReceiptUtils { private static final String WORKING_DIRECTORY_PATH = System.getenv().getOrDefault("WORKING_DIRECTORY_PATH", ""); - public static BizEvent getBizEventFromMessage(ExecutionContext context, String bizEventMessage) throws BizEventNotValidException { - try { - return ObjectMapperUtils.mapString(bizEventMessage, BizEvent.class); - } catch (JsonProcessingException e) { - String errorMsg = String.format("[%s] Error parsing the message coming from the queue", - context.getFunctionName()); - throw new BizEventNotValidException(errorMsg, e); - } - } - public static Path createWorkingDirectory() throws IOException { File workingDirectory = new File(WORKING_DIRECTORY_PATH); if (!workingDirectory.exists()) { diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewedTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewedTest.java index f51e66cf..57d646a7 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewedTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/ReceiptToReviewedTest.java @@ -1,9 +1,14 @@ package it.gov.pagopa.receipt.pdf.helpdesk; +import com.azure.cosmos.models.FeedResponse; import com.microsoft.azure.functions.*; import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReceiptError; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptErrorStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.model.ReceiptToReviewedRequest; import it.gov.pagopa.receipt.pdf.helpdesk.util.HttpResponseMessageMock; @@ -12,10 +17,11 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; -import java.util.Optional; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -63,6 +69,36 @@ void requestWithValidBizEventSaveReceiptErrorInReviewed() throws ReceiptNotFound assertEquals(ReceiptErrorStatusType.REVIEWED, captured.getStatus()); } + @Test + void requestWithValidCartSaveReceiptErrorInReviewed() throws ReceiptNotFoundException, CartNotFoundException { + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(request).createResponseBuilder(any(HttpStatus.class)); + + ReceiptError receiptError = ReceiptError.builder() + .bizEventId(BIZ_EVENT_ID) + .status(ReceiptErrorStatusType.TO_REVIEW) + .build(); + when(receiptCosmosClient.getReceiptError(BIZ_EVENT_ID)).thenReturn(receiptError); + + when(request.getQueryParameters()).thenReturn(Collections.singletonMap("isCart","true")); + + when(receiptCosmosClient.getCartDocument(any())).thenReturn(generateCart()); + + function = spy(new ReceiptToReviewed(receiptCosmosClient)); + + // test execution + AtomicReference responseMessage = new AtomicReference<>(); + assertDoesNotThrow(() -> responseMessage.set(function.run(request, BIZ_EVENT_ID, documentdb,executionContextMock ))); + assertEquals(HttpStatus.OK, responseMessage.get().getStatus()); + + verify(documentdb).setValue(receiptErrorCaptor.capture()); + ReceiptError captured = receiptErrorCaptor.getValue(); + assertEquals(BIZ_EVENT_ID, captured.getBizEventId()); + assertEquals(ReceiptErrorStatusType.REVIEWED, captured.getStatus()); + } + @Test void requestWithValidBizEventIdButReceiptNotFound() throws ReceiptNotFoundException { doAnswer((Answer) invocation -> { @@ -120,4 +156,14 @@ void requestWithoutEventIdReturnsBadRequest() { verifyNoInteractions(documentdb); } + + private CartForReceipt generateCart() { + CartForReceipt cart = new CartForReceipt(); + cart.setId("1"); + cart.setStatus(CartStatusType.FAILED); + cart.setTotalNotice(1); + cart.setCartPaymentId(new HashSet<>(new ArrayList<>( + List.of(new String[]{"valid_biz_event_id"})))); + return cart; + } } \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveScheduledTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveScheduledTest.java new file mode 100644 index 00000000..2e84a05d --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveScheduledTest.java @@ -0,0 +1,214 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.azure.cosmos.models.ModelBridgeInternal; +import com.microsoft.azure.functions.*; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.*; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReasonError; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.util.HttpResponseMessageMock; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.*; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class RecoverFailedCartMassiveScheduledTest { + + private final String TOKENIZED_DEBTOR_FISCAL_CODE = "tokenizedDebtorFiscalCode"; + private final String TOKENIZED_PAYER_FISCAL_CODE = "tokenizedPayerFiscalCode"; + private final String EVENT_ID = "a valid id"; + + @Mock + private ExecutionContext contextMock; + @Mock + private CartReceiptsCosmosClient cartReceiptsCosmosClientMock; + @Mock + private BizEventCosmosClientImpl bizEventCosmosClientMock; + @Mock + private BizEventToReceiptService bizEventToReceiptServiceMock; + + @Mock + private HttpRequestMessage> requestMock; + + @Captor + private ArgumentCaptor> cartForReceiptCaptor; + + @Spy + private OutputBinding> documentdb; + + private AutoCloseable closeable; + + private RecoverFailedCartScheduled sut; + + @BeforeEach + public void openMocks() { + closeable = MockitoAnnotations.openMocks(this); + sut = spy(new RecoverFailedCartScheduled(bizEventToReceiptServiceMock, cartReceiptsCosmosClientMock)); + } + + @AfterEach + public void releaseMocks() throws Exception { + closeable.close(); + } + + @Test + void recoverFailedReceiptMassiveSuccess() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList(generateCart()), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)) + .thenReturn(generateValidBizEvent(EVENT_ID)); + when(bizEventToReceiptServiceMock.createCartReceipt(any())).thenReturn(buildReceipt()); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + assertDoesNotThrow(() -> sut.run("info", documentdb, contextMock)); + + verify(documentdb).setValue(cartForReceiptCaptor.capture()); + assertEquals(1, cartForReceiptCaptor.getValue().size()); + + } + + @Test + void recoverFailedErrorWhenFailHandleCart() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList(generateCart()), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)) + .thenReturn(generateValidBizEvent(EVENT_ID)); + when(bizEventToReceiptServiceMock.createCartReceipt(any())).thenAnswer(x -> { + throw new Exception("test"); + }); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + assertDoesNotThrow(() -> sut.run("info", documentdb, contextMock)); + + verify(documentdb).setValue(cartForReceiptCaptor.capture()); + assertEquals(0, cartForReceiptCaptor.getValue().size()); + + } + + @Test + void recoverFailedErrorWhenFailRecover() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenAnswer(x -> new Exception("error")); + + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + assertDoesNotThrow(() -> sut.run("info", documentdb, contextMock)); + + verify(documentdb).setValue(cartForReceiptCaptor.capture()); + assertEquals(0, cartForReceiptCaptor.getValue().size()); + + } + + private BizEvent generateValidBizEvent(String totalNotice){ + BizEvent item = new BizEvent(); + + Payer payer = new Payer(); + payer.setEntityUniqueIdentifierValue(TOKENIZED_PAYER_FISCAL_CODE); + Debtor debtor = new Debtor(); + debtor.setEntityUniqueIdentifierValue(TOKENIZED_DEBTOR_FISCAL_CODE); + + TransactionDetails transactionDetails = new TransactionDetails(); + Transaction transaction = new Transaction(); + transaction.setCreationDate(String.valueOf(LocalDateTime.now())); + transactionDetails.setTransaction(transaction); + + PaymentInfo paymentInfo = new PaymentInfo(); + paymentInfo.setTotalNotice(totalNotice); + + item.setEventStatus(BizEventStatusType.DONE); + item.setId(EVENT_ID); + item.setPayer(payer); + item.setDebtor(debtor); + item.setTransactionDetails(transactionDetails); + item.setPaymentInfo(paymentInfo); + + return item; + } + + private CartForReceipt generateCart() { + CartForReceipt cart = new CartForReceipt(); + cart.setId("1"); + cart.setStatus(CartStatusType.FAILED); + cart.setTotalNotice(2); + cart.setCartPaymentId(new HashSet<>(new ArrayList<>( + List.of(new String[]{"1", "2"})))); + return cart; + } + + private CartForReceipt generateInsertedCart() { + CartForReceipt cart = generateCart(); + cart.setStatus(CartStatusType.INSERTED); + return cart; + } + + private Receipt buildReceipt() { + return Receipt.builder() + .eventId(EVENT_ID) + .status(ReceiptStatusType.IO_ERROR_TO_NOTIFY) + .reasonErr(ReasonError.builder() + .code(500) + .message("error message") + .build()) + .reasonErrPayer(ReasonError.builder() + .code(500) + .message("error message") + .build()) + .numRetry(0) + .notificationNumRetry(6) + .insertedAt(0) + .generatedAt(0) + .notifiedAt(0) + .build(); + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveTest.java new file mode 100644 index 00000000..93f5f6d4 --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartMassiveTest.java @@ -0,0 +1,304 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.azure.cosmos.models.ModelBridgeInternal; +import com.microsoft.azure.functions.*; +import it.gov.pagopa.receipt.pdf.helpdesk.client.CartReceiptsCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.*; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.EventData; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReasonError; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; +import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import it.gov.pagopa.receipt.pdf.helpdesk.util.HttpResponseMessageMock; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.*; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class RecoverFailedCartMassiveTest { + + private final String TOKENIZED_DEBTOR_FISCAL_CODE = "tokenizedDebtorFiscalCode"; + private final String TOKENIZED_PAYER_FISCAL_CODE = "tokenizedPayerFiscalCode"; + private final String EVENT_ID = "a valid id"; + + @Mock + private ExecutionContext contextMock; + @Mock + private CartReceiptsCosmosClient cartReceiptsCosmosClientMock; + @Mock + private BizEventCosmosClientImpl bizEventCosmosClientMock; + @Mock + private BizEventToReceiptService bizEventToReceiptServiceMock; + + @Mock + private HttpRequestMessage> requestMock; + + @Captor + private ArgumentCaptor> cartForReceiptCaptor; + + @Spy + private OutputBinding> documentdb; + + private AutoCloseable closeable; + + private RecoverFailedCartMassive sut; + + @BeforeEach + public void openMocks() { + closeable = MockitoAnnotations.openMocks(this); + sut = spy(new RecoverFailedCartMassive(bizEventToReceiptServiceMock, cartReceiptsCosmosClientMock)); + } + + @AfterEach + public void releaseMocks() throws Exception { + closeable.close(); + } + + @Test + void recoverFailedReceiptMassiveSuccess() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList(generateCart()), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)) + .thenReturn(generateValidBizEvent(EVENT_ID)); + when(bizEventToReceiptServiceMock.createCartReceipt(any())).thenReturn(buildReceipt()); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentdb).setValue(cartForReceiptCaptor.capture()); + assertEquals(1, cartForReceiptCaptor.getValue().size()); + CartForReceipt captured = cartForReceiptCaptor.getValue().get(0); + assertEquals(CartStatusType.SENT, captured.getStatus()); + } + + @Test + void recoverInsertedReceiptMassiveSuccess() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.INSERTED.name())); + + when(cartReceiptsCosmosClientMock.getInsertedCarts(any(), eq(100))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList(generateInsertedCart()), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)) + .thenReturn(generateValidBizEvent(EVENT_ID)); + when(bizEventToReceiptServiceMock.createCartReceipt(any())).thenReturn(buildReceipt()); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentdb).setValue(cartForReceiptCaptor.capture()); + assertEquals(1, cartForReceiptCaptor.getValue().size()); + CartForReceipt captured = cartForReceiptCaptor.getValue().get(0); + assertEquals(CartStatusType.SENT, captured.getStatus()); + } + + @Test + void recoverErrorIfStatusWrong() { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", "a wrong statys")); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertNotNull(response.getBody()); + + } + + @Test + void recoverErrorIfStatusNull() { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", null)); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertNotNull(response.getBody()); + + } + + @Test + void recoverFailedErrorWhenFailHandleCart() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList(generateCart()), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)) + .thenReturn(generateValidBizEvent(EVENT_ID)); + when(bizEventToReceiptServiceMock.createCartReceipt(any())).thenAnswer(x -> { + throw new Exception("test"); + }); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatus()); + assertNotNull(response.getBody()); + + } + + @Test + void recoverFailedErrorWhenFailRecover() throws BizEventNotFoundException { + when(requestMock.getQueryParameters()) + .thenReturn(Collections.singletonMap("status", CartStatusType.FAILED.name())); + + when(cartReceiptsCosmosClientMock.getFailedCarts(any(), eq(100))) + .thenAnswer(x -> new Exception("error")); + + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatus()); + assertNotNull(response.getBody()); + + } + + private BizEvent generateValidBizEvent(String totalNotice){ + BizEvent item = new BizEvent(); + + Payer payer = new Payer(); + payer.setEntityUniqueIdentifierValue(TOKENIZED_PAYER_FISCAL_CODE); + Debtor debtor = new Debtor(); + debtor.setEntityUniqueIdentifierValue(TOKENIZED_DEBTOR_FISCAL_CODE); + + TransactionDetails transactionDetails = new TransactionDetails(); + Transaction transaction = new Transaction(); + transaction.setCreationDate(String.valueOf(LocalDateTime.now())); + transactionDetails.setTransaction(transaction); + + PaymentInfo paymentInfo = new PaymentInfo(); + paymentInfo.setTotalNotice(totalNotice); + + item.setEventStatus(BizEventStatusType.DONE); + item.setId(EVENT_ID); + item.setPayer(payer); + item.setDebtor(debtor); + item.setTransactionDetails(transactionDetails); + item.setPaymentInfo(paymentInfo); + + return item; + } + + private CartForReceipt generateCart() { + CartForReceipt cart = new CartForReceipt(); + cart.setId("1"); + cart.setStatus(CartStatusType.FAILED); + cart.setTotalNotice(2); + cart.setCartPaymentId(new HashSet<>(new ArrayList<>( + List.of(new String[]{"1", "2"})))); + return cart; + } + + private CartForReceipt generateInsertedCart() { + CartForReceipt cart = generateCart(); + cart.setStatus(CartStatusType.INSERTED); + return cart; + } + + private Receipt buildReceipt() { + return Receipt.builder() + .eventId(EVENT_ID) + .status(ReceiptStatusType.IO_ERROR_TO_NOTIFY) + .reasonErr(ReasonError.builder() + .code(500) + .message("error message") + .build()) + .reasonErrPayer(ReasonError.builder() + .code(500) + .message("error message") + .build()) + .numRetry(0) + .notificationNumRetry(6) + .insertedAt(0) + .generatedAt(0) + .notifiedAt(0) + .build(); + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartTest.java new file mode 100644 index 00000000..6d8c63fe --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedCartTest.java @@ -0,0 +1,330 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.azure.core.http.rest.Response; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedResponse; +import com.azure.storage.queue.models.SendMessageResult; +import com.microsoft.azure.functions.*; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptQueueClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.CartReceiptsCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.*; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.EventData; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; +import it.gov.pagopa.receipt.pdf.helpdesk.service.PDVTokenizerServiceRetryWrapper; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.util.HttpResponseMessageMock; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.*; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class RecoverFailedCartTest { + + private final String PAYER_FISCAL_CODE = "a valid payer CF"; + private final String DEBTOR_FISCAL_CODE = "a valid debtor CF"; + private final String TOKENIZED_DEBTOR_FISCAL_CODE = "tokenizedDebtorFiscalCode"; + private final String TOKENIZED_PAYER_FISCAL_CODE = "tokenizedPayerFiscalCode"; + private final String EVENT_ID = "a valid id"; + + public static final String HTTP_MESSAGE_ERROR = "an error occured"; + + @Mock + private ExecutionContext contextMock; + @Mock + private PDVTokenizerServiceRetryWrapper pdvTokenizerServiceMock; + @Mock + private ReceiptCosmosService receiptCosmosServiceMock; + @Mock + private ReceiptQueueClient queueClientMock; + @Mock + private BizEventCosmosClient bizEventCosmosClientMock; + + @Mock + private ReceiptCosmosClient receiptCosmosClient; + + @Mock + private CartReceiptsCosmosClientImpl cartReceiptsCosmosClient; + + @Mock + private HttpRequestMessage> requestMock; + + @Captor + private ArgumentCaptor cartForReceiptArgumentCaptor; + + @Spy + private OutputBinding documentdb; + + private AutoCloseable closeable; + + private RecoverFailedCart sut; + + @BeforeEach + public void openMocks() { + closeable = MockitoAnnotations.openMocks(this); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, queueClientMock, bizEventCosmosClientMock, receiptCosmosClient); + sut = spy(new RecoverFailedCart(receiptService, cartReceiptsCosmosClient)); + } + + @AfterEach + public void releaseMocks() throws Exception { + closeable.close(); + } + + + @Test + void requestOnValidCartShouldResend() throws CartNotFoundException { + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.CREATED.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenReturn(generateCart()); + + CosmosItemResponse responseCosmos = Mockito.mock(CosmosItemResponse.class); + when(responseCosmos.getStatusCode()).thenReturn(201); + when(receiptCosmosClient.saveReceipts(any())).thenReturn(responseCosmos); + + FeedResponse feedResponseMock = mock(FeedResponse.class); + List receiptList = Collections.singletonList(generateValidBizEvent("1")); + when(feedResponseMock.getResults()).thenReturn(receiptList); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("1"), any(), any()); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentdb).setValue(cartForReceiptArgumentCaptor.capture()); + CartForReceipt captured = cartForReceiptArgumentCaptor.getValue(); + assertEquals(CartStatusType.SENT, captured.getStatus()); + } + + @Test + void requestOnUncompleteCartShouldntResend() throws CartNotFoundException { + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.CREATED.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + CartForReceipt cart = generateCart(); + cart.setCartPaymentId(Collections.emptySet()); + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenReturn(cart); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertNotNull(response.getBody()); + + } + + @Test + void requestOnAlreadySentCartShouldntResend() throws CartNotFoundException { + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.CREATED.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + CartForReceipt cart = generateCart(); + cart.setStatus(CartStatusType.SENT); + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenReturn(cart); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatus()); + assertNotNull(response.getBody()); + + } + + @Test + void requestWithMissingCartOnRequestIdShouldReturnNotFound() throws CartNotFoundException { + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenThrow(CartNotFoundException.class); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatus()); + assertNotNull(response.getBody()); + } + + @Test + void requestWithMissingCartIdShouldReturnError() throws CartNotFoundException { + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, null, documentdb, contextMock)); + + assertNotNull(response); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertNotNull(response.getBody()); + } + + @Test + @SneakyThrows + void errorTokenizingFiscalCodes() { + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID)).thenReturn(generateValidBizEvent("1")); + when(receiptCosmosServiceMock.getReceipt(EVENT_ID)).thenThrow(ReceiptNotFoundException.class); + lenient().when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)) + .thenThrow(new PDVTokenizerException(HTTP_MESSAGE_ERROR, org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR)); + + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenReturn(generateCart()); + + FeedResponse feedResponseMock = mock(FeedResponse.class); + List receiptList = Collections.singletonList(generateValidBizEvent("1")); + when(feedResponseMock.getResults()).thenReturn(receiptList); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("1"), any(), any()); + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatus()); + + ProblemJson problemJson = (ProblemJson) response.getBody(); + assertNotNull(problemJson); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), problemJson.getStatus()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.name(), problemJson.getTitle()); + assertNotNull(problemJson.getDetail()); + + verifyNoInteractions(queueClientMock); + } + + @Test + @SneakyThrows + void errorAddingMessageToQueue() { + when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)) + .thenReturn(TOKENIZED_DEBTOR_FISCAL_CODE); + when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(PAYER_FISCAL_CODE)) + .thenReturn(TOKENIZED_PAYER_FISCAL_CODE); + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.FORBIDDEN.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + when(cartReceiptsCosmosClient.getCartItem(EVENT_ID)).thenReturn(generateCart()); + + FeedResponse feedResponseMock = mock(FeedResponse.class); + List receiptList = Collections.singletonList(generateValidBizEvent("1")); + when(feedResponseMock.getResults()).thenReturn(receiptList); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("1"), any(), any()); + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + } + + + + private BizEvent generateValidBizEvent(String totalNotice){ + BizEvent item = new BizEvent(); + + Payer payer = new Payer(); + payer.setEntityUniqueIdentifierValue(PAYER_FISCAL_CODE); + Debtor debtor = new Debtor(); + debtor.setEntityUniqueIdentifierValue(DEBTOR_FISCAL_CODE); + + TransactionDetails transactionDetails = new TransactionDetails(); + Transaction transaction = new Transaction(); + transaction.setCreationDate(String.valueOf(LocalDateTime.now())); + transactionDetails.setTransaction(transaction); + + PaymentInfo paymentInfo = new PaymentInfo(); + paymentInfo.setTotalNotice(totalNotice); + paymentInfo.setAmount("102.30"); + + item.setEventStatus(BizEventStatusType.DONE); + item.setId(EVENT_ID); + item.setPayer(payer); + item.setDebtor(debtor); + item.setTransactionDetails(transactionDetails); + item.setPaymentInfo(paymentInfo); + + return item; + } + + private CartForReceipt generateCart() { + CartForReceipt cart = new CartForReceipt(); + cart.setId("1"); + cart.setStatus(CartStatusType.FAILED); + cart.setTotalNotice(2); + cart.setCartPaymentId(new HashSet<>(new ArrayList<>( + List.of(new String[]{"1", "2"})))); + return cart; + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptTest.java index f85bb948..98c5d0a1 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptTest.java @@ -1,6 +1,7 @@ package it.gov.pagopa.receipt.pdf.helpdesk; import com.azure.core.http.rest.Response; +import com.azure.cosmos.models.FeedResponse; import com.azure.storage.queue.models.SendMessageResult; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpRequestMessage; @@ -9,6 +10,7 @@ import com.microsoft.azure.functions.OutputBinding; import it.gov.pagopa.receipt.pdf.helpdesk.client.ReceiptQueueClient; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.*; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; @@ -28,11 +30,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; @@ -45,14 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class RecoverFailedReceiptTest { @@ -76,6 +67,9 @@ class RecoverFailedReceiptTest { @Mock private BizEventCosmosClientImpl bizEventCosmosClientMock; + @Mock + private ReceiptCosmosClientImpl receiptCosmosClient; + @Mock private HttpRequestMessage> requestMock; @@ -92,7 +86,8 @@ class RecoverFailedReceiptTest { @BeforeEach public void openMocks() { closeable = MockitoAnnotations.openMocks(this); - BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl(pdvTokenizerServiceMock, queueClientMock); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, queueClientMock, bizEventCosmosClientMock, receiptCosmosClient); sut = spy(new RecoverFailedReceipt(receiptService, bizEventCosmosClientMock, receiptCosmosServiceMock)); } @@ -141,6 +136,51 @@ void requestOnValidBizEventShouldCreateRequest() { assertEquals(1, captured.getEventData().getCart().size()); } + @Test + @SneakyThrows + void requestOnValidCartShouldCreateRequest() { + when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)) + .thenReturn(TOKENIZED_DEBTOR_FISCAL_CODE); + when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(PAYER_FISCAL_CODE)) + .thenReturn(TOKENIZED_PAYER_FISCAL_CODE); + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.CREATED.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + when(requestMock.getQueryParameters()).thenReturn(Collections.singletonMap("isCart","true")); + + FeedResponse feedResponseMock = mock(FeedResponse.class); + List receiptList = Collections.singletonList(generateValidBizEvent("1")); + when(feedResponseMock.getResults()).thenReturn(receiptList); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("a valid id"), any(), any()); + + when(receiptCosmosServiceMock.getReceipt(EVENT_ID)).thenThrow(ReceiptNotFoundException.class); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentdb).setValue(receiptCaptor.capture()); + Receipt captured = receiptCaptor.getValue(); + assertEquals(ReceiptStatusType.INSERTED, captured.getStatus()); + assertEquals(EVENT_ID, captured.getEventId()); + assertEquals(TOKENIZED_PAYER_FISCAL_CODE, captured.getEventData().getPayerFiscalCode()); + assertEquals(TOKENIZED_DEBTOR_FISCAL_CODE, captured.getEventData().getDebtorFiscalCode()); + assertNotNull(captured.getEventData().getCart()); + assertEquals(1, captured.getEventData().getCart().size()); + } + @Test @SneakyThrows void requestOnValidBizEventTransactionDetailsShouldCreateRequest() { @@ -216,6 +256,45 @@ void requestOnValidBizEventAndFailedReceiptShouldResend() throws BizEventNotFoun assertEquals(1, captured.getEventData().getCart().size()); } + @Test + void requestOnValidCartAndFailedReceiptShouldResend() throws BizEventNotFoundException, ReceiptNotFoundException { + when(receiptCosmosServiceMock.getReceipt(EVENT_ID)).thenReturn(createFailedReceipt()); + + Response queueResponse = mock(Response.class); + when(queueResponse.getStatusCode()).thenReturn(HttpStatus.CREATED.value()); + when(queueClientMock.sendMessageToQueue(anyString())).thenReturn(queueResponse); + + FeedResponse feedResponseMock = mock(FeedResponse.class); + List receiptList = Collections.singletonList(generateValidBizEvent("1")); + when(feedResponseMock.getResults()).thenReturn(receiptList); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("a valid id"), any(), any()); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + when(requestMock.getQueryParameters()).thenReturn(Collections.singletonMap("isCart","true")); + + // test execution + HttpResponseMessage response = assertDoesNotThrow(() -> sut.run(requestMock, EVENT_ID, documentdb, contextMock)); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentdb).setValue(receiptCaptor.capture()); + Receipt captured = receiptCaptor.getValue(); + assertEquals(ReceiptStatusType.INSERTED, captured.getStatus()); + assertEquals(EVENT_ID, captured.getEventId()); + assertEquals(TOKENIZED_PAYER_FISCAL_CODE, captured.getEventData().getPayerFiscalCode()); + assertEquals(TOKENIZED_DEBTOR_FISCAL_CODE, captured.getEventData().getDebtorFiscalCode()); + assertNotNull(captured.getEventData().getCart()); + assertEquals(1, captured.getEventData().getCart().size()); + } + @Test @SneakyThrows void requestOnValidBizEventAndFailedReceiptWithoutEventDataShouldUpdateWithToken() { diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptTest.java index a87be3d7..dbb4cbe2 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptTest.java @@ -5,9 +5,12 @@ import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; import com.microsoft.azure.functions.OutputBinding; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartStatusType; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.ReasonError; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; @@ -24,8 +27,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; -import java.util.List; -import java.util.Optional; +import java.util.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -101,6 +103,39 @@ void recoverNotNotifiedReceiptSuccess() throws ReceiptNotFoundException { assertNull(captured.getReasonErrPayer()); } + @Test + void recoverNotNotifiedCartReceiptSuccess() throws ReceiptNotFoundException, CartNotFoundException { + Receipt receipt = buildReceipt(); + when(receiptCosmosServiceMock.getReceipt(EVENT_ID)).thenReturn(receipt); + + doAnswer((Answer) invocation -> { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + }).when(requestMock).createResponseBuilder(any(HttpStatus.class)); + + when(requestMock.getQueryParameters()).thenReturn(Collections.singletonMap("isCart","true")); + + when(receiptCosmosServiceMock.getCart(any())).thenReturn(generateCart()); + + // test execution + HttpResponseMessage response = sut.run(requestMock, EVENT_ID, documentReceipts, executionContextMock); + + // test assertion + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getBody()); + + verify(documentReceipts).setValue(receiptCaptor.capture()); + + assertEquals(1, receiptCaptor.getValue().size()); + Receipt captured = receiptCaptor.getValue().get(0); + assertEquals(ReceiptStatusType.GENERATED, captured.getStatus()); + assertEquals(EVENT_ID, captured.getEventId()); + assertEquals(0, captured.getNotificationNumRetry()); + assertNull(captured.getReasonErr()); + assertNull(captured.getReasonErrPayer()); + } + @Test void recoverReceiptFailForMissingEventId() { doAnswer((Answer) invocation -> { @@ -217,4 +252,14 @@ private Receipt buildReceipt() { .notifiedAt(0) .build(); } + + private CartForReceipt generateCart() { + CartForReceipt cart = new CartForReceipt(); + cart.setId("1"); + cart.setStatus(CartStatusType.FAILED); + cart.setTotalNotice(1); + cart.setCartPaymentId(new HashSet<>(new ArrayList<>( + List.of(new String[]{"eventId"})))); + return cart; + } } \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImplTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImplTest.java new file mode 100644 index 00000000..32965dbc --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/client/impl/CartReceiptsCosmosClientImplTest.java @@ -0,0 +1,116 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.client.impl; + +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.util.CosmosPagedIterable; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.cart.CartForReceipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.CartNotFoundException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Iterator; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static uk.org.webcompere.systemstubs.SystemStubs.withEnvironmentVariables; + +class CartReceiptsCosmosClientImplTest { + + @Test + void testSingletonConnectionError() throws Exception { + String mockKey = "mockKeymockKeymockKeymockKeymockKeymockKeymockKeymockKeymockKeymockKeymockKeymockKeyMK=="; + withEnvironmentVariables( + "COSMOS_RECEIPT_KEY", mockKey, + "COSMOS_RECEIPT_SERVICE_ENDPOINT", "" + ).execute(() -> Assertions.assertThrows(IllegalArgumentException.class, CartReceiptsCosmosClientImpl::getInstance) + ); + } + + @Test + void runOk_Cart() throws CartNotFoundException { + Long CART_ID = 1L; + + CosmosClient mockClient = mock(CosmosClient.class); + + CosmosDatabase mockDatabase = mock(CosmosDatabase.class); + CosmosContainer mockContainer = mock(CosmosContainer.class); + + CosmosPagedIterable mockIterable = mock(CosmosPagedIterable.class); + + Iterator mockIterator = mock(Iterator.class); + CartForReceipt cartForReceipt = new CartForReceipt(); + cartForReceipt.setId(CART_ID.toString()); + + when(mockIterator.hasNext()).thenReturn(true); + when(mockIterator.next()).thenReturn(cartForReceipt); + + when(mockIterable.iterator()).thenReturn(mockIterator); + + when(mockContainer.queryItems(anyString(), any(), eq(CartForReceipt.class))).thenReturn( + mockIterable + ); + when(mockDatabase.getContainer(any())).thenReturn(mockContainer); + when(mockClient.getDatabase(any())).thenReturn(mockDatabase); + + CartReceiptsCosmosClientImpl client = new CartReceiptsCosmosClientImpl(mockClient); + + Assertions.assertDoesNotThrow(() -> client.getCartItem(String.valueOf(CART_ID))); + + CartForReceipt cartResponse = client.getCartItem(String.valueOf(CART_ID)); + + Assertions.assertEquals(CART_ID.toString(), cartResponse.getId()); + + } + + @Test + void runKo_Cart() { + CosmosClient mockClient = mock(CosmosClient.class); + + CosmosDatabase mockDatabase = mock(CosmosDatabase.class); + CosmosContainer mockContainer = mock(CosmosContainer.class); + + CosmosPagedIterable mockIterable = mock(CosmosPagedIterable.class); + + Iterator mockIterator = mock(Iterator.class); + + when(mockIterator.hasNext()).thenReturn(false); + + when(mockIterable.iterator()).thenReturn(mockIterator); + + when(mockContainer.queryItems(anyString(), any(), eq(CartForReceipt.class))).thenReturn( + mockIterable + ); + when(mockDatabase.getContainer(any())).thenReturn(mockContainer); + when(mockClient.getDatabase(any())).thenReturn(mockDatabase); + + CartReceiptsCosmosClientImpl client = new CartReceiptsCosmosClientImpl(mockClient); + + Assertions.assertThrows(CartNotFoundException.class, () -> client.getCartItem("an invalid receipt id")); + } + + @Test + void runOk_SaveCart() throws CartNotFoundException { + Long CART_ID = 1L; + + CosmosClient mockClient = mock(CosmosClient.class); + + CosmosDatabase mockDatabase = mock(CosmosDatabase.class); + CosmosContainer mockContainer = mock(CosmosContainer.class); + + CartForReceipt cartForReceipt = new CartForReceipt(); + + cartForReceipt.setId(CART_ID.toString()); + + when(mockDatabase.getContainer(any())).thenReturn(mockContainer); + when(mockClient.getDatabase(any())).thenReturn(mockDatabase); + + CartReceiptsCosmosClientImpl client = new CartReceiptsCosmosClientImpl(mockClient); + + Assertions.assertDoesNotThrow(() -> client.saveCart(cartForReceipt)); + + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImplTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImplTest.java new file mode 100644 index 00000000..673adec0 --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BizEventToReceiptServiceImplTest.java @@ -0,0 +1,59 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.service.impl; + +import com.azure.cosmos.models.FeedResponse; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptQueueClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; +import it.gov.pagopa.receipt.pdf.helpdesk.service.PDVTokenizerServiceRetryWrapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith({MockitoExtension.class, SystemStubsExtension.class}) +@MockitoSettings(strictness = Strictness.LENIENT) +public class BizEventToReceiptServiceImplTest { + + private BizEventToReceiptServiceImpl bizEventToReceiptService; + @Mock + private PDVTokenizerServiceRetryWrapper pdvTokenizerServiceMock; + @Mock + private ReceiptCosmosClientImpl receiptCosmosClient; + @Mock + private BizEventCosmosClient bizEventCosmosClientMock; + @Mock + private ReceiptQueueClientImpl queueClient; + + + @BeforeEach + public void init() { + bizEventToReceiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, + queueClient, + bizEventCosmosClientMock, + receiptCosmosClient + ); + } + + @Test + public void run_OK_getCartBizEvents() { + FeedResponse feedResponseMock = mock(FeedResponse.class); + when(feedResponseMock.getResults()).thenReturn(Collections.singletonList(new BizEvent())); + doReturn(Collections.singletonList(feedResponseMock)).when(bizEventCosmosClientMock) + .getAllBizEventDocument(Mockito.eq("1"), any(), any()); + assertDoesNotThrow(() -> bizEventToReceiptService.getCartBizEvents("1")); + } + +} diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImplTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImplTest.java index 9e59a1f3..1039b391 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImplTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/BuildTemplateServiceImplTest.java @@ -12,9 +12,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.*; @@ -77,10 +77,13 @@ class BuildTemplateServiceImplTest { private static final String NOT_PAGO_PA_CHANNEL = "NOT_PAGO_PA_CHANNEL"; private static final String ID_PA = "idPa"; private static final String USER_NAME = "user_name"; - private static final String USER_SURNAME = "user_surname"; + private static final String USER_SURNAME = "user_surname"; private static final String USER_FORMATTED_FULL_NAME = "user_name user_surname"; private static final String USER_TAX_CODE = "user tax code"; public static final String PAGOPA_PA_CHANNEL_ID = "pagopa channel"; + public static final String RECEIPT_ID = "receipt-id"; + public static final String BIZ_EVENT = "bizEvent"; + public static final String RECEIPT = "receipt"; private BuildTemplateServiceImpl buildTemplateService; @BeforeEach @@ -94,7 +97,7 @@ void setUp() throws Exception { @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannel() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -142,11 +145,12 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannel() { .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build() + ); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -189,7 +193,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannel() { @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTWinter() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -237,11 +241,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTWinte .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -284,7 +288,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTWinte @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTSummer() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -332,11 +336,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTSumme .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -379,7 +383,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedDSTSumme @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMillisecondsDSTWinter() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -427,11 +431,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMill .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -474,7 +478,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMill @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMillisecondsDSTSummer() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -522,11 +526,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMill .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -569,7 +573,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndIOChannelAndDateZonedWithMill @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnTransactionOrigin() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -617,11 +621,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnTransactionOri .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -664,7 +668,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnTransactionOri @Test void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnChannelId() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -712,11 +716,11 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnChannelId() { .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).amount(FORMATTED_GRAND_TOTAL).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -759,7 +763,7 @@ void mapTemplateAllFieldsSuccessCompleteTemplateAndPagoPaChannelOnChannelId() { @Test void mapTemplateAllFieldsSuccessPartialTemplateAndNotPagoPaChannel() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() .noticeNumber(NOTICE_NUMBER) @@ -787,11 +791,11 @@ void mapTemplateAllFieldsSuccessPartialTemplateAndNotPagoPaChannel() { .IUR(IUR) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_AMOUNT).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -835,7 +839,7 @@ void mapTemplateAllFieldsSuccessPartialTemplateAndNotPagoPaChannel() { @Test void mapTemplateWithoutTransactionDetailsSuccess() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() .iuv(IUV) @@ -863,11 +867,11 @@ void mapTemplateWithoutTransactionDetailsSuccess() { .IUR(IUR) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_AMOUNT).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -910,7 +914,7 @@ void mapTemplateWithoutTransactionDetailsSuccess() { @Test void mapTemplateWithoutTransactionDetailsAndPaymentTokenSuccess() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() .iuv(IUV) @@ -937,11 +941,11 @@ void mapTemplateWithoutTransactionDetailsAndPaymentTokenSuccess() { .IUR(IUR) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_AMOUNT).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -983,7 +987,7 @@ void mapTemplateWithoutTransactionDetailsAndPaymentTokenSuccess() { @Test void mapTemplateAllFieldsSuccessDebtorFullNameEmpty() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -1031,11 +1035,11 @@ void mapTemplateAllFieldsSuccessDebtorFullNameEmpty() { .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -1078,7 +1082,7 @@ void mapTemplateAllFieldsSuccessDebtorFullNameEmpty() { @Test void mapTemplateAllFieldsSuccessDebtorFullNameWithSpecialChar() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -1126,11 +1130,11 @@ void mapTemplateAllFieldsSuccessDebtorFullNameWithSpecialChar() { .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -1173,7 +1177,7 @@ void mapTemplateAllFieldsSuccessDebtorFullNameWithSpecialChar() { @Test void mapTemplateAllFieldsSuccessDebtorFullNameEqualsFiscalCode() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .idPaymentManager(BIZ_EVENT_ID) .debtorPosition(DebtorPosition.builder() @@ -1221,11 +1225,11 @@ void mapTemplateAllFieldsSuccessDebtorFullNameEqualsFiscalCode() { .build()) .build()) .eventStatus(BizEventStatusType.DONE) - .build(); - Receipt receipt = Receipt.builder().eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); AtomicReference atomicReference = new AtomicReference<>(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_DEBTOR, receipt))); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); @@ -1268,7 +1272,7 @@ void mapTemplateAllFieldsSuccessDebtorFullNameEqualsFiscalCode() { @Test void mapTemplateLeastAmountOfInfoSuccessPayer() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1294,16 +1298,14 @@ void mapTemplateLeastAmountOfInfoSuccessPayer() { .creditor(Creditor.builder() .idPA(ID_PA) .build()) - .build(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, - Receipt.builder().eventData(eventData).build())); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, receipt)); } @Test void mapTemplateLeastAmountOfInfoSuccessDebtor() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1325,16 +1327,14 @@ void mapTemplateLeastAmountOfInfoSuccessDebtor() { .creditor(Creditor.builder() .idPA(ID_PA) .build()) - .build(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> buildTemplateService.buildTemplate( - event, GENERATED_BY_DEBTOR, Receipt.builder().eventData(eventData).build())); + .build()); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt)); } @Test void mapTemplateSuccessRequestByDebtorTrueWithoutPayerAndUserFiscalCode() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1362,12 +1362,10 @@ void mapTemplateSuccessRequestByDebtorTrueWithoutPayerAndUserFiscalCode() { ) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate( - event, GENERATED_BY_DEBTOR, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertTrue(receiptPDFTemplate.getTransaction().isRequestedByDebtor()); @@ -1375,7 +1373,7 @@ void mapTemplateSuccessRequestByDebtorTrueWithoutPayerAndUserFiscalCode() { @Test void mapTemplateSuccessRequestByDebtorTrueWithPayerFiscalCodeDifferent() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1406,12 +1404,10 @@ void mapTemplateSuccessRequestByDebtorTrueWithPayerFiscalCodeDifferent() { ) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate( - event, GENERATED_BY_DEBTOR, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertTrue(receiptPDFTemplate.getTransaction().isRequestedByDebtor()); @@ -1419,7 +1415,7 @@ void mapTemplateSuccessRequestByDebtorTrueWithPayerFiscalCodeDifferent() { @Test void mapTemplateSuccessRequestByDebtorTrueWithUserFiscalCodeDifferent() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1448,12 +1444,10 @@ void mapTemplateSuccessRequestByDebtorTrueWithUserFiscalCodeDifferent() { .user(User.builder().fiscalCode(PAYER_VALID_CF).build()) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, - GENERATED_BY_DEBTOR, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertTrue(receiptPDFTemplate.getTransaction().isRequestedByDebtor()); @@ -1461,7 +1455,7 @@ void mapTemplateSuccessRequestByDebtorTrueWithUserFiscalCodeDifferent() { @Test void mapTemplateSuccessRequestByDebtorFalseWithPayerAndUserFiscalCodeEqual() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1494,12 +1488,10 @@ void mapTemplateSuccessRequestByDebtorFalseWithPayerAndUserFiscalCodeEqual() { .user(User.builder().fiscalCode(DEBTOR_VALID_CF).build()) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate( - event, GENERATED_BY_DEBTOR, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertFalse(receiptPDFTemplate.getTransaction().isRequestedByDebtor()); @@ -1507,7 +1499,7 @@ void mapTemplateSuccessRequestByDebtorFalseWithPayerAndUserFiscalCodeEqual() { @Test void mapTemplateSuccessRequestByDebtorFalseWhenGeneratedByPayer() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1539,12 +1531,10 @@ void mapTemplateSuccessRequestByDebtorFalseWhenGeneratedByPayer() { ) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, - Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertFalse(receiptPDFTemplate.getTransaction().isRequestedByDebtor()); @@ -1552,7 +1542,7 @@ void mapTemplateSuccessRequestByDebtorFalseWhenGeneratedByPayer() { @Test void mapTemplateSuccessWithUserNameAndSurname() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1587,12 +1577,10 @@ void mapTemplateSuccessWithUserNameAndSurname() { .build()) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate - (event, GENERATED_BY_PAYER, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertEquals(USER_FORMATTED_FULL_NAME, receiptPDFTemplate.getUser().getData().getFullName()); @@ -1600,7 +1588,7 @@ void mapTemplateSuccessWithUserNameAndSurname() { @Test void mapTemplateSuccessWithUserTaxCodeFromTransaction() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1636,12 +1624,10 @@ void mapTemplateSuccessWithUserTaxCodeFromTransaction() { .build()) .build() ) - .build(); + .build()); AtomicReference atomicReference = new AtomicReference<>(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); - assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate( - event, GENERATED_BY_PAYER, Receipt.builder().eventData(eventData).build()))); + Receipt receipt = Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).amount(FORMATTED_GRAND_TOTAL).build()).build(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, receipt))); ReceiptPDFTemplate receiptPDFTemplate = atomicReference.get(); assertEquals(USER_TAX_CODE, receiptPDFTemplate.getUser().getData().getTaxCode()); @@ -1649,56 +1635,56 @@ void mapTemplateSuccessWithUserTaxCodeFromTransaction() { @Test void mapTemplateNoServiceCustomerIdError() { - BizEvent event = new BizEvent(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + List bizEventList = Collections.singletonList(new BizEvent()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.SERVICE_CUSTOMER_ID), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, RECEIPT, TemplateDataField.SERVICE_CUSTOMER_ID, RECEIPT, null), e.getMessage()); } @Test void mapTemplateNoTransactionTimestampError() { - BizEvent event = BizEvent.builder().id(BIZ_EVENT_ID).paymentInfo(PaymentInfo.builder().IUR(IUR).build()).build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + List bizEventList = Collections.singletonList(BizEvent.builder().id(BIZ_EVENT_ID).paymentInfo(PaymentInfo.builder().IUR(IUR).build()).build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_TIMESTAMP), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT, TemplateDataField.TRANSACTION_TIMESTAMP, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoTransactionAmountError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) .paymentDateTime(DATE_TIME_TIMESTAMP_MILLISECONDS_DST_WINTER) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_AMOUNT), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, RECEIPT,TemplateDataField.TRANSACTION_AMOUNT, RECEIPT,RECEIPT_ID), e.getMessage()); } @Test void mapTemplateNoPspError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) .paymentDateTime(DATE_TIME_TIMESTAMP_MILLISECONDS_DST_WINTER) .amount(AMOUNT_WITHOUT_CENTS) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspNameError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1708,16 +1694,16 @@ void mapTemplateNoPspNameError() { .psp(Psp.builder() .idPsp("noName") .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_NAME), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_NAME, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspCompanyNameError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1728,16 +1714,16 @@ void mapTemplateNoPspCompanyNameError() { .idPsp("noCompanyName") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_COMPANY_NAME), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_COMPANY_NAME, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspAddressError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1748,16 +1734,18 @@ void mapTemplateNoPspAddressError() { .idPsp("noAddress") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_ADDRESS), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, + + BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_ADDRESS, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspCityError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1768,16 +1756,16 @@ void mapTemplateNoPspCityError() { .idPsp("noCity") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_CITY), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_CITY, BIZ_EVENT, BIZ_EVENT_ID ), e.getMessage()); } @Test void mapTemplateNoPspProvinceError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1788,16 +1776,16 @@ void mapTemplateNoPspProvinceError() { .idPsp("noProvince") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_PROVINCE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_PROVINCE, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspBuildingNumberError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1808,16 +1796,16 @@ void mapTemplateNoPspBuildingNumberError() { .idPsp("noBuildingNumber") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_BUILDING_NUMBER), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_BUILDING_NUMBER, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspPostalCodeError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1828,16 +1816,16 @@ void mapTemplateNoPspPostalCodeError() { .idPsp("noPostalCode") .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_POSTAL_CODE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_PSP_POSTAL_CODE, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoPspLogoError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1853,16 +1841,16 @@ void mapTemplateNoPspLogoError() { .fee(FEE_LONG) .build()) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_PSP_LOGO), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT, TemplateDataField.TRANSACTION_PSP_LOGO, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoRrnError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .paymentDateTime(DATE_TIME_TIMESTAMP_MILLISECONDS_DST_WINTER) @@ -1877,16 +1865,16 @@ void mapTemplateNoRrnError() { .idTransaction(ID_TRANSACTION) .build()) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.TRANSACTION_RRN), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.TRANSACTION_RRN, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoUserDataFullNameError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1897,16 +1885,16 @@ void mapTemplateNoUserDataFullNameError() { .idPsp(ID_PSP) .psp(PSP_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.USER_DATA_FULL_NAME), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.USER_DATA_FULL_NAME, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoUserDataTaxCodeError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1920,16 +1908,16 @@ void mapTemplateNoUserDataTaxCodeError() { .payer(Payer.builder() .fullName(PAYER_FULL_NAME) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.USER_DATA_TAX_CODE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.USER_DATA_TAX_CODE, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoCartItemRefNumberTypeError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1944,16 +1932,16 @@ void mapTemplateNoCartItemRefNumberTypeError() { .fullName(PAYER_FULL_NAME) .entityUniqueIdentifierValue(PAYER_VALID_CF) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_REF_NUMBER_TYPE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_REF_NUMBER_TYPE, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoCartItemRefNumberValueIUVError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1971,16 +1959,16 @@ void mapTemplateNoCartItemRefNumberValueIUVError() { .debtorPosition(DebtorPosition.builder() .modelType(MODEL_TYPE_IUV_CODE) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_REF_NUMBER_VALUE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_REF_NUMBER_VALUE, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateWrongModelTypeError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -1999,16 +1987,16 @@ void mapTemplateWrongModelTypeError() { .iuv(IUV) .modelType(MODEL_TYPE_NOTICE_CODE) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_REF_NUMBER_VALUE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_REF_NUMBER_VALUE, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoCartItemDebtorTaxCodeValueError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -2027,17 +2015,17 @@ void mapTemplateNoCartItemDebtorTaxCodeValueError() { .modelType(MODEL_TYPE_IUV_CODE) .iuv(IUV) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, - Receipt.builder().eventData(EventData.builder().debtorFiscalCode("DEBTOR_FC").build()).build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, + Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).debtorFiscalCode(DEBTOR_VALID_CF).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_DEBTOR_TAX_CODE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_DEBTOR_TAX_CODE, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoCartItemPayeeTaxCodeValueError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -2059,17 +2047,17 @@ void mapTemplateNoCartItemPayeeTaxCodeValueError() { .debtor(Debtor.builder() .entityUniqueIdentifierValue(DEBTOR_VALID_CF) .build()) - .build(); - TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, - Receipt.builder().eventData(EventData.builder().debtorFiscalCode("DEBTOR_FC").build()).build())); + .build()); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData( + EventData.builder().amount(FORMATTED_GRAND_TOTAL).debtorFiscalCode(DEBTOR_VALID_CF).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_PAYEE_TAX_CODE), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_PAYEE_TAX_CODE, BIZ_EVENT,BIZ_EVENT_ID), e.getMessage()); } @Test void mapTemplateNoCartItemAmountValueError() { - BizEvent event = BizEvent.builder() + List bizEventList = Collections.singletonList(BizEvent.builder() .id(BIZ_EVENT_ID) .paymentInfo(PaymentInfo.builder() .IUR(IUR) @@ -2101,13 +2089,172 @@ void mapTemplateNoCartItemAmountValueError() { ) .build() ) - .build(); - EventData eventData = EventData.builder().cart(Collections.singletonList( - CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build(); + .build()); + Receipt receipt = Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(List.of(CartItem.builder().subject(REMITTANCE_INFORMATION).build())).build()).build(); + TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_PAYER, receipt)); + + assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, BIZ_EVENT,TemplateDataField.CART_ITEM_AMOUNT, BIZ_EVENT, BIZ_EVENT_ID), e.getMessage()); + } + + @Test + void mapTemplateNoCartItemSubjectError() { + List listOfBizEvents = Collections.singletonList(BizEvent.builder() + .id(BIZ_EVENT_ID) + .paymentInfo(PaymentInfo.builder() + .IUR(IUR) + .paymentDateTime(DATE_TIME_TIMESTAMP_MILLISECONDS_DST_WINTER) + .remittanceInformation(REMITTANCE_INFORMATION) + .build()) + .psp(Psp.builder() + .idPsp(ID_PSP) + .psp(PSP_NAME) + .build()) + .payer(Payer.builder() + .fullName(PAYER_FULL_NAME) + .entityUniqueIdentifierValue(PAYER_VALID_CF) + .build()) + .debtorPosition(DebtorPosition.builder() + .modelType(MODEL_TYPE_IUV_CODE) + .iuv(IUV) + .build()) + .debtor(Debtor.builder() + .entityUniqueIdentifierValue(DEBTOR_VALID_CF) + .build()) + .creditor(Creditor.builder() + .companyName(COMPANY_NAME) + .idPA(ID_PA) + .build()) + .transactionDetails(TransactionDetails.builder() + .transaction(Transaction.builder() + .grandTotal(GRAND_TOTAL_LONG).build() + ) + .build() + ) + .build()); TemplateDataMappingException e = assertThrows(TemplateDataMappingException.class, () -> - buildTemplateService.buildTemplate(event, GENERATED_BY_PAYER, Receipt.builder().eventData(eventData).build())); + buildTemplateService.buildTemplate(listOfBizEvents, GENERATED_BY_PAYER, Receipt.builder().id(RECEIPT_ID).eventId(BIZ_EVENT_ID).eventData( + EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(Collections.singletonList(CartItem.builder().build())) + .debtorFiscalCode(DEBTOR_VALID_CF).build()).build())); assertEquals(ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode(), e.getStatusCode()); - assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, TemplateDataField.CART_ITEM_AMOUNT), e.getMessage()); + assertEquals(String.format(TemplateDataField.ERROR_MAPPING_MESSAGE, RECEIPT, TemplateDataField.CART_ITEM_SUBJECT, RECEIPT,RECEIPT_ID), e.getMessage()); + } + + @Test + void mapTemplateAllFieldsSuccessMultipleBizEvents() { + List bizEventList = new ArrayList<>(); + List cartItemList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + bizEventList.add( + BizEvent.builder() + .id(BIZ_EVENT_ID + i) + .idPaymentManager(BIZ_EVENT_ID) + .debtorPosition(DebtorPosition.builder() + .iuv(IUV+i) + .modelType(MODEL_TYPE_IUV_CODE) + .build()) + .creditor(Creditor.builder() + .companyName(COMPANY_NAME) + .idPA(ID_PA) + .build()) + .psp(Psp.builder() + .idPsp(ID_PSP) + .psp(PSP_NAME) + .build()) + .debtor(Debtor.builder() + .fullName(DEBTOR_FULL_NAME) + .entityUniqueIdentifierValue(DEBTOR_VALID_CF) + .build()) + .payer(Payer.builder().fullName(PAYER_FULL_NAME).entityUniqueIdentifierValue(PAYER_VALID_CF).build()) + .paymentInfo(PaymentInfo.builder() + .paymentDateTime(DATE_TIME_TIMESTAMP_MILLISECONDS_DST_WINTER) + .paymentToken(PAYMENT_TOKEN) + .amount(AMOUNT_WITHOUT_CENTS) + .fee(FEE_WITH_SINGLE_DIGIT_CENTS) + .remittanceInformation(REMITTANCE_INFORMATION) + .IUR(IUR) + .build()) + .transactionDetails(TransactionDetails.builder() + .wallet(WalletItem.builder() + .info(Info.builder().brand(BRAND).holder(HOLDER_FULL_NAME).build()) + .onboardingChannel(PAGO_PA_CHANNEL_IO) + .build()) + .transaction(Transaction.builder() + .idTransaction(ID_TRANSACTION) + .grandTotal(GRAND_TOTAL_LONG) + .amount(AMOUNT_LONG) + .fee(FEE_LONG) + .rrn(RRN) + .numAut(AUTH_CODE) + .creationDate(DATE_TIME_TIMESTAMP_ZONED_DST_WINTER) + .psp(TransactionPsp.builder() + .businessName(PSP_NAME) + .build()) + .origin(PAGOPA_PA_CHANNEL_ID) + .build()) + .build()) + .eventStatus(BizEventStatusType.DONE) + .build() + ); + + cartItemList.add( + CartItem.builder().subject(REMITTANCE_INFORMATION + i).build() + ); + } + Receipt receipt = Receipt.builder().eventId(String.valueOf(ID_TRANSACTION)).eventData(EventData.builder().amount(FORMATTED_GRAND_TOTAL).cart(cartItemList).build()).build(); + + AtomicReference atomicReference = new AtomicReference<>(); + assertDoesNotThrow(() -> atomicReference.set(buildTemplateService.buildTemplate(bizEventList, GENERATED_BY_DEBTOR, receipt))); + + ReceiptPDFTemplate receiptPdfTemplate = atomicReference.get(); + + assertNotNull(receiptPdfTemplate); + assertEquals(String.valueOf(ID_TRANSACTION), receiptPdfTemplate.getServiceCustomerId()); + + it.gov.pagopa.receipt.pdf.helpdesk.model.template.Transaction transaction = receiptPdfTemplate.getTransaction(); + assertEquals(DATE_TIME_TIMESTAMP_FORMATTED_DST_WINTER, transaction.getTimestamp()); + assertEquals(FORMATTED_GRAND_TOTAL, transaction.getAmount()); + assertEquals(PSP_LOGO, transaction.getPsp().getLogo()); + assertEquals(FORMATTED_FEE, transaction.getPsp().getFee().getAmount()); + assertEquals(PSP_NAME, transaction.getPsp().getName()); + assertEquals(PSP_CITY, transaction.getPsp().getCity()); + assertEquals(PSP_COMPANY, transaction.getPsp().getCompanyName()); + assertEquals(PSP_POSTAL_CODE, transaction.getPsp().getPostalCode()); + assertEquals(PSP_ADDRESS, transaction.getPsp().getAddress()); + assertEquals(PSP_BUILDING_NUMBER, transaction.getPsp().getBuildingNumber()); + assertEquals(PSP_PROVINCE, transaction.getPsp().getProvince()); + assertEquals(RRN, transaction.getRrn()); + assertEquals(BRAND, transaction.getPaymentMethod().getName()); + assertEquals(BRAND_ASSET_URL, transaction.getPaymentMethod().getLogo()); + assertEquals(HOLDER_FULL_NAME, transaction.getPaymentMethod().getAccountHolder()); + assertEquals(AUTH_CODE, transaction.getAuthCode()); + assertEquals(GENERATED_BY_DEBTOR, transaction.isRequestedByDebtor()); + assertTrue(transaction.isProcessedByPagoPA()); + + assertNull(receiptPdfTemplate.getUser()); + + it.gov.pagopa.receipt.pdf.helpdesk.model.template.Cart cart = receiptPdfTemplate.getCart(); + String decurrenciedFormattedAmount = FORMATTED_AMOUNT.replace(".", "").replace(",", "."); + assertEquals(currencyFormat(String.valueOf(Double.parseDouble(decurrenciedFormattedAmount)*bizEventList.size())), cart.getAmountPartial()); + + for (int i = 0; i < bizEventList.size(); i++) { + assertEquals(FORMATTED_AMOUNT, cart.getItems().get(i).getAmount()); + assertEquals(DEBTOR_FULL_NAME, cart.getItems().get(i).getDebtor().getFullName()); + assertEquals(DEBTOR_VALID_CF, cart.getItems().get(i).getDebtor().getTaxCode()); + assertEquals(REMITTANCE_INFORMATION+i, cart.getItems().get(i).getSubject()); + assertEquals(COMPANY_NAME, cart.getItems().get(i).getPayee().getName()); + assertEquals(ID_PA, cart.getItems().get(i).getPayee().getTaxCode()); + assertEquals(MODEL_TYPE_IUV_TEXT, cart.getItems().get(i).getRefNumber().getType()); + assertEquals(IUV+i, cart.getItems().get(i).getRefNumber().getValue()); + } + } + + private String currencyFormat(String value) { + BigDecimal valueToFormat = new BigDecimal(value); + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ITALY); + numberFormat.setMaximumFractionDigits(2); + numberFormat.setMinimumFractionDigits(2); + return numberFormat.format(valueToFormat); } } \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImplTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImplTest.java index 9bb2ecb0..beaf685e 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImplTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/service/impl/GenerateReceiptPdfServiceImplTest.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import static it.gov.pagopa.receipt.pdf.helpdesk.service.impl.GenerateReceiptPdfServiceImpl.ALREADY_CREATED; import static org.apache.http.HttpStatus.SC_OK; @@ -99,7 +100,7 @@ void generateReceiptsPayerNullWithSuccess() throws Exception { doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); @@ -127,7 +128,7 @@ void generateReceiptsSameDebtorPayerWithSuccess() throws Exception { doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); @@ -157,7 +158,8 @@ void generateReceiptsDifferentDebtorPayerWithSuccess() throws Exception { doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); + assertNotNull(pdfGeneration); assertFalse(pdfGeneration.isGenerateOnlyDebtor()); @@ -187,7 +189,7 @@ void generateReceiptsPayerNullFailPDFEngineCallReturn500() throws Exception { doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); @@ -211,7 +213,7 @@ void generateReceiptsPayerNullFailBuildTemplateData() throws Exception { doThrow(new TemplateDataMappingException("error message", ReasonErrorCode.ERROR_TEMPLATE_PDF.getCode())) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); @@ -238,7 +240,7 @@ void generateReceiptsPayerNullFailSaveToBlobStorageThrowsException() throws Exce doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); @@ -266,7 +268,7 @@ void generateReceiptsPayerNullFailSaveToBlobStorageReturn500() throws Exception doReturn(new ReceiptPDFTemplate()) .when(buildTemplateServiceMock).buildTemplate(any(), anyBoolean(), any()); - PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, bizEventOnly,Path.of("/tmp")); + PdfGeneration pdfGeneration = sut.generateReceipts(receiptOnly, Collections.singletonList(bizEventOnly),Path.of("/tmp")); assertNotNull(pdfGeneration); assertTrue(pdfGeneration.isGenerateOnlyDebtor()); diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtilsTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtilsTest.java index 61d2c29f..51442181 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtilsTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtilsTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.microsoft.azure.functions.HttpStatus; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.ReceiptQueueClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.*; @@ -48,7 +49,8 @@ void createReceiptSuccessWithPaymentInfo() throws PDVTokenizerException, JsonPro when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)).thenReturn(TOKENIZED_DEBTOR_FISCAL_CODE); when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(PAYER_FISCAL_CODE)).thenReturn(TOKENIZED_PAYER_FISCAL_CODE); - BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl(pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class)); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class), mock(BizEventCosmosClientImpl.class), mock(ReceiptCosmosClientImpl.class)); Receipt receipt = BizEventToReceiptUtils.createReceipt(generateValidBizEvent(false,false), receiptService, logger); @@ -64,7 +66,8 @@ void createReceiptSuccessWithoutPaymentInfoButWithTransferList() throws PDVToken when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)).thenReturn(TOKENIZED_DEBTOR_FISCAL_CODE); when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(PAYER_FISCAL_CODE)).thenReturn(TOKENIZED_PAYER_FISCAL_CODE); - BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl(pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class)); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class), mock(BizEventCosmosClientImpl.class), mock(ReceiptCosmosClientImpl.class)); Receipt receipt = BizEventToReceiptUtils.createReceipt(generateValidBizEvent(false,true), receiptService, logger); @@ -80,7 +83,8 @@ void createReceiptSuccessWithoutRemittanceInformation() throws PDVTokenizerExcep when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)).thenReturn(TOKENIZED_DEBTOR_FISCAL_CODE); when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(PAYER_FISCAL_CODE)).thenReturn(TOKENIZED_PAYER_FISCAL_CODE); - BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl(pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class)); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class), mock(BizEventCosmosClientImpl.class), mock(ReceiptCosmosClientImpl.class)); Receipt receipt = BizEventToReceiptUtils.createReceipt(generateValidBizEvent(true,false), receiptService, logger); @@ -95,7 +99,8 @@ void createReceiptSuccessWithoutRemittanceInformation() throws PDVTokenizerExcep void createReceiptSuccessWithTokenizerFailed() throws PDVTokenizerException, JsonProcessingException { when(pdvTokenizerServiceMock.generateTokenForFiscalCodeWithRetry(DEBTOR_FISCAL_CODE)).thenThrow(new PDVTokenizerException("exception", HttpStatus.I_AM_A_TEAPOT.value())); - BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl(pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class)); + BizEventToReceiptServiceImpl receiptService = new BizEventToReceiptServiceImpl( + pdvTokenizerServiceMock, mock(ReceiptQueueClientImpl.class), mock(BizEventCosmosClientImpl.class), mock(ReceiptCosmosClientImpl.class)); Receipt receipt = BizEventToReceiptUtils.createReceipt(generateValidBizEvent(false,false), receiptService, logger);