Skip to main content
 
 
Splunk Lantern

PO Monitoring: Supplier performance on purchase orders process

 

This article shows you how to monitor how quickly suppliers respond to the purchase order and order changes. This is a key performance indicator for companies that need to monitor purchase order (PO) lifecycles. PO monitoring plays a critical role in maintaining effective communication and coordination between buyers and suppliers, ensuring that all parties are aligned and informed throughout the process, and enhancing overall supply chain visibility. A proactive approach minimizes the risk of errors or delays, enabling businesses to maintain efficient operations and uphold customer satisfaction.

KPI search example

This KPI pairs the initial EDI 850 (Purchase Order) with the EDI 855 (Purchase Order Acknowledgment) from the supplier. This ensures that there are no technical issues, and the supplier has indeed acknowledged the order. A pair of EDI 850 and 855 messages is a strong indicator that the purchase order will be successfully processed.

Using this dataset (EDI 850, 855), you can set thresholds for situations where a supplier fails to respond to the buyer's PO, as well as monitor overall business performance regarding how fast POs are being acknowledged by suppliers. To do this, group the search by edi_code IN (850, 855) and calculate the duration between these two events.

index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) 
| table _time edi_ack_status edi_buyer edi_code edi_code_ack edi_cont_num edi_date edi_flag edi_requestor edi_responder edi_seller edi_sequence edi_time edi_tr_id edi_type 
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status 
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack) 
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id 
| search edi_code_cnt>1
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24

The calculation of time_po_to_ack_time is applied to each purchase order and business process-level acknowledgment, indicating how long the supplier took to respond to the initial purchase order request. With this time data, shown in the following results, thresholds (such as SLAs) can be applied or averages can be calculated to monitor performance at various levels, such as by supplier, product, or order timing.

image14.png

Search explanations

Splunk search Explanation
index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) Select EDI X12 data by selecting sourcetype of edi:x12.
| table _time edi_ack_status edi_buyer edi_code edi_code_ack edi_cont_num edi_date edi_flag edi_requestor edi_responder edi_seller edi_sequence edi_time edi_tr_id edi_type Format the relevant fields into a table.
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack)
Create a new evaluated field edi_ack_status_combo that combines edi_code, edi_code_ack, edi_ack_statusfield. Use another evalcommand to create edi_code_groupby field to join all EDI events with EDI 997 acknowledgment events.
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id

Join all EDI events with EDI 997 (acknowledgment) events into a single event. A successfully joined event we'll have EDI edi_ack_status field that indicates there was a matching pair of EDI with EDI acknowledgment.

Those events with null values in edi_ack_status means that there's no matching pair of EDI acknowledgments. Events with successfully joined EDIs have “A”, “E”, “R” flags indicating it's status.

| search edi_code_cnt>1 Filter to select purchase order transactions (850) have received (855) events. 1 indicates no, more than 1 indicates EDIs with received ACK(855).
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24 Calculate time_po_to_ack_time, the time the supplier took to process the PO, then acknowledge it at the business level.

At this point, with the calculated time taken to receive a purchase order acknowledgment (EDI 855), which indicates the supplier has successfully acknowledged the order, we can measure their performance in handling orders. By applying another stats aggregation command, we can calculate the average time_po_to_ack_time by edi_responder. This provides insights into how responsive each supplier is in processing orders. While this summary gives an overview of supplier performance, we can also track it over time by analyzing trends. Using the stats and avg(time_po_to_ack_time) functions grouped by edi_responder, we can observe how suppliers' responsiveness evolves.

index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) 
| table _time edi_ack_status edi_buyer edi_code edi_code_ack edi_cont_num edi_date edi_flag edi_requestor edi_responder edi_seller edi_sequence edi_time edi_tr_id edi_type 
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status 
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack) 
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id 
| search edi_code_cnt>1
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24
| stats avg(time_po_to_ack_time) as avg_time_po_to_ack_time by edi_responder
| sort - avg_time_po_to_ack_time

The results display the performance of each supplier by calculating the average time it takes for them to acknowledge and respond to purchase order requests from the buyer. By using the sort command, we can identify suppliers with longer response times, which might indicate potential violations of business SLAs. On a positive note, in the example results below, all suppliers have responded to the purchase order requests.

