Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public enum EventStatusCodeEnum {
RECRI002(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(), "Ingresso nel paese estero", false),
RECRI005(EventTypeEnum.RETRYABLE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(F01, F02, F03, F04), "Furto, smarrimento o deterioramento", false),
RECRI003A(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(), "Consegnato - pre-esito", false),
RECRI004A(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(SKIP_VALIDATION), "Mancata consegna - pre-esito", false),
RECRI004A(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(M01, M02, M03, M04, M05, M06, M07, M08, M09), "Mancata consegna - pre-esito", false),
RECRI003B(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(), "Consegnato - In Dematerializzazione", true),
RECRI004B(EventTypeEnum.INTERMEDIATE_EVENT, ProductType.RIR, EventStatus.PROGRESS, List.of(SKIP_VALIDATION), "Mancata consegna - In Dematerializzazione", true),
RECRI003C(EventTypeEnum.FINAL_EVENT, ProductType.RIR, EventStatus.OK, List.of(),"Consegnato - Fascicolo Chiuso", false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,60 @@

import it.pagopa.pn.papertracker.middleware.dao.PaperTrackingsDAO;
import it.pagopa.pn.papertracker.middleware.msclient.DataVaultClient;
import it.pagopa.pn.papertracker.middleware.dao.dynamo.entity.Event;
import it.pagopa.pn.papertracker.model.EventStatusCodeEnum;
import it.pagopa.pn.papertracker.model.HandlerContext;
import it.pagopa.pn.papertracker.service.handler_step.generic.GenericFinalEventBuilder;
import it.pagopa.pn.papertracker.service.handler_step.HandlerStep;
import it.pagopa.pn.papertracker.utils.TrackerUtility;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import static it.pagopa.pn.papertracker.model.EventStatusCodeEnum.RECRI004C;


@Component
@Slf4j
public class FinalEventBuilderRir extends GenericFinalEventBuilder implements HandlerStep {

/**
* Step che elabora l'evento finale per una raccomandata RIR in base alla logica di business definita.
* Se l'evento che ha innescato il flusso è un evento finale, viene estratto l'evento dal contesto,
* viene valutato lo status code e determinato lo stato dell'evento secondo le regole di business.
* Infine, l'evento viene aggiunto alla lista degli eventi da inviare.
* Viene utilizzato il metodo di utility evaluateStatusCodeAndRetrieveStatus perché tutti i casi non gestiti esplicitamente (M01, M03, M04)
* e il caso della deliveryFailureCause = null ricadono comunque nel ramo di default, che restituisce il valore KO previsto dall’enum.
*
* @param context Contesto contenente le informazioni necessarie per l'elaborazione dell'evento.
* @return Mono<Void>
*/

private final PaperTrackingsDAO paperTrackingsDAO;

public FinalEventBuilderRir(DataVaultClient dataVaultClient, PaperTrackingsDAO paperTrackingsDAO) {
super(dataVaultClient, paperTrackingsDAO);
this.paperTrackingsDAO = paperTrackingsDAO;
}

@Override
public Mono<Void> execute(HandlerContext context) {
log.info("Executing FinalEventBuilderRir for trackingId: {}", context.getTrackingId());

return Mono.just(TrackerUtility.extractEventFromContext(context))
.doOnNext(event -> context.setFinalStatusCode(event.getStatusCode()))
.flatMap(event -> handleFinalEvent(context, event))
.thenReturn(context)
.map(ctx -> paperTrackingsDAO.updateItem(ctx.getPaperTrackings().getTrackingId(), getPaperTrackingsToUpdate()))
.then();
}

private Mono<Void> handleFinalEvent(HandlerContext context, Event finalEvent) {
String statusCode = finalEvent.getStatusCode();
if (RECRI004C.name().equals(statusCode)) {
String eventStatus = TrackerUtility.evaluateStatusCodeAndRetrieveStatus(RECRI004C.name(), statusCode, context.getPaperTrackings()).name();
return addEventToSend(context, finalEvent, eventStatus);
}
return addEventToSend(context, finalEvent, EventStatusCodeEnum.fromKey(statusCode).getStatus().name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@

import it.pagopa.pn.papertracker.middleware.dao.PaperTrackingsDAO;
import it.pagopa.pn.papertracker.middleware.dao.PaperTrackingsErrorsDAO;
import it.pagopa.pn.papertracker.middleware.dao.dynamo.entity.ErrorCategory;
import it.pagopa.pn.papertracker.middleware.dao.dynamo.entity.Event;
import it.pagopa.pn.papertracker.middleware.dao.dynamo.entity.PaperTrackings;
import it.pagopa.pn.papertracker.model.DeliveryFailureCauseEnum;
import it.pagopa.pn.papertracker.model.EventStatusCodeEnum;
import it.pagopa.pn.papertracker.model.HandlerContext;
import it.pagopa.pn.papertracker.service.handler_step.HandlerStep;
import it.pagopa.pn.papertracker.service.handler_step.generic.GenericSequenceValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.util.List;

import static it.pagopa.pn.papertracker.model.EventStatusCodeEnum.RECRI004A;

@Component
@Slf4j
Expand All @@ -14,4 +26,42 @@ public class SequenceValidatorRir extends GenericSequenceValidator implements Ha
public SequenceValidatorRir(PaperTrackingsDAO paperTrackingsDAO, PaperTrackingsErrorsDAO paperTrackingsErrorsDAO) {
super(paperTrackingsDAO, paperTrackingsErrorsDAO);
}
}


@Override
protected Mono<Event> validateSingleDeliveryFailureCause(Event event, PaperTrackings paperTrackings, HandlerContext context, Boolean strictFinalEventValidation) {
log.info("Beginning RIR validation for delivery failure cause for event : {}", event);

EventStatusCodeEnum statusCodeEnum = EventStatusCodeEnum.fromKey(event.getStatusCode());

if (statusCodeEnum.equals(RECRI004A)) {

String deliveryFailureCause = event.getDeliveryFailureCause();
List<DeliveryFailureCauseEnum> allowedCauses = statusCodeEnum.getDeliveryFailureCauseList();

if (!StringUtils.hasText(deliveryFailureCause)) {
// Se la causa non è valorizzata, vado avanti
return Mono.just(event);
}

if (allowedCauses.contains(DeliveryFailureCauseEnum.fromValue(deliveryFailureCause))) {
// Se valorizzata ed è tra le allowed, vado avanti
return Mono.just(event);
}

//TODO: aggiornare con additionalDetail dopo marge

// Se valorizzata ma non tra le allowed, errore/warning
return getErrorOrSaveWarning(
"Invalid deliveryFailureCause: " + deliveryFailureCause,
context,
paperTrackings,
ErrorCategory.DELIVERY_FAILURE_CAUSE_ERROR,
strictFinalEventValidation,
event
);
}
// Per tutti gli altri casi, delega alla superclasse
return super.validateSingleDeliveryFailureCause(event, paperTrackings, context, strictFinalEventValidation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,30 +254,40 @@ public Mono<List<Event>> getOnlyLatestEvents(List<Event> events) {
*/
private Mono<List<Event>> validateDeliveryFailureCause(List<Event> events, PaperTrackings paperTrackings, HandlerContext context, Boolean strictFinalEventValidation) {
log.info("Beginning validation for delivery failure cause for events : {}", events);

return Flux.fromIterable(events)
.flatMap(event -> {
String deliveryFailureCause = event.getDeliveryFailureCause();
EventStatusCodeEnum statusCodeEnum = EventStatusCodeEnum.fromKey(event.getStatusCode());
List<DeliveryFailureCauseEnum> allowedCauses = statusCodeEnum.getDeliveryFailureCauseList();
.flatMap(event -> validateSingleDeliveryFailureCause(
event, paperTrackings, context, strictFinalEventValidation))
.collectList();
}

boolean isSkipValidation = allowedCauses.contains(DeliveryFailureCauseEnum.SKIP_VALIDATION);
boolean isEmptyAllowedAndNoCause = CollectionUtils.isEmpty(allowedCauses) && !StringUtils.hasText(deliveryFailureCause);
boolean isValidCause = allowedCauses.contains(DeliveryFailureCauseEnum.fromValue(deliveryFailureCause));
protected Mono<Event> validateSingleDeliveryFailureCause(Event event,
PaperTrackings paperTrackings,
HandlerContext context,
Boolean strictFinalEventValidation) {

if (isSkipValidation || isEmptyAllowedAndNoCause || isValidCause) {
return Mono.just(event);
}
String deliveryFailureCause = event.getDeliveryFailureCause();
EventStatusCodeEnum statusCodeEnum = EventStatusCodeEnum.fromKey(event.getStatusCode());
List<DeliveryFailureCauseEnum> allowedCauses = statusCodeEnum.getDeliveryFailureCauseList();

return getErrorOrSaveWarning(
"Invalid deliveryFailureCause: " + deliveryFailureCause,
context,
paperTrackings,
ErrorCategory.DELIVERY_FAILURE_CAUSE_ERROR,
strictFinalEventValidation,
event
);
})
.collectList();
boolean isSkipValidation = allowedCauses.contains(DeliveryFailureCauseEnum.SKIP_VALIDATION);
boolean isEmptyAllowedAndNoCause = CollectionUtils.isEmpty(allowedCauses)
&& !StringUtils.hasText(deliveryFailureCause);
boolean isValidCause = allowedCauses.contains(
DeliveryFailureCauseEnum.fromValue(deliveryFailureCause));

if (isSkipValidation || isEmptyAllowedAndNoCause || isValidCause) {
return Mono.just(event);
}

return getErrorOrSaveWarning(
"Invalid deliveryFailureCause: " + deliveryFailureCause,
context,
paperTrackings,
ErrorCategory.DELIVERY_FAILURE_CAUSE_ERROR,
strictFinalEventValidation,
event
);
}

/**
Expand Down Expand Up @@ -403,7 +413,7 @@ private boolean allStockStatusTimestampAreEquals(List<Event> events, Set<String>
return timestamps.size() <= 1 || timestamps.stream().allMatch(t -> t.equals(timestamps.getFirst()));
}

private <T> Mono<T> getErrorOrSaveWarning(String message, HandlerContext context, PaperTrackings paperTrackings, ErrorCategory errorCategory, Boolean strictFinalEventValidation, T returnValue) {
protected <T> Mono<T> getErrorOrSaveWarning(String message, HandlerContext context, PaperTrackings paperTrackings, ErrorCategory errorCategory, Boolean strictFinalEventValidation, T returnValue) {
log.info("getErrorOrSaveWarning for trackingId {}: {} | strictFinalEventValidation: {}", context.getTrackingId(), message, strictFinalEventValidation);

var error = PaperTrackingsErrorsMapper.buildPaperTrackingsError(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package it.pagopa.pn.papertracker.service.handler_step.RIR;

import it.pagopa.pn.papertracker.config.PnPaperTrackerConfigs;
import it.pagopa.pn.papertracker.generated.openapi.msclient.externalchannel.model.PaperProgressStatusEvent;
import it.pagopa.pn.papertracker.generated.openapi.msclient.paperchannel.model.StatusCodeEnum;
import it.pagopa.pn.papertracker.middleware.dao.PaperTrackingsDAO;
import it.pagopa.pn.papertracker.middleware.dao.dynamo.entity.*;
import it.pagopa.pn.papertracker.middleware.msclient.DataVaultClient;
import it.pagopa.pn.papertracker.model.HandlerContext;
import it.pagopa.pn.papertracker.utils.TrackerUtility;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -29,9 +29,6 @@
@ExtendWith(MockitoExtension.class)
class FinalEventBuilderRirTest {

@Mock
PnPaperTrackerConfigs cfg;

@Mock
DataVaultClient dataVaultClient;

Expand Down Expand Up @@ -124,6 +121,30 @@ void buildRIRFinalEvent_withoutDiscoveredAddress() {
Assertions.assertEquals("M02", handlerContext.getEventsToSend().getFirst().getDeliveryFailureCause());
}

@Test
void buildRIRFinalEvent_withRECRI004C_statusCode() {
// Arrange
PaperProgressStatusEvent finalEvent = getFinalEvent(RECRI004C.name());
handlerContext.setPaperProgressStatusEvent(finalEvent);
handlerContext.setEventId(EVENT_ID);
Event event = new Event();
event.setStatusCode(RECRI004C.name());
event.setStatusTimestamp(Instant.now());
event.setRequestTimestamp(Instant.now());
event.setId(EVENT_ID);
handlerContext.getPaperTrackings().setEvents(List.of(event));

// Act
StepVerifier.create(finalEventBuilder.execute(handlerContext))
.verifyComplete();

// Assert
Assertions.assertEquals(1, handlerContext.getEventsToSend().size());
String expectedStatus = TrackerUtility.evaluateStatusCodeAndRetrieveStatus(RECRI004C.name(), RECRI004C.name(), handlerContext.getPaperTrackings()).name();
Assertions.assertNotNull(handlerContext.getEventsToSend().getFirst().getStatusCode());
Assertions.assertEquals(expectedStatus, handlerContext.getEventsToSend().getFirst().getStatusCode().name());
}

private PaperProgressStatusEvent getFinalEvent(String statusCode) {
PaperProgressStatusEvent finalEvent = new PaperProgressStatusEvent();
finalEvent.setStatusCode(statusCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ private void verifyOutputs(List<PaperTrackerDryRunOutputs> list, List<PaperTrack
if (is(e, "RECRI002")) {assertNoAttach(e);assertProgress(e);}
if (is(e, "RECRI004A")) {assertNoAttach(e);assertProgress(e);}
if (is(e, "RECRI004B")) {assertAttach(e, "Plico");assertProgress(e);}
if (is(e, "RECRI004C")) {assertNoAttach(e);assertKo(e);assertNull(e.getDeliveryFailureCause());}
if (is(e, "RECRI004C")) {assertNoAttach(e);assertKo(e);assertNotNull(e.getDeliveryFailureCause());}
});
}
case OK_RETRY_RIR -> {
Expand Down Expand Up @@ -228,7 +228,7 @@ private void verifyPaperTrackings(PaperTrackings pt, PaperTrackings newPt, TestS
case OK_RIR ->
assertValidatedDoneSubset(pt, 7, 5, null, List.of("RECRI001", "RECRI002", "RECRI003A", "RECRI003B", "RECRI003C"), DONE,BusinessState.DONE);
case OK_RETRY_RIR -> assertValidatedDone(newPt, 7, 5, null, DONE,BusinessState.DONE);
case FAIL_RIR -> assertValidatedDone(pt, 7, 5, null, DONE,BusinessState.DONE);
case FAIL_RIR -> assertValidatedDone(pt, 7, 5, "M01", DONE,BusinessState.DONE);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,74 @@ void validateSequenceInvalidRegisteredLetterCode() {
throwable.getMessage().contains("Registered letter codes do not match in sequence"))
.verify();
}

@Test
void validateSequenceValidRECRI004A() {
// Arrange
context.getPaperProgressStatusEvent().setStatusCode("RECRI004C");
Instant timestamp = Instant.now();
Instant businessTimestamp = Instant.now();
context.getPaperTrackings().setEvents(List.of(
buildEvent("RECRI001", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI002", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI004A", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI004B", timestamp, businessTimestamp.plusSeconds(1), "REG123", "", List.of(DocumentTypeEnum.PLICO.getValue())),
buildEvent("RECRI004C", timestamp, businessTimestamp.plusSeconds(2), "REG123", "", null)
));
when(paperTrackingsDAO.updateItem(any(), any())).thenReturn(Mono.empty());

// Act
StepVerifier.create(sequenceValidatorRir.execute(context))
.verifyComplete();

// Assert
verify(paperTrackingsDAO, times(1)).updateItem(any(), any());
}

@Test
void validateSequenceValidRECRI004AWithFailureCause() {
// Arrange
context.getPaperProgressStatusEvent().setStatusCode("RECRI004C");
Instant timestamp = Instant.now();
Instant businessTimestamp = Instant.now();
context.getPaperTrackings().setEvents(List.of(
buildEvent("RECRI001", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI002", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI004A", timestamp, businessTimestamp, "REG123", "M01", null),
buildEvent("RECRI004B", timestamp, businessTimestamp.plusSeconds(1), "REG123", "", List.of(DocumentTypeEnum.PLICO.getValue())),
buildEvent("RECRI004C", timestamp, businessTimestamp.plusSeconds(2), "REG123", "", null)
));
when(paperTrackingsDAO.updateItem(any(), any())).thenReturn(Mono.empty());

// Act
StepVerifier.create(sequenceValidatorRir.execute(context))
.verifyComplete();

// Assert
verify(paperTrackingsDAO, times(1)).updateItem(any(), any());
}

@Test
void validateSequenceValidRECRI004AWithInvalidFailureCause() {
// Arrange
context.getPaperProgressStatusEvent().setStatusCode("RECRI004C");
Instant timestamp = Instant.now();
Instant businessTimestamp = Instant.now();
context.getPaperTrackings().setEvents(List.of(
buildEvent("RECRI001", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI002", timestamp, businessTimestamp, "REG123", "", null),
buildEvent("RECRI004A", timestamp, businessTimestamp, "REG123", "INVALID", null),
buildEvent("RECRI004B", timestamp, businessTimestamp.plusSeconds(1), "REG123", "", List.of(DocumentTypeEnum.PLICO.getValue())),
buildEvent("RECRI004C", timestamp, businessTimestamp.plusSeconds(2), "REG123", "", null)
));
when(paperTrackingsDAO.updateItem(any(), any())).thenReturn(Mono.empty());

// Act & Assert
StepVerifier.create(sequenceValidatorRir.execute(context))
.expectErrorMatches(throwable -> throwable instanceof PnPaperTrackerValidationException &&
throwable.getMessage().contains("Invalid deliveryFailureCause: INVALID"))
.verify();
}

private Event buildEvent(String statusCode, Instant statusTimestamp, Instant requestTimestamp, String registeredLetterCode, String deliveryFailureCause, List<String> attachmentTypes) {
Event event = new Event();
Expand Down
Loading