Querying Purchase Orders
Inside this guide:
Prerequisites
Introduction
Querying for schedule changes
Querying for booking data
Using webhooks
Next steps
Prerequisites
To cover this use case, Zencargo must be the source of truth for Purchase Order Management. Consult your team to see if this case applies to you. Generally, if your manufacturers are being onboarded to Zencargo to update POs and make bookings, Zencargo becomes the source of truth for PO data before the booking stage, and you will want to keep your ERP in sync using these queries. If this isn't the case, you might be looking for the Packing List guide.
Introduction
The purchaseOrder query allows you to retrieve the latest state of information Zencargo holds about all Purchase Orders.
During these guides, we'll use a single sample Purchase Order to explain the query. If you want to follow along, it's a good idea to create a Purchase Order using the PurchaseOrdersCreateOrder outlined in the Creating Purchase Orders guide as we'll be using the same references in this guide. As a reminder, we send Zencargo a data structure that looks like this:
{
"orderReferenceNumber": "PO-SEAWARD-2",
"orderDate": "2021-01-01",
"manufacturerID": "uuid12345",
"originID": "uuid12345",
"destinationID": "uuid98765",
"orderedLineItems": [
{
"productSku": "10000",
"quantityOrdered": 10000,
"cbm": 32.0,
"initialCargoReadyDate": "2020-03-16",
"requiredDeliveryDate": "2020-05-04",
"erpLineId": "YOUR_ERP_LINE_ID",
},
{
"productSku": "20000",
"quantityOrdered": 50000,
"cbm": 38.0,
"initialCargoReadyDate": "2020-03-16",
"requiredDeliveryDate": "2020-05-04",
"erpLineId": "YOUR_ERP_LINE_ID",
}
]
}
If you've followed the Creating Purchase Orders guide, you'll be familiar with the data model. To briefly reiterate it here:
- You send multiple OrderedLineItem objects, representing a single SKU and its ordered quantity, expected ready date and required delivery date
- Zencargo creates one Lot per ordered line item which holds the actual quantity, actual ready date and estimated delivery date
Refer back to the Creating Purchase Orders guide or the Concepts guide to learn more about the data model.
Now let's explore a few use cases for querying purchase order data.
Querying for schedule changes
So, let's imagine a scenario where your PO is created and the production begins. Manufacturers update Zencargo with the latest cargo ready date and expected fulfilled quantity, and Zencargo calculates the latest delivery estimate. This is all data you likely want to query to update your internal systems.
For now we'll focus on querying a single PO using the orderReferenceNumber that you provided. Review the purchaseOrder query arguments to see more advanced filters.
Note: the query and example below are for illustrative purposes for a single PO. If you're regularly planning to poll Zencargo, consider using filters to retrieve multiple objects in one call.
We'll be using the API Console to save time having to authenticate. Copy and paste this into your API console query section to get started.
POST /graphql
Query
query($orderReferenceNumber: String!) {
purchaseOrders(orderReferenceNumber: $orderReferenceNumber) {
nodes {
orderReferenceNumber
orderedLineItems {
product {
skuCode
}
lots {
cargoReadyDate {
date
}
estimatedDeliveryDate
quantityFulfilled
}
erpLineId
}
}
}
}
Variables
{
"orderReferenceNumber": "PO-SEAWARD-2"
}
JSON Response
{
"data": {
"purchaseOrders": {
"nodes": [
{
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"lots": [
{
"cargoReadyDate": {
"date": "2021-03-24"
},
"estimatedDeliveryDate": "2021-05-14",
"quantityFulfilled": 10000,
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "10000"
}
},
{
"lots": [
{
"cargoReadyDate": {
"date": "2021-03-24"
},
"estimatedDeliveryDate": "2021-05-14",
"quantityFulfilled": 50000
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "20000"
}
}
]
}
]
}
}
}
Let's pick this data apart to examine what it means. First, remember that our Purchase Order originally contained two OrderedLineItem objects:
- we ordered 10000 of sku
10000, with an initial cargo ready date of 16th March and a required delivery date of 4th May - we ordered 50000 of sku
20000, with an initial cargo ready date of 16th March and a required delivery date of 4th May
From the return value, we can see that something has changed:
- we're still due to receive 10000 of sku
10000and 50000 of sku20000, but now thecargoReadyDatefor both is the 24th March - What's more, the
estimatedDeliveryDatehas been pushed back from the 4th to the 12th of May
Note carefully that the data was retrieved inside the Lot objects. This is because the Lot is the place where the latest state is stored. Zencargo takes in OrderedLineItem objects (and stores them for analytics) and then updates Lot objects. If you're querying, it's 99% likely that you want to retrieve Lot information, not OrderedLineItem information, because that's where the latest data is.
So, what has happened? In the real world, the manufacturer has experienced a delay and the goods are no longer going to be ready on the initial date - this has caused a delay to the estimated delivery date. By querying for this information, you can update your ERP or other systems to reflect the delay. What's more, you can explore the cargoReadyDate object, which is a RichDate, to see why the delay happened.
Expanding the data being requested in the cargoReadyDate object would show us this data:
# inside the lot
cargoReadyDate {
date
lastUpdated {
updatedAt
}
reasonForChange {
category
description
}
}
{
"cargoReadyDate": {
"date": "2021-03-24",
"lastUpdated": {
"updatedAt": "2021-02-12"
},
"reasonForChange": {
"category": "raw_materials",
"description": "there was an issue with sourcing raw materials"
}
}
}
Depending on how sophisticated your system is, you might want to trigger specific actions based on the new dates, or even the reasons.
Querying for booking data
When the manufacturer eventually books the goods, you can retrieve this information via API too to keep systems up to date and send advanced notices of arrivals. Let's amend that original query to include booking information to illustrate this.
POST /graphql
Query
query($orderReferenceNumber: String!) {
purchaseOrders(orderReferenceNumber: $orderReferenceNumber) {
nodes {
orderReferenceNumber
orderedLineItems {
erpLineId
product {
skuCode
}
lots {
quantityFulfilled
estimatedDeliveryDate
booking {
zencargoReference
stage {
value
}
modeOfTransport
estimatedArrival {
date
time
timeZone
}
}
}
}
}
}
}
Variables
{
"orderReferenceNumber": "PO-SEAWARD-2"
}
JSON Response
{
"data": {
"purchaseOrders": {
"nodes": [
{
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"lots": [
{
"booking": {
"estimatedArrival": {
"date": "2022-05-10",
"time": "15:00:00",
"timeZone": "Europe/London"
},
"modeOfTransport": "OCEAN",
"stage": {
"value": "departed_pol"
},
"zencargoReference": "ZBLUTH-647"
},
"estimatedDeliveryDate": "2021-05-14",
"quantityFulfilled": 10000
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "10000"
}
},
{
"lots": [
{
"booking": {
"estimatedArrival": {
"date": "2022-05-10",
"time": "15:00:00",
"timeZone": "Europe/London"
},
"modeOfTransport": "OCEAN",
"stage": {
"value": "departed_pol"
},
"zencargoReference": "ZBLUTH-647"
},
"estimatedDeliveryDate": "2021-05-14",
"quantityFulfilled": 49000
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "20000"
}
}
]
}
]
}
}
}
First, note that we've retrieved the data inside a Booking object available inside each Lot. You could have used the bookings query to get this information as well. It's the same object, and it's up to you how you want to query for this data and which data points you want back.
Now, let's examine this payload:
- both lots are booked into a booking with a reference of
ZBLUTH-647 - the booking is an ocean booking that has departed the port of load - the Stage enum will help you translate this.
- the vessel is scheduled to arrive to the port of destination on the 10th of May
- as before, we can see that the delivery estimate is still the 14th of May
You may want to update your ERP, or store a reference to the booking that the PO is inside. Many customers update their warehousing teams with the arrival date, and the quantities. Once you know the booking, you will be able to make subsequent queries for the Packing List information - which is where you'll find detailed information like quantities, volume and cargo details - using the packingLists query which is described in the Packing Lists guide.
Querying for ERP line id
It is also possible to query the ERP line id of each ordered line item if you have provided them when creating or updating the Purchasing Order.
POST /graphql
Query
query($orderReferenceNumber: String!) {
purchaseOrders(orderReferenceNumber: $orderReferenceNumber) {
nodes {
orderedLineItems {
erpLineId
...
}
}
}
}
Variables
{
"orderReferenceNumber": "PO-SEAWARD-2"
}
JSON Response
{
"data": {
"purchaseOrders": {
"nodes": [
{
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"erpLineId": "YOUR_ERP_LINE_ID"
}
]
}
]
}
}
}
Using Webhooks
Zencargo employs webhooks to allow our API clients to update data when things change. We regularly review and update the webhooks topics and encourage you to make use of the existing ones, and tell us when you need to fall back to polling so we can explore adding more topics.
Specifically to purchase orders, you can subscribe to webhook topics:
- when the cargo ready date changes, which covers the first part of this guide and would allow you to only query the API when the dates changed instead of polling for changes
- when a lot is booked, which would allow you to directly call the POs you know have been booked instead of polling
- when the quantities change, which could happen during production if the manufacturer realises they cannot ship the expected quantity.
You should explore the Webhooks Introduction to learn more.
Next Steps
- Updating Purchase Orders - If you need to, learn to update PO data
- Querying Packing Lists - To learn about querying packing list data after bookings have been placed
- Making your first call - If you're not sure how GraphQL works, start here.