Stock synchronization - examples
Johann Sonnenberger avatar
Written by Johann Sonnenberger
Updated over a week ago

Webhook: sales_order_finished

This webhook will send as payload a sales order which has been already picked, packed, and shipped in PULPO WMS. As products have already left the warehouse, in this case, the stock should always be reduced.

Example of sales_order_finished webhook payload:

{
"warehouse_id": 42,
"warehouse_name": "warehouse_1",
"updated_at": "2020-06-26T13:29:51",
"type": "sales_order_finished",
"status": "triggered",
"inserted_at": "2020-06-26T13:29:51",
"id": "db6fe13f-781b-4c52-8953-2a57be28e9d1",
"data": {
"attributes": {},
"warehouse_id": 42,
"warehouse": {
"zip_code": "93880",
"tenant_id": 43,
"state": "Arkansas",
"site": "Suite 343",
"priority": 180,
"phone": "1592943142382-0397702894",
"name": "warehouse_1",
"line2": "Apt. 182",
"line1": "40673 Griffin Way",
"id": 42,
"fax": "1592943142382-5804679",
"country": "Tanzania",
"city": "New Karine",
"active": true
},
"updated_at": "2020-06-23T20:39:33",
"type": "sales_order",
"third_party_id": 90593,
"state": "ended",
"ship_to": "0670 Grady Trail Apt. 244",
"return_labels": [],
"priority": 5,
"packing_location_id": 591432,
"order_num": "ORDER_3",
"notes": "Provident et qui perferendis in excepturi.",
"items": [
{
"state": null,
"required_date": null,
"quantity": 3,
"product_id": 1,
"product": {
"width": 1,
"weight": 26,
"volume": 1,
"units_per_sales_package": 1,
"units_per_purchase_package": 1,
"third_party_id": 90593,
"tenant_id": 43,
"supplier_product_id": "P-1592943142562-05135",
"stackable": true,
"sku": "52068",
"sales_measure_units": "BOX",
"purchase_measure_units": "BOX",
"product_categories": [
{
"tenant_id": 43,
"name": "hazardous",
"id": 4693,
"code": "hazardous"
}
],
"name": "product_serial_1",
"minimum_sales_unit": 1,
"minimum_purchase_unit": 1,
"management_type": "serial",
"length": 1,
"id": 131289,
"height": 1,
"description": "",
"cost_price": 1,
"batch_control": false,
"barcodes": [
"product_serial_1_barcode"
],
"attributes": {},
"attachments": [],
"active": true
},
"id": 233419,
"attributes": {},
"batches": []
},
{
"state": null,
"required_date": null,
"quantity": 1,
"product_id": 5,
"product": {
"width": 1,
"weight": 50,
"volume": 1,
"units_per_sales_package": 1,
"units_per_purchase_package": 1,
"third_party_id": 90593,
"tenant_id": 43,
"supplier_product_id": "P-1592943142526-02089",
"stackable": true,
"sku": "87609",
"sales_measure_units": "BOX",
"purchase_measure_units": "BOX",
"name": "product_lot_1",
"minimum_sales_unit": 1,
"minimum_purchase_unit": 1,
"management_type": "lot",
"length": 1,
"id": 5,
"height": 1,
"description": "",
"cost_price": 1,
"batch_control": false,
"barcodes": [
"product_lot_1_barcode"
],
"attributes": {},
"attachments": [],
"active": true
},
"id": 233420,
"attributes": {},
"batches": []
},
{
"state": null,
"required_date": null,
"quantity": 1,
"product_id": 9,
"product": {
"width": 1,
"weight": 42,
"volume": 1,
"units_per_sales_package": 1,
"units_per_purchase_package": 1,
"third_party_id": 90593,
"tenant_id": 43,
"supplier_product_id": "P-1592943142552-38767",
"stackable": true,
"sku": "8193",
"sales_measure_units": "BOX",
"purchase_measure_units": "BOX",
"product_categories": [
{
"tenant_id": 43,
"name": "pick",
"id": 4692,
"code": "pick"
}
],
"name": "product_none_1",
"minimum_sales_unit": 1,
"minimum_purchase_unit": 1,
"management_type": "none",
"length": 1,
"id": 9,
"height": 1,
"description": "",
"cost_price": 1,
"batch_control": false,
"barcodes": [
"product_none_1_barcode"
],
"attributes": {},
"attachments": [],
"active": true
},
"id": 233421,
"attributes": {},
"batches": []
}
],
"is_cart": false,
"inserted_at": "2020-06-23T20:12:23",
"id": 163008,
"destination_warehouse_id": null,
"destination_warehouse": null,
"delivery_date": "2020-07-07T20:12:23",
"criterium": "Ebay",
"attachments": []
}
}

