Updating Purchase Orders
Inside this guide:
Prerequisites
Introduction
Updating order information
Updating lot information
Updating lot schedules
Next steps
Prerequisites
To cover this use case, Zencargo must NOT be the source of truth for Purchase Order Management. Consult your team to see if this case applies to you. Generally, if you have not onboarded manufacturers to Zencargo, and updates to schedules and quantities happen in the ERP, then you can use this mutation to keep Zencargo up to date with your ERP. If you have onboarded manufacturers and Zencargo is to be considered the source of truth for PO management, consult the Querying Purchase Orders 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 mutations. If you want to follow along, it's a good idea to create the 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.
Before proceeding, if you intend to follow along, ensure you have a valid UUID of a Purchase Order you've created on Zencargo
Now let's explore a few use cases for updating Purchase Order data.
Updating order information
This is likely the least frequent use case, but is the simplest, so let's start here. Zencargo holds two types of information: the order information like the attributes of the purchase order, and the contents of OrderedLineItem objects, and fulfilment information which is all stored in Lot objects. We'll start by explaining the mutation that can update the Order Information, which is purchaseOrdersUpdateOrder.
When might you use this?
- To tell Zencargo that the attributes of an order, such as its manufacturer or raised date, have changed due to an error in your original mutation
- To tell Zencargo that you've changed the ordered quantity or originally intended schedule,
- due to a mistake, or
- due to a renegotiation with your supplier
When should you NOT use this?
- To tell Zencargo that the fulfilment schedule of an order has been delayed or changed
- To tell Zencargo that the quantities the manufacturer will ship to you differ from the original expected quantities.
See the next section of the guide for the correct mutation for these last two cases.
Performing the mutation
The purchaseOrdersUpdateOrder mutation allows you to specify any of the original fields you supplied when creating the order. For instance, let's say that, when you created the order, you fired over the wrong order date. This is how we'd update the order created above to update the order date.
POST /graphql
Query
mutation($orderId: String!, $newOrderDate: Date!) {
purchaseOrdersUpdateOrder(input: {
purchaseOrderId: $orderId,
purchaseOrder: {
orderDate: $newOrderDate
}
}) {
purchaseOrder {
orderReferenceNumber
orderDate
}
}
}
Remember to substitute this variable for the UUID of a purchase order you've created in your own account. If you need an ID, see the purchaseOrders query to retrieve one based on the order reference number you supplied earlier
Variables
{
"orderId": "YOUR_ORDER_ID_HERE",
"newOrderDate": "2021-01-01"
}
JSON Response
{
"data": {
"purchaseOrdersUpdateOrder": {
"purchaseOrder": {
"orderDate": "2021-01-01",
"orderReferenceNumber": "PO-SEAWARD-2"
}
}
}
}
You'll mostly be calling this mutation to rectify errors, and because of this you can only amend OrderedLineItem objects. See the docs for the data stored in these objects.
The rest of these guides will focus on the truly valuable mutations, which is to update Lot information.
Updating Lot information
During the production of goods, manufacturers will sometimes revise the quantities they will fulfil. Zencargo stores original order information at the OrderedLineItem level, and it stores actual fulfilment information at the Lot level.
If you need to update the quantities that will be shipped of a SKU in a PO on Zencargo, you need to use the purchaseOrdersUpdateLots mutation.
To fire this mutation, we need to find the Lot IDs that are to be updated. To find lot IDs, you can specify them inside the return value either of the original mutation and persist them somewhere, or retrieve them later on. It's entirely up to you how to retrieve and whether you persist these references. Let's look at one strategy:
Using the purchaseOrders query to retrieve Lot IDs
Let's imagine that our ERP gets updated to indicate that the SKU 20000 in "PO-SEAWARD-2" has had its fulfilled quantity revised down from 50k to 48k by the manufacturer. We chose not to store the Zencargo IDs of the PO when we created it. So now, we must make a query to purchaseOrders to get the orderedLineItem and lot IDs of the SKU in question.
POST /graphql
Query
query($orderReferenceNumber: String!) {
purchaseOrders(orderReferenceNumber: $orderReferenceNumber) {
nodes {
id
orderReferenceNumber
orderedLineItems {
id
product {
skuCode
}
lots {
id
quantityFulfilled
}
erpLineId
}
}
}
}
Variables
{
"orderReferenceNumber": "PO-SEAWARD-2"
}
JSON Response
{
"data": {
"purchaseOrders": {
"nodes": [
{
"id": "c7b1db12-6f5f-4aaf-b0d2-caa9398e072c",
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"id": "ea9cc920-283b-4877-94fa-7ff9e0929bc7",
"lots": [
{
"id": "f48751b3-d47b-4fd1-95ac-ae861d6d7002",
"quantityFulfilled": 10000
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "10000"
}
},
{
"id": "dc1a25d2-2f66-43ff-8076-c3276b5998e5",
"lots": [
{
"id": "e9c905be-a15c-4376-94f6-7122accf7437",
"quantityFulfilled": 50000
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "20000"
}
}
]
}
]
}
}
}
Note: the UUIDs here will be different in your environment. When you see one from here on out, substitute it for one of your own
In this response, we can grab the ID of the line item and the lots associated with each SKU. We write some logic on our side to find the line item object containing the SKU we are looking to update, and then we grab the Lot objects.
Note that the "lots" are objects in an array, meaning one "orderedLineItem" can contain multiple lots, if the manufacturer has split the shipment of the PO across multiple bookings. It's not possible to do this via API right now, but you still need to handle the fact that these could be an array.
Now we can retrieve our OrderedLineItem and Lot IDs and store them somewhere. Hopefully this guide convinces you to store the IDs during the original creation mutation operation, as it will make this sort of double-querying behaviour obsolete.
When we have the IDs, we can make the call to update the relevant Lot with the new "quantityFulfilled" using the purchaseOrdersUpdateLots mutation.
We only want to update that last lot, the one associated to the SKU 20000, so we'll only send this in our mutation. The UpdateLotsInput type defines the fields and types we have to provide. We must provide latest values for cbm and quantityFulfilled for each Lot in our update payload.
POST /graphql
Query
mutation($lineItemId: String!, $lotId: String!, $newCbm: Float!, $newQuantity: Int!) {
purchaseOrdersUpdateLots(input: {
orderedLineItemId: $lineItemId,
lots: [
{
id: $lotId,
quantityFulfilled: $newQuantity,
cbm: $newCbm
}
]
}) {
purchaseOrder {
orderReferenceNumber
orderedLineItems {
product {
skuCode
}
erpLineId
lots {
id
quantityFulfilled
cbm
}
}
}
}
}
Remember to substitute this variable for the UUID of a purchase order you've created in your own account. If you need an ID, see the purchaseOrders query to retrieve one based on the order reference number you supplied earlier
Variables
{
"lineItemId": "YOUR_LINE_ITEM_ID",
"lotId": "YOUR_LOT_ID",
"newCbm": 36.5,
"newQuantity": 48000,
"erpLineId": "YOUR_NEW_ERP_LINE_ID"
}
JSON Response
{
"data": {
"purchaseOrdersUpdateLots": {
"purchaseOrder": {
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"lots": [
{
"cbm": 32.0,
"id": "f48751b3-d47b-4fd1-95ac-ae861d6d7002",
"quantityFulfilled": 10000
}
],
"product": {
"skuCode": "10000"
}
},
{
"lots": [
{
"cbm": 36.5,
"id": "e9c905be-a15c-4376-94f6-7122accf7437",
"quantityFulfilled": 40000
}
],
"erpLineId": "YOUR_NEW_ERP_LINE_ID",
"product": {
"skuCode": "20000"
}
}
]
}
}
}
}
As you can see, the lot's quantity and CBM were updated to the new values we specified in the payload. Now, when bookings are made, Zencargo can have up-to-date values for the quantity and CBM of SKUs in the PO.
As well as the quantity and volume of the goods in the Lot, we can also update the schedule: the cargo ready date of the goods and the estimated delivery date.
Updating Lot schedules
Imagine that the our ERP also gets updated to indicate that the cargo ready date of that sku, 20000, has also been pushed back from the 16th of March to the 24th. To update this information, we need to use a different mutation, purchaseOrdersUpdateLotEstimates.
It works broadly the same as the previous section: we need to retrieve the lot IDs for the objects we want to update (we don't need ordered line item IDs here) and then we fire over the mutation:
POST /graphql
Query
mutation($lotId: String!, $newCargoReadyDate: Date!) {
purchaseOrdersUpdateLotEstimates(input: {
lotIds: [ $lotId ],
cargoReadyDate: {
date: $newCargoReadyDate
}
}) {
purchaseOrder {
orderReferenceNumber
orderedLineItems {
product {
skuCode
}
erpLineId
lots {
id
cargoReadyDate {
date
}
}
}
}
}
}
Remember to substitute this variable for the UUID of a purchase order you've created in your own account. If you need an ID, see the purchaseOrders query to retrieve one based on the order reference number you supplied earlier
Variables
{
"lotId": "YOUR_LOT_ID",
"newCargoReadyDate": "2021-03-24"
}
JSON Response
{
"data": {
"purchaseOrdersUpdateLotEstimates": {
"purchaseOrder": {
"orderReferenceNumber": "PO-SEAWARD-2",
"orderedLineItems": [
{
"lots": [
{
"cargoReadyDate": {
"date": "2021-03-16"
},
"id": "f48751b3-d47b-4fd1-95ac-ae861d6d7002"
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "10000"
}
},
{
"lots": [
{
"cargoReadyDate": {
"date": "2021-03-24"
},
"id": "e9c905be-a15c-4376-94f6-7122accf7437"
}
],
"erpLineId": "YOUR_ERP_LINE_ID",
"product": {
"skuCode": "20000"
}
}
]
}
}
}
}
In this case, we're only sending over a new cargoReadyDate, but if we knew a new delivery estimate we could send that over too.
You'll also notice that only one of the lots in the order were updated. This is by design: it allows you to specify details about a purchase order down to the SKU level. If we wanted to update all Lots inside an order, our input object allowed us to specify an array of Lot IDs. Explore the InputObject type to see your options here.
Next Steps
- 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.