Skip to content

Commit

Permalink
Merge pull request #91 from pagopa/PRDP-258-add-receipt-status-TO_REVIEW
Browse files Browse the repository at this point in the history
[PRDP-258] Added new Receipt status TO_REVIEW
  • Loading branch information
pasqualespica authored Nov 30, 2023
2 parents 62a4f9e + 8ad5ed2 commit 5622a29
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 93 deletions.
4 changes: 3 additions & 1 deletion integration-test/src/features/receipt_pdf_datastore.feature
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ Feature: All about payment events consumed by Azure functions receipt-pdf-genera
And the receipt has not the status "INSERTED"
And the blob storage has the PDF document

Scenario: a biz event enqueued on receipts poison queue is stored on receipt-message-error datastore
Scenario: a biz event enqueued on receipts poison queue is stored on receipt-message-error datastore and the receipt status is updated to TO_REVIEW
Given a random biz event with id "receipt-generator-int-test-id-3" enqueued on receipts poison queue with poison retry "true"
When the biz event has been properly stored on receipt-message-error datastore after 20000 ms
Then the receipt-message-error datastore returns the error receipt
And the error receipt has the status "TO_REVIEW"
And the receipts datastore returns the updated receipt
And the receipt has the status "TO_REVIEW"

Scenario: a biz event stored on receipt-message-error is enqueued on receipt queue that trigger the PDF receipt generation
Given a receipt with id "receipt-generator-int-test-id-4" stored into receipt datastore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ Then('the receipt has not the status {string}', function (targetStatus) {
assert.notStrictEqual(this.responseToCheck.resources[0].status, targetStatus);
});

Then('the receipt has the status {string}', function (targetStatus) {
assert.strictEqual(this.responseToCheck.resources[0].status, targetStatus);
});

Then('the receipts datastore returns the updated receipt', async function(){
this.responseToCheck = await getDocumentByIdFromReceiptsDatastore(this.eventId);
})