The sales order information is returned in response.data which contains all items included in the sales order along with the quantity and the product for each one.

In this case, iterate over each item and reduce the current quantity of each product by the quantity of the sales item.

  • For product with sku 52068 (data.items[0].product.sku) → current stock of this product should be reduced by 3, which is the quantity of the item (data.items[0].quantity)

  • For product with sku 87609 (data.items[0].product.sku) → current stock of this product should be reduced by 5, which is the quantity of the item (data.items[1].quantity)

  • For product with sku 8193 (data.items[2].product.sku) → current stock of this product should be reduced by 1, which is the quantity of the item (data.items[2].quantity)

In every payload, each item contains the whole data of the product, in case the customer identifies their products with a different attribute in the connected system.

Webhook: incoming_good_created

This webhook will be triggered each time new incoming goods are created in PulpoWMS.

The incoming good can be created manually or it can be created from an existing purchase order (in which case the purchase order information is also returned in the payload data.purchase_order)

Example of incoming_good_created webhook payload:

{
"webhook_id": null,
"warehouse_name": "warehouse_1",
"warehouse_id": 4177,
"updated_at": "2021-02-25T14:12:07",
"type": "incoming_good_created",
"status": "triggered",
"inserted_at": "2021-02-25T14:12:07",
"id": "3e671766-edae-4730-b0c9-fa081fa94f74",
"data": {
"items": [
{
"attachments": [],
"batch": null,
"destination_location_id": 349833,
"id": 2143,
"notes": null,
"product": {
"units_per_sales_package": 1,
"width": 0.15,
"length": 0.5,
"height": 0.15,
"name": "111",
"third_party_id": 29936,
"product_categories": [],
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"7452351231285"
],
"management_type": "none",
"attributes": {},
"cost_price": 0,
"weight": 50,
"units_per_purchase_package": 1,
"volume": 0.0113,
"id": 105333,
"sales_measure_units": "Colli",
"description": null,
"sku": "1015"
},
"quantity": 10,
"state": "accepted"
},
{
"attachments": [],
"batch": null,
"destination_location_id": 349833,
"id": 2144,
"notes": null,
"product": {
"units_per_sales_package": 1,
"width": 0.15,
"length": 0.15,
"height": 0.2,
"name": "128",
"third_party_id": 29934,
"product_categories": [],
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"1032_barcode"
],
"management_type": "none",
"attributes": {},
"cost_price": 1,
"weight": 2.2,
"units_per_purchase_package": 1,
"volume": 0.0045,
"id": 105350,
"sales_measure_units": "Colli",
"description": null,
"sku": "1032"
},
"quantity": 3,
"state": "accepted"
},
{
"attachments": [],
"batch": null,
"destination_location_id": 349837,
"id": 2145,
"notes": null,
"product": {
"units_per_sales_package": 1,
"width": 0.15,
"length": 0.15,
"height": 0.2,
"name": "128",
"third_party_id": 29934,
"product_categories": [],
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"1032_barcode"
],
"management_type": "none",
"attributes": {},
"cost_price": 1,
"weight": 2.2,
"units_per_purchase_package": 1,
"volume": 0.0045,
"id": 105350,
"sales_measure_units": "Colli",
"description": null,
"sku": "1032"
},
"quantity": 2,
"state": "rejected"
}
],
"sequence_number": "IG-0000001",
"start_date": "2021-12-02T14:13:53",
"purchase_order": {
"items": [
{
"attributes": {},
"checked_quantity": 10,
"id": 114466,
"product": null,
"product_id": 105333,
"requested_quantity": 10,
"state": "received"
},
{
"attributes": {},
"checked_quantity": 5,
"id": 114467,
"product": null,
"product_id": 105350,
"requested_quantity": 5,
"state": "received"
}
],
"notes": null,
"attachments": [],
"state": "closed",
"order_num": "PO 123",
"warehouse_id": 4177,
"attributes": {},
"updated_at": "2021-12-02T14:15:29",
"delivery_date": "2021-12-02T14:12:24",
"type": "purchase_order",
"id": 37046
},
"attachments": [],
"end_date": "2021-12-02T14:15:29",
"owner": {
"location_id": 349739,
"active": true,
"employee_id": "pulpo_stock_666_333_477",
"tenant_id": 3808,
"erp_tenant_id": null,
"last_name": "Vandervort",
"username": "user_1",
"language": "en",
"first_name": "Abner",
"type": "admin",
"id": 7219,
"email": "Abner.Vandervort@wms.com"
},
"warehouse_id": 4177,
"inserted_at": "2021-12-02T14:15:29",
"id": 981,
"document_type": "purchase_order",
"sales_order_id": null
}
}

