Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

DT-632: UC4 - Carrier - Process updated shipping instructions #25

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -49,26 +49,59 @@ private EblScenarioListBuilder thenAllPathsFrom(
case SI_RECEIVED -> thenEither(
uc2_carrier_requestUpdateToShippingInstruction()
.then(shipper_GetShippingInstructions(SI_PENDING_UPDATE, TD_START)
.thenHappyPathFrom(SI_PENDING_UPDATE)),
.thenAllPathsFrom(SI_PENDING_UPDATE)),
uc3_shipper_submitUpdatedShippingInstructions()
.then(
shipper_GetShippingInstructions(SI_RECEIVED, SI_UPDATE_RECEIVED, TD_START)
.then(
uc2_carrier_requestUpdateToShippingInstruction()
.then(shipper_GetShippingInstructions(SI_PENDING_UPDATE, TD_START)
.thenHappyPathFrom(SI_PENDING_UPDATE)))),
.thenAllPathsFrom(SI_UPDATE_RECEIVED)),
uc6_carrier_publishDraftTransportDocument()
.then(
shipper_GetShippingInstructions(SI_RECEIVED, TD_DRAFT, true)
.then(shipper_GetTransportDocument(TD_DRAFT)
.thenAllPathsFrom(TD_DRAFT))));
case SI_UPDATE_RECEIVED -> thenEither(
uc2_carrier_requestUpdateToShippingInstruction()
.then(shipper_GetShippingInstructions(SI_PENDING_UPDATE, TD_START)
.thenHappyPathFrom(SI_PENDING_UPDATE)),
uc4a_carrier_acceptUpdatedShippingInstructions()
.then(shipper_GetShippingInstructions(SI_RECEIVED, TD_START)
.thenHappyPathFrom(SI_RECEIVED)),
uc4d_carrier_declineUpdatedShippingInstructions()
.then(shipper_GetShippingInstructions(SI_RECEIVED, SI_DECLINED, TD_START)
.thenAllPathsFrom(SI_DECLINED)));
case SI_DECLINED -> thenEither(
uc6_carrier_publishDraftTransportDocument()
.then(shipper_GetShippingInstructions(SI_RECEIVED, TD_DRAFT, true)
.then(shipper_GetTransportDocument(TD_DRAFT)
.thenHappyPathFrom(TD_DRAFT))),
uc2_carrier_requestUpdateToShippingInstruction()
.then(shipper_GetShippingInstructions(SI_PENDING_UPDATE, TD_START)
.thenHappyPathFrom(SI_PENDING_UPDATE)),
uc3_shipper_submitUpdatedShippingInstructions()
.then(shipper_GetShippingInstructions(SI_UPDATE_RECEIVED, TD_START)
.thenHappyPathFrom(SI_UPDATE_RECEIVED)));
default -> then(noAction()); // TODO
};
}

private EblScenarioListBuilder thenHappyPathFrom(
ShippingInstructionsStatus shippingInstructionsStatus) {
return then(noAction()); // TODO
return switch (shippingInstructionsStatus) {
case SI_RECEIVED, SI_DECLINED -> then(uc6_carrier_publishDraftTransportDocument()
.then(
shipper_GetShippingInstructions(SI_RECEIVED, TD_DRAFT, true)
.then(shipper_GetTransportDocument(TD_DRAFT)
.thenHappyPathFrom(TD_DRAFT))));
case SI_PENDING_UPDATE -> then(uc3_shipper_submitUpdatedShippingInstructions()
.then(
shipper_GetShippingInstructions(SI_RECEIVED, SI_UPDATE_RECEIVED, TD_START)
.thenHappyPathFrom(SI_UPDATE_RECEIVED)));
case SI_UPDATE_RECEIVED -> then(uc4a_carrier_acceptUpdatedShippingInstructions()
.then(shipper_GetShippingInstructions(SI_RECEIVED, TD_START)
.thenHappyPathFrom(SI_RECEIVED))
);
default -> then(noAction()); // TODO
};
}

private EblScenarioListBuilder thenAllPathsFrom(TransportDocumentStatus transportDocumentStatus) {
Expand Down Expand Up @@ -201,6 +234,36 @@ private static EblScenarioListBuilder uc2_carrier_requestUpdateToShippingInstruc
EBL_NOTIFICATIONS_API, EBL_SI_NOTIFICATION_SCHEMA_NAME)));
}