image4.png

Use a bar chart visualization to identify which suppliers are experiencing difficulties and assess the severity of the issues.

image8.png

Monitoring performance trends over time for each supplier can provide valuable insights, helping to spot any spikes that might disrupt the flow of materials in the supply chain. By simply replacing the stats command with timechart, you can quickly shift the analysis to understand how suppliers have performed over time.

index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) 
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status 
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack) 
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id 
| search edi_code_cnt>1
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24
| timechart span=6h avg(time_po_to_ack_time) as avg_time_po_to_ack_time by edi_responder

image7.png

The average purchase order response time, broken down by supplier, helps identify any sudden changes that may indicate early operational issues.

Based on the performance of various suppliers in responding to purchase orders, we can establish a threshold of a certain number of days. In the previous example, three days seems to be the average time for supplier PO acknowledgment, so we will use this as a threshold to identify which supplier orders are at risk of delay. After calculating the time between the purchase order and the acknowledgement (time_po_to_ack_time), we apply a search condition to filter for orders where this calculated value exceeds three days. This can be done using the search condition: search time_po_to_ack_time>=3.

index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) 
| table _time edi_ack_status edi_buyer edi_code edi_code_ack edi_cont_num edi_date edi_flag edi_requestor edi_responder edi_seller edi_sequence edi_time edi_tr_id edi_type 
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status 
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack) 
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id 
| search edi_code_cnt>1
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24
| search time_po_to_ack_time>=3

The results display all EDI 850 Purchase Order (PO) requests where the supplier has not acknowledged the order for three days or more. Splunk SPL offers an easy and powerful way to calculate and apply logical conditions, such as this duration, directly within the search criteria.

image11.png

Search explanations

Splunk search Explanation
index=supply_chain_edi sourcetype="edi:x12" edi_code IN (850 855) Select EDI X12 data by selecting sourcetype of edi:x12.
| table _time edi_ack_status edi_buyer edi_code edi_code_ack edi_cont_num edi_date edi_flag edi_requestor edi_responder edi_seller edi_sequence edi_time edi_tr_id edi_type Format the relevant fields into a table.
| eval edi_ack_status_combo=edi_code+"-"+edi_code_ack+"-"+edi_ack_status
| eval edi_code_groupby=if(isnull(edi_code_ack), edi_code, edi_code_ack)
Create a new evaluated field edi_ack_status_combo that combines edi_code, edi_code_ack, edi_ack_statusfield. Use another evalcommand to create edi_code_groupby field to join all EDI events with EDI 997 acknowledgment events.
| stats last(_time) AS _time, earliest(_time) AS time_po, latest(_time) AS time_po_ack, last(edi_requestor) AS edi_requestor, last(edi_responder) AS edi_responder, first(edi_code) AS edi_type, values(edi_code) AS edi_code, dc(edi_code) AS edi_code_cnt, last(edi_ack_status) AS edi_ack_status BY edi_tr_id

Join all EDI events with EDI 997 (acknowledgment) events into a single event. A successfully joined event will have EDI edi_ack_status field that indicates there was a matching pair of EDI with EDI acknowledgment.

Events with null values in edi_ack_status means that there's no matching pair of EDI acknowledgments. Events with successfully joined EDIs have “A”, “E”, “R” flags indicating their status.

| search edi_code_cnt>1 Filter to select purchase order transactions (850) that have received (855) events. 1 indicates no, more than 1 indicates EDIs with received ACK(855).
| eval time_po_to_ack_time=(time_po_ack-time_po)/60/60/24 Calculate time_po_to_ack_time, the time the supplier took to process the PO, then acknowledge it at the business level.
| search time_po_to_ack_time>=3 Apply a threshold of 3 hrs as the SLA to filter for transactions that violates the limit.

Next steps

When you have this search running in your Splunk platform, return to the Monitoring purchase order lifecycles use case to learn how to share the results with stakeholders and to find other KPIs you might want to measure. You can also review the Supply Chain Optimization Solution Accelerator for more great use cases to help you use the Splunk platform to be successful in your supply chain operations.