The incoming goods information are returned in response.data.items

Each item can be either accepted or rejected in the moment of its reception. Based on this, the customer should handle rejected items adding or ignoring the stock, depending on its operations.

In this case, iterate over each item and increase the current quantity of each product by the quantity of the item.

  • For product with sku 1015 (data.items[0].product.sku) → current stock of this product should be increased by 10, which is the quantity of the item (data.items[0].quantity) as this product was accepted (data.items[0].state).

  • For product with sku 1032 (data.items[1].product.sku) → current stock of this product should be increased by 3, which is the quantity of the item (data.items[1].quantity) as this product was accepted (data.items[1].state).

  • For product with sku 1032 - rejected (data.items[2].product.sku) → Based on the customer’s operations this item could increase the product’s quantity by 2 or could be ignored

Webhook: replenishment_order_created

This webhook will be triggered each time a replenishment order is created in PulpoWMS. Replenishment orders can be of the following types: manual. incoming_goods, supply, sales_order_cancelled, return, kitting, batched and kit_move

For modifications in stock quantities, this webhook should be ignored as usual movements are inside the warehouse, except for the kit_move type, in which a new kit is created and quantity for this kit should be increased.

Example of replenishment_order_created webhook payload:

{
"warehouse_name": "warehouse_1",
"warehouse_id": 4177,
"updated_at": "2020-10-15T22:56:48",
"type": "replenishment_order_created",
"status": "triggered",
"inserted_at": "2020-10-15T22:56:48",
"id": "2f64a394-a2e8-4a3a-985b-90a4f7df0f30",
"data": {
"items": [
{
"replenishment_order_id": 11669,
"batches": [],
"origin_location_type": {
"name": "Kitting Location Type"
},
"confirmed_quantity": 0,
"product_id": 105310,
"origin_location_id": 349821,
"product": {
"units_per_sales_package": 1,
"width": 1,
"length": 1,
"height": 1,
"name": "product_none_1",
"third_party_id": 29931,
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"product_none_1_barcode"
],
"management_type": "none",
"attributes": {
"attribute": "Consequatur aut sed eum quas ut.",
"image_url": "https://pulpo-public-images.s3.us-east-2.amazonaws.com/none1.png"
},
"cost_price": 1,
"weight": 6,
"units_per_purchase_package": 1,
"volume": 1,
"id": 105310,
"sales_measure_units": "BOX",
"description": "Sint et veritatis sint aspernatur aut.",
"sku": "product_none_1_sku"
},
"destination_location_type": {
"name": "Crossdocking Location Type"
},
"destination_location_id": 349817,
"id": 32525,
"requested_quantity": 1
}
],
"sequence_number": "RE-0000006",
"start_date": null,
"state": "queue",
"end_date": null,
"owner": {
"location_id": 349739,
"active": true,
"employee_id": "pulpo_stock_666_333_477",
"tenant_id": 3808,
"erp_tenant_id": null,
"last_name": "Vandervort",
"username": "user_1",
"language": "en",
"first_name": "Abner",
"type": "admin",
"id": 7219,
"email": "Abner.Vandervort@wms.com"
},
"warehouse_id": 4177,
"inserted_at": "2021-12-02T14:50:01",
"type": "kit_move",
"id": 11669
}
}