Then('the blob storage has the PDF document', async function () {
let blobExist = await receiptPDFExist(this.responseToCheck.resources[0].mdAttach.name);
assert.strictEqual(true, blobExist);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ async function deleteDocumentFromReceiptsDatastoreByEventId(eventId){
}

async function createDocumentInReceiptsDatastore(id) {
let event = createReceipt(id);
let receipt = createReceipt(id);
try {
return await receiptContainer.items.create(event);
return await receiptContainer.items.create(receipt);
} catch (err) {
console.log(err);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.QueueOutput;
import com.microsoft.azure.functions.annotation.QueueTrigger;
import it.gov.pagopa.receipt.pdf.generator.client.ReceiptCosmosClient;
import it.gov.pagopa.receipt.pdf.generator.client.impl.ReceiptCosmosClientImpl;
import it.gov.pagopa.receipt.pdf.generator.entity.event.BizEvent;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.ReasonError;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.Receipt;
Expand All @@ -18,7 +16,9 @@
import it.gov.pagopa.receipt.pdf.generator.exception.ReceiptNotFoundException;
import it.gov.pagopa.receipt.pdf.generator.model.PdfGeneration;
import it.gov.pagopa.receipt.pdf.generator.service.GenerateReceiptPdfService;
import it.gov.pagopa.receipt.pdf.generator.service.ReceiptCosmosService;
import it.gov.pagopa.receipt.pdf.generator.service.impl.GenerateReceiptPdfServiceImpl;
import it.gov.pagopa.receipt.pdf.generator.service.impl.ReceiptCosmosServiceImpl;
import it.gov.pagopa.receipt.pdf.generator.utils.ObjectMapperUtils;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpStatus;
Expand Down Expand Up @@ -48,16 +48,16 @@ public class GenerateReceiptPdf {
private static final String PATTERN_FORMAT = "yyyy.MM.dd.HH.mm.ss";

private final GenerateReceiptPdfService generateReceiptPdfService;
private final ReceiptCosmosClient receiptCosmosClient;
private final ReceiptCosmosService receiptCosmosService;

public GenerateReceiptPdf() {
this.generateReceiptPdfService = new GenerateReceiptPdfServiceImpl();
this.receiptCosmosClient = ReceiptCosmosClientImpl.getInstance();
this.receiptCosmosService = new ReceiptCosmosServiceImpl();
}

GenerateReceiptPdf(GenerateReceiptPdfService generateReceiptPdfService, ReceiptCosmosClient receiptCosmosClient) {
GenerateReceiptPdf(GenerateReceiptPdfService generateReceiptPdfService, ReceiptCosmosService receiptCosmosService) {
this.generateReceiptPdfService = generateReceiptPdfService;
this.receiptCosmosClient = receiptCosmosClient;
this.receiptCosmosService = receiptCosmosService;
}

/**
Expand Down Expand Up @@ -123,7 +123,7 @@ public void processGenerateReceipt(
context.getFunctionName(), LocalDateTime.now(), bizEvent.getId());

//Retrieve receipt's data from CosmosDB
Receipt receipt = getReceipt(context, bizEvent);
Receipt receipt = this.receiptCosmosService.getReceipt(bizEvent.getId());

//Verify receipt status
if (isReceiptInInValidState(receipt)) {
Expand Down Expand Up @@ -205,25 +205,6 @@ private boolean isReceiptInInValidState(Receipt receipt) {
|| (!receipt.getStatus().equals(ReceiptStatusType.INSERTED) && !receipt.getStatus().equals(ReceiptStatusType.RETRY));
}

private Receipt getReceipt(ExecutionContext context, BizEvent bizEvent) throws ReceiptNotFoundException {
Receipt receipt;
//Retrieve receipt from CosmosDB
try {
receipt = receiptCosmosClient.getReceiptDocument(bizEvent.getId());
} catch (ReceiptNotFoundException e) {
String errorMsg = String.format("[%s] Receipt not found with the biz-event id %s",
context.getFunctionName(), bizEvent.getId());
throw new ReceiptNotFoundException(errorMsg, e);
}

if (receipt == null) {
String errorMsg = "[{}] Receipt retrieved with the biz-event id {} is null";
logger.error(errorMsg, context.getFunctionName(), bizEvent.getId());
throw new ReceiptNotFoundException(errorMsg);
}
return receipt;
}

private BizEvent getBizEventFromMessage(ExecutionContext context, String bizEventMessage) throws BizEventNotValidException {
try {
return ObjectMapperUtils.mapString(bizEventMessage, BizEvent.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
import com.microsoft.azure.functions.annotation.CosmosDBOutput;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.QueueTrigger;
import it.gov.pagopa.receipt.pdf.generator.client.ReceiptQueueClient;
import it.gov.pagopa.receipt.pdf.generator.client.impl.ReceiptQueueClientImpl;
import it.gov.pagopa.receipt.pdf.generator.entity.event.BizEvent;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.Receipt;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.ReceiptError;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.enumeration.ReceiptErrorStatusType;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.enumeration.ReceiptStatusType;
import it.gov.pagopa.receipt.pdf.generator.exception.Aes256Exception;
import it.gov.pagopa.receipt.pdf.generator.exception.ReceiptNotFoundException;
import it.gov.pagopa.receipt.pdf.generator.exception.UnableToQueueException;
import it.gov.pagopa.receipt.pdf.generator.service.ReceiptCosmosService;
import it.gov.pagopa.receipt.pdf.generator.service.impl.ReceiptCosmosServiceImpl;
import it.gov.pagopa.receipt.pdf.generator.utils.Aes256Utils;
import it.gov.pagopa.receipt.pdf.generator.utils.ObjectMapperUtils;
import org.slf4j.Logger;
Expand All @@ -31,6 +37,19 @@ public class ManageReceiptPoisonQueue {

private final Logger logger = LoggerFactory.getLogger(ManageReceiptPoisonQueue.class);

private final ReceiptCosmosService receiptCosmosService;
private final ReceiptQueueClient queueService;

public ManageReceiptPoisonQueue() {
this.receiptCosmosService = new ReceiptCosmosServiceImpl();
this.queueService = ReceiptQueueClientImpl.getInstance();
}

ManageReceiptPoisonQueue(ReceiptCosmosService receiptCosmosService, ReceiptQueueClient receiptQueueClient) {
this.receiptCosmosService = receiptCosmosService;
this.queueService = receiptQueueClient;
}

/**
* This function will be invoked when a Queue trigger occurs
*
Expand All @@ -39,7 +58,8 @@ public class ManageReceiptPoisonQueue {
* If invalid or already retried saves on CosmosDB receipt-message-errors collection
*
* @param errorMessage payload of the message sent to the poison queue, triggering the function
* @param documentdb Output binding that will insert/update data with the errors not to retry within the function
* @param receiptsOutputBinding Output binding that will update the receipt relative to the bizEvent
* @param receiptErrorOutputBinding Output binding that will insert/update data with the errors not to retry within the function
* @param context Function context
*/
@FunctionName("ManageReceiptPoisonQueueProcessor")
Expand All @@ -49,12 +69,18 @@ public void processManageReceiptPoisonQueue(
queueName = "%RECEIPT_QUEUE_TOPIC_POISON%",
connection = "RECEIPTS_STORAGE_CONN_STRING")
String errorMessage,
@CosmosDBOutput(
name = "ReceiptDatastore",
databaseName = "db",
collectionName = "receipts",
connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING")
OutputBinding<Receipt> receiptsOutputBinding,
@CosmosDBOutput(
name = "ReceiptMessageErrorsDatastore",
databaseName = "db",
collectionName = "receipts-message-errors",
connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING")
OutputBinding<ReceiptError> documentdb,
OutputBinding<ReceiptError> receiptErrorOutputBinding,
final ExecutionContext context) {

BizEvent bizEvent = null;
Expand All @@ -80,10 +106,9 @@ public void processManageReceiptPoisonQueue(

if (retriableContent) {
bizEvent.setAttemptedPoisonRetry(true);
ReceiptQueueClientImpl queueService = ReceiptQueueClientImpl.getInstance();
try {
Response<SendMessageResult> sendMessageResult =
queueService.sendMessageToQueue(Base64.getMimeEncoder()
this.queueService.sendMessageToQueue(Base64.getMimeEncoder()
.encodeToString(Objects.requireNonNull(ObjectMapperUtils.writeValueAsString(bizEvent))
.getBytes()));
if (sendMessageResult.getStatusCode() != HttpStatus.CREATED.value()) {
Expand All @@ -94,15 +119,23 @@ public void processManageReceiptPoisonQueue(
logger.error("[{}] error for the function called at {} when attempting" +
"to requeue BizEvent wit id {}, saving to cosmos for review",
context.getFunctionName(), LocalDateTime.now(), bizEvent.getId(), e);
saveToDocument(context, errorMessage, bizEvent.getId(), documentdb);
saveReceiptErrorAndUpdateReceipt(errorMessage, receiptsOutputBinding, receiptErrorOutputBinding, context, bizEvent);
}
} else {
saveToDocument(context, errorMessage, bizEvent != null ? bizEvent.getId() : null, documentdb);
saveReceiptErrorAndUpdateReceipt(errorMessage, receiptsOutputBinding, receiptErrorOutputBinding, context, bizEvent);
}
}

private void saveToDocument(ExecutionContext context, String errorMessage, String bizEventId,
OutputBinding<ReceiptError> documentdb) {
private void saveReceiptErrorAndUpdateReceipt(String errorMessage, OutputBinding<Receipt> receiptsOutputBinding, OutputBinding<ReceiptError> receiptErrorOutputBinding, ExecutionContext context, BizEvent bizEvent) {
String bizEventId = bizEvent != null ? bizEvent.getId() : null;
saveToReceiptError(context, errorMessage, bizEventId, receiptErrorOutputBinding);
if(bizEventId != null){
updateReceiptToReview(context, bizEventId, receiptsOutputBinding);
}
}

private void saveToReceiptError(ExecutionContext context, String errorMessage, String bizEventId,
OutputBinding<ReceiptError> receiptErrorOutputBinding) {

ReceiptError receiptError = ReceiptError.builder()
.bizEventId(bizEventId)
Expand All @@ -118,6 +151,22 @@ private void saveToDocument(ExecutionContext context, String errorMessage, Strin
receiptError.setMessageError(e.getMessage());
}

documentdb.setValue(receiptError);
receiptErrorOutputBinding.setValue(receiptError);
}

private void updateReceiptToReview(ExecutionContext context, String bizEventId,
OutputBinding<Receipt> receiptOutputBinding) {
try {
Receipt receipt = this.receiptCosmosService.getReceipt(bizEventId);

receipt.setStatus(ReceiptStatusType.TO_REVIEW);

logger.info("[{}] updating receipt with id {} to status {}",
context.getFunctionName(), receipt.getId(), ReceiptStatusType.TO_REVIEW);
receiptOutputBinding.setValue(receipt);
} catch (ReceiptNotFoundException e) {
logger.error("[{}] error updating status of receipt with eventId {}, receipt not found",
context.getFunctionName(),bizEventId, e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package it.gov.pagopa.receipt.pdf.generator.entity.receipt.enumeration;

public enum ReceiptStatusType {
NOT_QUEUE_SENT, INSERTED, RETRY, GENERATED, SIGNED, FAILED, IO_NOTIFIED, IO_ERROR_TO_NOTIFY, IO_NOTIFIER_RETRY, UNABLE_TO_SEND, NOT_TO_NOTIFY
NOT_QUEUE_SENT, INSERTED, RETRY, GENERATED, SIGNED, FAILED, IO_NOTIFIED, IO_ERROR_TO_NOTIFY, IO_NOTIFIER_RETRY, UNABLE_TO_SEND, NOT_TO_NOTIFY, TO_REVIEW
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package it.gov.pagopa.receipt.pdf.generator.service;

import it.gov.pagopa.receipt.pdf.generator.entity.receipt.Receipt;
import it.gov.pagopa.receipt.pdf.generator.exception.ReceiptNotFoundException;

public interface ReceiptCosmosService {

/**
* Recovers a receipt from the CosmosDB by the property eventId
* @param bizEventId BizEvent id relative to the receipt
* @return the receipt found
* @throws ReceiptNotFoundException when no receipt has been found
*/
Receipt getReceipt(String bizEventId) throws ReceiptNotFoundException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package it.gov.pagopa.receipt.pdf.generator.service.impl;

import it.gov.pagopa.receipt.pdf.generator.client.ReceiptCosmosClient;
import it.gov.pagopa.receipt.pdf.generator.client.impl.ReceiptCosmosClientImpl;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.Receipt;
import it.gov.pagopa.receipt.pdf.generator.exception.ReceiptNotFoundException;
import it.gov.pagopa.receipt.pdf.generator.service.ReceiptCosmosService;

public class ReceiptCosmosServiceImpl implements ReceiptCosmosService {

private final ReceiptCosmosClient receiptCosmosClient;

public ReceiptCosmosServiceImpl() {
this.receiptCosmosClient = ReceiptCosmosClientImpl.getInstance();
}

public ReceiptCosmosServiceImpl(ReceiptCosmosClient receiptCosmosClient) {
this.receiptCosmosClient = receiptCosmosClient;
}

/**
* {@inheritDoc}
*/
@Override
public Receipt getReceipt(String bizEventId) throws ReceiptNotFoundException {
Receipt receipt;
try {
receipt = receiptCosmosClient.getReceiptDocument(bizEventId);
} catch (ReceiptNotFoundException e) {
String errorMsg = String.format("Receipt not found with the biz-event id %s",bizEventId);
throw new ReceiptNotFoundException(errorMsg, e);
}

if (receipt == null) {
String errorMsg = String.format("Receipt retrieved with the biz-event id %s is null", bizEventId);
throw new ReceiptNotFoundException(errorMsg);
}
return receipt;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import it.gov.pagopa.receipt.pdf.generator.exception.ReceiptNotFoundException;
import it.gov.pagopa.receipt.pdf.generator.model.PdfGeneration;
import it.gov.pagopa.receipt.pdf.generator.service.GenerateReceiptPdfService;
import it.gov.pagopa.receipt.pdf.generator.service.impl.ReceiptCosmosServiceImpl;
import lombok.SneakyThrows;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -55,7 +56,7 @@ void setUp() {
requeueMessageMock = (OutputBinding<String>) spy(OutputBinding.class);
executionContextMock = mock(ExecutionContext.class);

sut = spy(new GenerateReceiptPdf(generateReceiptPdfServiceMock, receiptCosmosClientMock));
sut = spy(new GenerateReceiptPdf(generateReceiptPdfServiceMock, new ReceiptCosmosServiceImpl(receiptCosmosClientMock)));
}

@Test
Expand Down
Loading

0 comments on commit 5622a29

Please sign in to comment.