private static EblScenarioListBuilder uc4a_carrier_acceptUpdatedShippingInstructions() {
EblComponentFactory componentFactory = threadLocalComponentFactory.get();
String carrierPartyName = threadLocalCarrierPartyName.get();
String shipperPartyName = threadLocalShipperPartyName.get();
return new EblScenarioListBuilder(
previousAction ->
new UC4_Carrier_ProcessUpdateToShippingInstructionsAction(
carrierPartyName,
shipperPartyName,
(EblAction) previousAction,
componentFactory.getMessageSchemaValidator(
EBL_NOTIFICATIONS_API, EBL_SI_NOTIFICATION_SCHEMA_NAME),
true));
}

private static EblScenarioListBuilder uc4d_carrier_declineUpdatedShippingInstructions() {
EblComponentFactory componentFactory = threadLocalComponentFactory.get();
String carrierPartyName = threadLocalCarrierPartyName.get();
String shipperPartyName = threadLocalShipperPartyName.get();
return new EblScenarioListBuilder(
previousAction ->
new UC4_Carrier_ProcessUpdateToShippingInstructionsAction(
carrierPartyName,
shipperPartyName,
(EblAction) previousAction,
componentFactory.getMessageSchemaValidator(
EBL_NOTIFICATIONS_API, EBL_SI_NOTIFICATION_SCHEMA_NAME),
false));
}