In this case, first verify the type of the replenishment order created (data.type). In case it is not a kit_move, this webhook can be ignored. Otherwise, iterate over the items increasing the current stock for each item’s product with the item’s requested quantity

  • For product with sku product_none_1_sku (data.items[0].product.sku): Current stock for this product should be increased by 1, the requested quantity of the item (data.items[0].requested_quantity)

Webhook: replenishment_order_finished

This webhook will be triggered each time a replenishment order is finished in PulpoWMS. As mentioned, in this case, stock should be modified when a replenishment has type kitting, as products that were used to create a kit, are no longer available for a different purpose.

Example of replenishment_order_finished webhook payload:

{
"warehouse_id": 4177,
"warehouse_name": "warehouse_1",
"updated_at": "2020-10-13T16:27:59",
"type": "replenishment_order_finished",
"status": "triggered",
"inserted_at": "2020-10-13T16:27:59",
"id": "cbbefb3e-8f7e-47c5-a613-f053977fa711",
"data": {
"items": [
{
"replenishment_order_id": 11668,
"batches": [
{
"batch_id": null,
"id": 1008,
"quantity": 4,
"replenishment_item_id": 32523
}
],
"origin_location_type": {
"name": "Storage Location Type"
},
"confirmed_quantity": 4,
"product_id": 105312,
"origin_location_id": 349756,
"product": {
"units_per_sales_package": 1,
"width": 1,
"length": 1,
"height": 1,
"name": "product_none_3",
"third_party_id": 29931,
"product_categories": [
{
"code": "cold",
"id": 27072,
"name": "cold"
},
{
"code": "volume",
"id": 27073,
"name": "volume"
},
{
"code": "heavy",
"id": 27071,
"name": "heavy"
}
],
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"product_none_3_barcode"
],
"management_type": "none",
"attributes": {
"attribute": "Non reprehenderit rerum ex ut ut.",
"image_url": "https://pulpo-public-images.s3.us-east-2.amazonaws.com/none0.png"
},
"cost_price": 1,
"weight": 43,
"units_per_purchase_package": 1,
"volume": 1,
"id": 105312,
"sales_measure_units": "BOX",
"description": "Ratione molestiae consequuntur placeat eos error!",
"sku": "product_none_3_sku"
},
"destination_location_type": {
"name": "Kitting Location Type"
},
"destination_location_id": 349821,
"id": 32523,
"requested_quantity": 4
},
{
"replenishment_order_id": 11668,
"batches": [
{
"batch_id": null,
"id": 1009,
"quantity": 6,
"replenishment_item_id": 32524
}
],
"origin_location_type": {
"name": "Storage Location Type"
},
"confirmed_quantity": 6,
"product_id": 105311,
"origin_location_id": 349792,
"product": {
"units_per_sales_package": 1,
"width": 1,
"length": 1,
"height": 1,
"name": "product_none_2",
"third_party_id": 29931,
"product_categories": [
{
"code": "volume",
"id": 27073,
"name": "volume"
},
{
"code": "hazardous",
"id": 27069,
"name": "hazardous"
}
],
"third_party": {},
"tenant_id": 3808,
"barcodes": [
"product_none_2_barcode"
],
"management_type": "none",
"attributes": {
"attribute": "Ipsam quis molestiae architecto sit ratione?",
"image_url": "https://pulpo-public-images.s3.us-east-2.amazonaws.com/none2.png"
},
"cost_price": 1,
"weight": 32,
"units_per_purchase_package": 1,
"volume": 1,
"id": 105311,
"sales_measure_units": "BOX",
"description": "Maxime ab voluptas repellendus assumenda repudiandae.",
"sku": "product_none_2_sku"
},
"destination_location_type": {
"name": "Kitting Location Type"
},
"destination_location_id": 349821,
"id": 32524,
"requested_quantity": 6
}
],
"sequence_number": "RE-0000005",
"start_date": "2021-12-02T14:48:51",
"state": "ended",
"end_date": "2021-12-02T14:50:00",
"owner": {
"location_id": 349739,
"active": true,
"employee_id": "pulpo_stock_666_333_477",
"tenant_id": 3808,
"erp_tenant_id": null,
"last_name": "Vandervort",
"username": "user_1",
"language": "en",
"first_name": "Abner",
"type": "admin",
"id": 7219,
"email": "Abner.Vandervort@wms.com"
},
"warehouse_id": 4177,
"inserted_at": "2021-12-02T14:48:21",
"type": "kitting",
"id": 11668
}
}


