Skip to main content

Routing a shipment according to its status

This workflow routes each shipment status update: it confirms each package at delivery, publishes the completion event and alerts logistics in case of delay.

Loading the diagram…

The need​

Each shipment status update must be routed to the customer notification or the logistics alert depending on the delivery status. The workflow confirms each package at delivery, publishes the completion event and alerts logistics in case of delay.

What the workflow does​

  1. Shipment status — the Trigger node captures the delivery.status event. The tracking number, the status and the list of packages arrive in data.
  2. Normalize the payload — the Code node prepares context.variables.status and context.variables.packages for the following nodes.
  3. Delivery status — the Switch node routes {{ context.variables.status }} to the corresponding branch.
  4. Alert on delay — if the status is delayed, an email warns the logistics team.
  5. Confirm each package — if the status is delivered, the ForEach node iterates over {{ data.packages }} (current element {{ colis }}).
  6. Update the package tracking — at each iteration, the PostgreSQL node confirms the package (animated "loop" edge).
  7. Shipment completed event — after the loop, the Send Google Pub/Sub node publishes delivery_completed on the CRM's Pub/Sub topic.

What you need​

Construction​

Copy the workflow definition and paste it into the editor (the Trigger node is recreated automatically, it is not in the snippet):

[
{
"id": "code-108",
"name": "Normalize the payload",
"config": {
"type": "CODE",
"code": "context.variables.status = data.status; context.variables.packages = data.packages;"
},
"parents": [
"trigger"
],
"position": {
"x": 0,
"y": 200
},
"next": "switch-108"
},
{
"id": "switch-108",
"name": "Delivery status",
"config": {
"type": "SWITCH",
"variable": "{{ context.variables.status }}",
"cases": [
{
"value": "delivered",
"next": "foreach-108"
},
{
"value": "delayed",
"next": "email-108"
}
],
"noMatchBehaviour": "error"
},
"parents": [
"code-108"
],
"position": {
"x": 0,
"y": 400
}
},
{
"id": "foreach-108",
"name": "Confirm each package",
"config": {
"type": "FOREACH",
"foreachCode": "data.packages",
"itemKey": "colis"
},
"parents": [
"switch-108"
],
"position": {
"x": 800,
"y": 600
},
"next": "event-108",
"loopStartNodeId": "db-108"
},
{
"id": "db-108",
"name": "Update the package tracking",
"config": {
"type": "DATABASE_POSTGRESQL",
"query": "UPDATE shipments SET status = 'confirmed' WHERE tracking = $1",
"binds": [
"$.colis.tracking"
],
"outputKey": "trackingUpdate"
},
"parents": [
"foreach-108"
],
"position": {
"x": 1600,
"y": 800
}
},
{
"id": "event-108",
"name": "Shipment completed event",
"config": {
"type": "SEND_EVENT",
"provider": {
"type": "GCP_PUBSUB",
"projectId": "mon-projet-logistique",
"topicId": "livraisons"
},
"body": "{\"event\": \"delivery_completed\", \"trackingNumber\": \"{{ data.trackingNumber }}\"}"
},
"parents": [
"foreach-108"
],
"position": {
"x": 800,
"y": 1000
}
},
{
"id": "email-108",
"name": "Alert on delay",
"config": {
"type": "SEND_EMAIL",
"to": [
"logistique@transporteur.fr"
],
"subject": "Delayed delivery: {{ data.trackingNumber }}",
"content": "Delivery {{ data.trackingNumber }} is delayed.",
"sendAsHtml": true
},
"parents": [
"switch-108"
],
"position": {
"x": 800,
"y": 800
}
}
]

Check that it works​

  • Expected values: the delivered and delayed cases must match the statuses published by the carrier exactly (case, spelling).
  • Deploy the workflow (Deploy a workflow), then trigger the real scenario: every execution generates a trace you can view (View traces).

Variations​

  • Unhandled cases: noMatchBehaviour: "error" makes the workflow fail if the status is unknown; add an "other" branch to track unknown statuses instead of crashing.
  • Loop: the animated "loop" edge illustrates the iteration of the ForEach node; the loop body (Update the package tracking) runs once per package.

Going further


See also: Examples and integrations