diff --git a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/EblScenarioListBuilder.java b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/EblScenarioListBuilder.java index 0441f714..18297ae2 100644 --- a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/EblScenarioListBuilder.java +++ b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/EblScenarioListBuilder.java @@ -111,13 +111,22 @@ private EblScenarioListBuilder thenAllPathsFrom(TransportDocumentStatus transpor .then( shipper_GetTransportDocument(TD_ISSUED) .thenAllPathsFrom(TD_ISSUED))); - case TD_ISSUED -> then(noAction()); // TODO + case TD_ISSUED -> then( + uc12_carrier_awaitSurrenderRequestForDelivery() + .then(shipper_GetTransportDocument(TD_PENDING_SURRENDER_FOR_DELIVERY)) + ); default -> then(noAction()); // TODO }; } - private EblScenarioListBuilder thenHappyPathFrom(TransportDocumentStatus tdStatus) { - return then(noAction()); // TODO + private EblScenarioListBuilder thenHappyPathFrom(TransportDocumentStatus transportDocumentStatus) { + return switch (transportDocumentStatus) { + case TD_ISSUED -> then( + uc12_carrier_awaitSurrenderRequestForDelivery() + .then(shipper_GetTransportDocument(TD_PENDING_SURRENDER_FOR_DELIVERY)) + ); + default -> then(noAction()); // TODO + }; } private EblScenarioListBuilder(Function actionBuilder) { @@ -291,4 +300,18 @@ private static EblScenarioListBuilder uc8_carrier_issueTransportDocument() { componentFactory.getMessageSchemaValidator( EBL_NOTIFICATIONS_API, EBL_TD_NOTIFICATION_SCHEMA_NAME))); } + + private static EblScenarioListBuilder uc12_carrier_awaitSurrenderRequestForDelivery() { + EblComponentFactory componentFactory = threadLocalComponentFactory.get(); + String carrierPartyName = threadLocalCarrierPartyName.get(); + String shipperPartyName = threadLocalShipperPartyName.get(); + return new EblScenarioListBuilder( + previousAction -> + new UC12_Carrier_AwaitSurrenderRequestForDeliveryAction( + carrierPartyName, + shipperPartyName, + (EblAction) previousAction, + componentFactory.getMessageSchemaValidator( + EBL_NOTIFICATIONS_API, EBL_TD_NOTIFICATION_SCHEMA_NAME))); + } } diff --git a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/action/UC12_Carrier_AwaitSurrenderRequestForDeliveryAction.java b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/action/UC12_Carrier_AwaitSurrenderRequestForDeliveryAction.java new file mode 100644 index 00000000..b225fed8 --- /dev/null +++ b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/action/UC12_Carrier_AwaitSurrenderRequestForDeliveryAction.java @@ -0,0 +1,46 @@ +package org.dcsa.conformance.standards.ebl.action; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.stream.Stream; +import lombok.Getter; +import org.dcsa.conformance.core.check.*; + +@Getter +public class UC12_Carrier_AwaitSurrenderRequestForDeliveryAction extends StateChangingSIAction { + private final JsonSchemaValidator requestSchemaValidator; + + public UC12_Carrier_AwaitSurrenderRequestForDeliveryAction( + String carrierPartyName, + String shipperPartyName, + EblAction previousAction, + JsonSchemaValidator requestSchemaValidator) { + super(carrierPartyName, shipperPartyName, previousAction, "UC8", 204); + this.requestSchemaValidator = requestSchemaValidator; + } + + @Override + public String getHumanReadablePrompt() { + return ("UC12: Shipper requests surrender for delivery (via the surrender API if applicable) for transport document with reference %s and carrier sends notification that surrender has been requested. Note when the conformance toolkit is acting as carrier, no action is required from the shipper (the action will auto-resolve). When the conformance toolkit is acting like the Shipper, you will have to ensure that the carrier system sees a surrender request (the surrender uses a different API not in scope for this test)." + .formatted(getDspSupplier().get().transportDocumentReference())); + } + + @Override + public ObjectNode asJsonNode() { + return super.asJsonNode() + .put("documentReference", getDspSupplier().get().shippingInstructionsReference()); + } + + @Override + public ConformanceCheck createCheck(String expectedApiVersion) { + return new ConformanceCheck(getActionTitle()) { + @Override + protected Stream createSubChecks() { + return getTDNotificationChecks( + getMatchedExchangeUuid(), + expectedApiVersion, + requestSchemaValidator + ); + } + }; + } +} diff --git a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/models/CarrierShippingInstructions.java b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/models/CarrierShippingInstructions.java index 1a1cdb40..875fd656 100644 --- a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/models/CarrierShippingInstructions.java +++ b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/models/CarrierShippingInstructions.java @@ -204,6 +204,12 @@ public void issueTransportDocument(String documentReference) { .put(shippedDateField, date); } + public void surrenderForDeliveryRequest(String documentReference) { + checkState(documentReference, getTransportDocumentState(), s -> s == TD_ISSUED); + var td = getTransportDocument().orElseThrow(); + td.put(TRANSPORT_DOCUMENT_STATUS, TD_PENDING_SURRENDER_FOR_DELIVERY.wireName()); + } + private void copyFieldIfPresent(JsonNode source, ObjectNode dest, String field) { var data = source.get(field); if (data != null) { diff --git a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/party/EblCarrier.java b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/party/EblCarrier.java index ccad7e68..34dac0fe 100644 --- a/ebl/src/main/java/org/dcsa/conformance/standards/ebl/party/EblCarrier.java +++ b/ebl/src/main/java/org/dcsa/conformance/standards/ebl/party/EblCarrier.java @@ -73,7 +73,8 @@ protected Map, Consumer> getActionP Map.entry(UC2_Carrier_RequestUpdateToShippingInstructionsAction.class, this::requestUpdateToShippingInstructions), Map.entry(UC4_Carrier_ProcessUpdateToShippingInstructionsAction.class, this::processUpdatedShippingInstructions), Map.entry(UC6_Carrier_PublishDraftTransportDocumentAction.class, this::publishDraftTransportDocument), - Map.entry(UC8_Carrier_IssueTransportDocumentAction.class, this::issueTransportDocument) + Map.entry(UC8_Carrier_IssueTransportDocumentAction.class, this::issueTransportDocument), + Map.entry(UC12_Carrier_AwaitSurrenderRequestForDeliveryAction.class, this::notifyOfSurrenderForDelivery) ); } @@ -162,6 +163,21 @@ private void issueTransportDocument(JsonNode actionPrompt) { addOperatorLogEntry("Issued transport document '%s'".formatted(documentReference)); } + private void notifyOfSurrenderForDelivery(JsonNode actionPrompt) { + log.info("Carrier.notifyOfSurrenderForDelivery(%s)".formatted(actionPrompt.toPrettyString())); + + var documentReference = actionPrompt.get("documentReference").asText(); + var sir = tdrToSir.getOrDefault(documentReference, documentReference); + + var si = CarrierShippingInstructions.fromPersistentStore(persistentMap, sir); + si.surrenderForDeliveryRequest(documentReference); + si.save(persistentMap); + generateAndEmitNotificationFromTransportDocument(actionPrompt, si, true); + + addOperatorLogEntry("Sent notification for surrender for delivery of transport document '%s'".formatted(documentReference)); + } + + private void generateAndEmitNotificationFromShippingInstructions(JsonNode actionPrompt, CarrierShippingInstructions shippingInstructions, boolean includeShippingInstructionsReference) { var notification = ShippingInstructionsNotification.builder()