In this case, first verify the type of the replenishment order finished (data.type). In case it is not a kitting type, this webhook can be ignored. Otherwise, iterate over the items reducing the current stock for each item’s product by the item’s confirmed quantity

  • For product with sku product_none_3_sku (data.items[0].product.sku): Current stock for this product should be reduced by 4, the confirmed quantity of the item (data.items[0].confirmed_quantity)

  • For product with sku product_none_2_sku (data.items[1].product.sku): Current stock for this product should be reduced by 6, the confirmed quantity of the item (data.items[1].confirmed_quantity)

Webhook: counting_task_closed

This webhook will be triggered each time a counting task has been audited and finished in PulpoWMS.

This task can reduced. increased or not operate over the stock based on each item is_valid attribute and the difference between the counted items (item.quantity) and the current stock in the system.

When is_valid = true, it means the difference in the stock was accepted by the auditor and change can be made in the stock, if is_valid = false, these items can be ignored.

Example of replenishment_order_finished webhook payload:

{
"warehouse_id": 4177,
"warehouse_name": "warehouse_1",
"updated_at": "2020-06-26T15:54:15",
"type": "counting_task_closed",
"status": "triggered",
"inserted_at": "2020-06-26T15:54:15",
"id": "49e14038-2110-4612-83c6-bca727c93c93",
"data": {
"items": [
{
"batch_id": null,
"location_type": {
"name": "Storage Location Type"
},
"location_id": 349741,
"is_valid": true,
"quantity": 90,
"product_id": 105346,
"count_iteration": 1,
"product": {
"units_per_sales_package": 1,
"width": 0.15,
"length": 0.15,
"height": 0.2,
"name": "124",
"third_party_id": 29934,
"product_categories": null,
"third_party": {},
"tenant_id": 3808,
"barcodes": null,
"management_type": "none",
"attributes": {},
"cost_price": 2,
"weight": 2.2,
"units_per_purchase_package": 1,
"volume": 0.0045,
"id": 105346,
"sales_measure_units": "Unverpackt",
"description": null,
"sku": "1028"
},
"attachments": [],
"current_stock_quantity": 93,
"id": 2626,
"counter_id": 7219
},
{
"batch_id": null,
"location_type": {
"name": "Storage Location Type"
},
"location_id": 349741,
"is_valid": false,
"quantity": 30,
"product_id": 105419,
"count_iteration": 1,
"product": {
"units_per_sales_package": 1,
"width": 0.3,
"length": 0.2,
"height": 0.02,
"name": "Pullover \"Baltic\" 1 1135",
"third_party_id": 29932,
"product_categories": null,
"third_party": {},
"tenant_id": 3808,
"barcodes": null,
"management_type": "none",
"attributes": {},
"cost_price": 2,
"weight": 0.5,
"units_per_purchase_package": 1,
"volume": 0.0012,
"id": 105419,
"sales_measure_units": "Colli",
"description": null,
"sku": "1134"
},
"attachments": [],
"current_stock_quantity": 30,
"id": 2627,
"counter_id": 7219
},
{
"batch_id": null,
"location_type": {
"name": "Storage Location Type"
},
"location_id": 349741,
"is_valid": true,
"quantity": 4,
"product_id": 105439,
"count_iteration": 1,
"product": {
"units_per_sales_package": 1,
"width": 0.3,
"length": 0.2,
"height": 0.02,
"name": "Pullover \"Baltic\" 1 1135",
"third_party_id": 29932,
"product_categories": null,
"third_party": {},
"tenant_id": 3808,
"barcodes": null,
"management_type": "none",
"attributes": {},
"cost_price": 4,
"weight": 0.5,
"units_per_purchase_package": 1,
"volume": 0.0012,
"id": 105439,
"sales_measure_units": "Colli",
"description": null,
"sku": "1154"
},
"attachments": [],
"current_stock_quantity": 0,
"id": 2628,
"counter_id": 7219
},
{
"batch_id": null,
"location_type": {
"name": "Storage Location Type"
},
"location_id": 349741,
"is_valid": false,
"quantity": 101,
"product_id": 105333,
"count_iteration": 1,
"product": {
"units_per_sales_package": 1,
"width": 0.15,
"length": 0.5,
"height": 0.15,
"name": "111",
"third_party_id": 29936,
"product_categories": null,
"third_party": {},
"tenant_id": 3808,
"barcodes": null,
"management_type": "none",
"attributes": {},
"cost_price": 10,
"weight": 50,
"units_per_purchase_package": 1,
"volume": 0.0112,
"id": 105333,
"sales_measure_units": "Colli",
"description": null,
"sku": "1015"
},
"attachments": [],
"current_stock_quantity": 96,
"id": 2625,
"counter_id": 7219
}
],
"location_id": 349741,
"sequence_number": "CT-0000001",
"owner_id": 7219,
"product_id": null,
"count_iteration": 1,
"product": null,
"attachments": [],
"state": "closed",
"location": {
"dimension_height": 80,
"zone_code": "zone_1",
"rack_id": 20693,
"priority": null,
"level": 1,
"active": true,
"position": 1,
"available": true,
"dimension_depth": 100,
"module": 1,
"dimension_width": 120,
"code": "zone_1-1-1-1-1-1",
"zone_id": 27463,
"is_volume": false,
"is_defined": true,
"hallway": 1,
"location_type_id": 2,
"attributes": {
"is_defined": true,
"position_left": 5,
"position_top": 3
},
"deleted_at": null,
"row": 1,
"id": 349741,
"deleted_by": null
},
"warehouse_id": 4177,
"inserted_at": "2021-12-02T15:15:13",
"type": "location",
"id": 3443,
"auditor_id": 7219,
"description": null,
"counter_id": 7219,
"auditor": {
"location_id": 349739,
"active": true,
"employee_id": "pulpo_stock_666_333_477",
"tenant_id": 3808,
"erp_tenant_id": null,
"last_name": "Vandervort",
"username": "user1",
"language": "en",
"first_name": "Abner",
"type": "admin",
"id": 7219,
"email": "Abner.Vandervort@wms.com"
},
"group": null
}
}

In this case take the items (data.items), filter by the ones is_valid = true, and iterate over the valid items calculating the difference given by item.quantity - item.current_stock_quantity. In case the result is 0, no modification in the stock should be done, for positive difference, stock should be increased and for negative difference the stock should be reduced.

In the example, valid items are products with sku 1154 and 1028

  • For product with sku 1028: The current stock of this product should be reduced by 3, as:
    90 (item[0].quantity) - 93 (item[0].current_stock_quantity) = -3

  • For product with sku 1154: The current stock of this product should be increased by 4, as:
    4 (item[2].quantity) - 0 (item[2].current_stock_quantity) = 4

Did this answer your question?