private static EblScenarioListBuilder uc6_carrier_publishDraftTransportDocument() {
EblComponentFactory componentFactory = threadLocalComponentFactory.get();
String carrierPartyName = threadLocalCarrierPartyName.get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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 UC4_Carrier_ProcessUpdateToShippingInstructionsAction extends StateChangingSIAction {
private final JsonSchemaValidator requestSchemaValidator;
private final boolean acceptChanges;

public UC4_Carrier_ProcessUpdateToShippingInstructionsAction(
String carrierPartyName,
String shipperPartyName,
EblAction previousAction,
JsonSchemaValidator requestSchemaValidator,
boolean acceptChanges) {
super(carrierPartyName, shipperPartyName, previousAction, acceptChanges ? "UC4a" : "UC4d", 204);
this.requestSchemaValidator = requestSchemaValidator;
this.acceptChanges = acceptChanges;
}

@Override
public String getHumanReadablePrompt() {
if (acceptChanges) {
return ("UC4: Accept updated shipping instructions with document reference %s"
.formatted(getDspSupplier().get().shippingInstructionsReference()));
}
return ("UC4: Decline updated shipping instructions with document reference %s"
.formatted(getDspSupplier().get().shippingInstructionsReference()));
}

@Override
public ObjectNode asJsonNode() {
return super.asJsonNode()
.put("documentReference", getDspSupplier().get().shippingInstructionsReference())
.put("acceptChanges", acceptChanges);
}

@Override
public ConformanceCheck createCheck(String expectedApiVersion) {
return new ConformanceCheck(getActionTitle()) {
@Override
protected Stream<? extends ConformanceCheck> createSubChecks() {
return getSINotificationChecks(
getMatchedExchangeUuid(),
expectedApiVersion,
requestSchemaValidator
);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@ public class CarrierShippingInstructions {

private static final Set<ShippingInstructionsStatus> PENDING_UPDATE_PREREQUISITE_STATES = Set.of(
SI_RECEIVED,
SI_UPDATE_RECEIVED
);

private static final Set<ShippingInstructionsStatus> DRAFT_TRANSPORT_DOCUMENT_PREREQUISITE_STATES = Set.of(
SI_RECEIVED,
SI_UPDATE_RECEIVED
SI_UPDATE_RECEIVED,
SI_DECLINED
);

private static final String SI_STATUS = "shippingInstructionsStatus";
Expand Down Expand Up @@ -174,9 +170,20 @@ public void acceptUpdatedShippingInstructions(String documentReference) {
changeSIState(SI_STATUS, SI_RECEIVED);
}

public void declineUpdatedShippingInstructions(String documentReference, String reason) {
checkState(documentReference, getShippingInstructionsState(), s -> s == SI_UPDATE_RECEIVED);
var updated = getUpdatedShippingInstructions().orElseThrow();
setShippingInstructions(updated);
clearUpdatedShippingInstructions();
setReason(reason);
mutateShippingInstructionsAndUpdate(siData -> siData.remove("requestedChanges"));
changeSIState(UPDATED_SI_STATUS, SI_DECLINED);
}

public void publishDraftTransportDocument(String documentReference) {
checkState(documentReference, getShippingInstructionsState(), s -> s == SI_RECEIVED);
assert getUpdatedShippingInstructions().isEmpty();
// SI_DECLINED only applies to the updated SI. UC1 -> UC3 -> UC4 (decline) -> UC6 is applicable and
// in this case, the SI would be in RECEIVED with updated state SI_DECLINED.
checkState(documentReference, getShippingInstructionsState(), s -> s == SI_RECEIVED || s == SI_DECLINED);
this.generateTDFromSI();
var tdData = getTransportDocument().orElseThrow();
var tdr = tdData.required(TRANSPORT_DOCUMENT_REFERENCE).asText();
Expand Down Expand Up @@ -272,7 +279,7 @@ public void putShippingInstructions(String documentReference, ObjectNode newShip
checkState(
documentReference,
currentState,
s -> s != SI_DECLINED && s != SI_COMPLETED
s -> s != SI_COMPLETED
);
changeSIState(UPDATED_SI_STATUS, SI_UPDATE_RECEIVED);
copyMetadataFields(getShippingInstructions(), newShippingInstructionData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
import org.dcsa.conformance.core.traffic.ConformanceMessageBody;
import org.dcsa.conformance.core.traffic.ConformanceRequest;
import org.dcsa.conformance.core.traffic.ConformanceResponse;
import org.dcsa.conformance.standards.ebl.action.Carrier_SupplyScenarioParametersAction;
import org.dcsa.conformance.standards.ebl.action.UC2_Carrier_RequestUpdateToShippingInstructionsAction;
import org.dcsa.conformance.standards.ebl.action.UC6_Carrier_PublishDraftTransportDocumentAction;
import org.dcsa.conformance.standards.ebl.action.UC8_Carrier_IssueTransportDocumentAction;
import org.dcsa.conformance.standards.ebl.action.*;
import org.dcsa.conformance.standards.ebl.models.CarrierShippingInstructions;

@Slf4j
Expand Down Expand Up @@ -74,6 +71,7 @@ protected Map<Class<? extends ConformanceAction>, Consumer<JsonNode>> getActionP
return Map.ofEntries(
Map.entry(Carrier_SupplyScenarioParametersAction.class, this::supplyScenarioParameters),
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)
);
Expand All @@ -93,7 +91,7 @@ private void supplyScenarioParameters(JsonNode actionPrompt) {
asyncOrchestratorPostPartyInput(
OBJECT_MAPPER
.createObjectNode()
.put("actionId", actionPrompt.get("actionId").asText())
.put("actionId", actionPrompt.required("actionId").asText())
.set("input", carrierScenarioParameters.toJson()));
addOperatorLogEntry(
"Provided CarrierScenarioParameters: %s".formatted(carrierScenarioParameters));
Expand All @@ -102,7 +100,7 @@ private void supplyScenarioParameters(JsonNode actionPrompt) {
private void requestUpdateToShippingInstructions(JsonNode actionPrompt) {
log.info("Carrier.requestUpdateToShippingInstructions(%s)".formatted(actionPrompt.toPrettyString()));

var documentReference = actionPrompt.get("documentReference").asText();
var documentReference = actionPrompt.required("documentReference").asText();
var sir = tdrToSir.getOrDefault(documentReference, documentReference);

var si = CarrierShippingInstructions.fromPersistentStore(persistentMap, sir);
Expand All @@ -116,6 +114,25 @@ private void requestUpdateToShippingInstructions(JsonNode actionPrompt) {
}


private void processUpdatedShippingInstructions(JsonNode actionPrompt) {
log.info("Carrier.processUpdatedShippingInstructions(%s)".formatted(actionPrompt.toPrettyString()));

var documentReference = actionPrompt.required("documentReference").asText();
var accept = actionPrompt.required("acceptChanges").asBoolean(true);
var sir = tdrToSir.getOrDefault(documentReference, documentReference);

var si = CarrierShippingInstructions.fromPersistentStore(persistentMap, sir);
if (accept) {
si.acceptUpdatedShippingInstructions(documentReference);
} else {
si.declineUpdatedShippingInstructions(documentReference, "Declined as requested by the Conformance orchestrator");
}
si.save(persistentMap);
generateAndEmitNotificationFromShippingInstructions(actionPrompt, si, true);

addOperatorLogEntry("Processed update to the shipping instructions with document reference '%s'".formatted(documentReference));
}

private void publishDraftTransportDocument(JsonNode actionPrompt) {
log.info("Carrier.publishDraftTransportDocument(%s)".formatted(actionPrompt.toPrettyString()));

Expand Down
Loading