Goods receipt BPMN example
Goods receipt is the gate between a supplier delivery and your stock records: unload, match against the purchase order, inspect, and post the receipt. Warehouses map it because it sits on the boundary of three functions with different incentives, and because errors here cascade into wrong stock figures and disputed supplier invoices. The classic failure is booking goods in before anyone has checked what actually arrived.
The model is a single pool with Warehouse, Quality, and Finance lanes. Two exclusive gateways guard the flow: one checks the delivery against the purchase order, the other checks physical condition, and both failure branches converge on the same discrepancy path. That convergence is the modelling choice worth noticing: one rejection procedure handles both problems, so the diagram avoids duplicating tasks.
Standard BPMN 2.0 interchange XML: opens in Camunda Modeler, Signavio, Bizagi, and any other compliant tool.
The process at a glance
How to read this diagram
Everything begins when a delivery arrives at the Warehouse lane. Staff unload the delivery and match it to the purchase order, and the gateway "Delivery matches PO?" makes the first decision. Its No branch, the default, records a discrepancy, sends a notification to the supplier, and finishes at the "Delivery rejected" end event. The Yes branch passes the goods to the Quality lane, where an inspector checks their condition.
At the second gateway, "Goods undamaged?", a No result routes to the same discrepancy task the first gateway uses, so both rejection reasons share one exit. A Yes result returns the goods to the Warehouse for putaway, after which Finance posts the goods receipt note and the process ends at "Receipt posted". The two end events split the outcomes cleanly: stock is either on the shelf and in the ledger, or formally rejected with the supplier informed.
BPMN elements used
| Element | Count | In this diagram |
|---|---|---|
| Start event | 1 | Delivery arrived |
| End event | 2 | Delivery rejected, Receipt posted |
| Task | 4 | Unload delivery, Match delivery to PO, Record discrepancy, Put away stock |
| User task | 1 | Inspect goods condition |
| Service task | 1 | Post goods receipt note |
| Send task | 1 | Notify supplier |
| Exclusive gateway | 2 | Delivery matches PO?, Goods undamaged? |
View the BPMN 2.0 XML for this diagram
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="swimdraft" exporterVersion="1.0">
<bpmn2:collaboration id="Collaboration_1">
<bpmn2:participant id="pool_gr" name="Goods receipt" processRef="Process_pool_gr" />
</bpmn2:collaboration>
<bpmn2:process id="Process_pool_gr" isExecutable="false">
<bpmn2:laneSet id="LaneSet_pool_gr">
<bpmn2:lane id="lane_gr_wh" name="Warehouse">
<bpmn2:flowNodeRef>start_gr</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_gr_unload</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_gr_match</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>g_gr_match</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_gr_discrep</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_gr_notify</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>end_gr_rej</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_gr_putaway</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_gr_qa" name="Quality">
<bpmn2:flowNodeRef>t_gr_inspect</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>g_gr_cond</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_gr_fin" name="Finance">
<bpmn2:flowNodeRef>t_gr_grn</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>end_gr_ok</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="start_gr" name="Delivery arrived">
<bpmn2:outgoing>fgr1</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="t_gr_unload" name="Unload delivery">
<bpmn2:incoming>fgr1</bpmn2:incoming>
<bpmn2:outgoing>fgr2</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="t_gr_match" name="Match delivery to PO">
<bpmn2:incoming>fgr2</bpmn2:incoming>
<bpmn2:outgoing>fgr3</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:exclusiveGateway id="g_gr_match" name="Delivery matches PO?" default="fgr5">
<bpmn2:incoming>fgr3</bpmn2:incoming>
<bpmn2:outgoing>fgr4</bpmn2:outgoing>
<bpmn2:outgoing>fgr5</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:userTask id="t_gr_inspect" name="Inspect goods condition">
<bpmn2:incoming>fgr4</bpmn2:incoming>
<bpmn2:outgoing>fgr6</bpmn2:outgoing>
</bpmn2:userTask>
<bpmn2:exclusiveGateway id="g_gr_cond" name="Goods undamaged?" default="fgr8">
<bpmn2:incoming>fgr6</bpmn2:incoming>
<bpmn2:outgoing>fgr7</bpmn2:outgoing>
<bpmn2:outgoing>fgr8</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:task id="t_gr_discrep" name="Record discrepancy">
<bpmn2:incoming>fgr5</bpmn2:incoming>
<bpmn2:incoming>fgr8</bpmn2:incoming>
<bpmn2:outgoing>fgr9</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sendTask id="t_gr_notify" name="Notify supplier">
<bpmn2:incoming>fgr9</bpmn2:incoming>
<bpmn2:outgoing>fgr10</bpmn2:outgoing>
</bpmn2:sendTask>
<bpmn2:endEvent id="end_gr_rej" name="Delivery rejected">
<bpmn2:incoming>fgr10</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:task id="t_gr_putaway" name="Put away stock">
<bpmn2:incoming>fgr7</bpmn2:incoming>
<bpmn2:outgoing>fgr11</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:serviceTask id="t_gr_grn" name="Post goods receipt note">
<bpmn2:incoming>fgr11</bpmn2:incoming>
<bpmn2:outgoing>fgr12</bpmn2:outgoing>
</bpmn2:serviceTask>
<bpmn2:endEvent id="end_gr_ok" name="Receipt posted">
<bpmn2:incoming>fgr12</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="fgr1" sourceRef="start_gr" targetRef="t_gr_unload" />
<bpmn2:sequenceFlow id="fgr2" sourceRef="t_gr_unload" targetRef="t_gr_match" />
<bpmn2:sequenceFlow id="fgr3" sourceRef="t_gr_match" targetRef="g_gr_match" />
<bpmn2:sequenceFlow id="fgr4" name="Yes" sourceRef="g_gr_match" targetRef="t_gr_inspect">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="fgr5" name="No" sourceRef="g_gr_match" targetRef="t_gr_discrep" />
<bpmn2:sequenceFlow id="fgr6" sourceRef="t_gr_inspect" targetRef="g_gr_cond" />
<bpmn2:sequenceFlow id="fgr7" name="Yes" sourceRef="g_gr_cond" targetRef="t_gr_putaway">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="fgr8" name="No" sourceRef="g_gr_cond" targetRef="t_gr_discrep" />
<bpmn2:sequenceFlow id="fgr9" sourceRef="t_gr_discrep" targetRef="t_gr_notify" />
<bpmn2:sequenceFlow id="fgr10" sourceRef="t_gr_notify" targetRef="end_gr_rej" />
<bpmn2:sequenceFlow id="fgr11" sourceRef="t_gr_putaway" targetRef="t_gr_grn" />
<bpmn2:sequenceFlow id="fgr12" sourceRef="t_gr_grn" targetRef="end_gr_ok" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="pool_gr_di" bpmnElement="pool_gr" isHorizontal="true">
<dc:Bounds x="20" y="20" width="1420" height="500" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_gr_wh_di" bpmnElement="lane_gr_wh" isHorizontal="true">
<dc:Bounds x="50" y="20" width="1390" height="240" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_gr_qa_di" bpmnElement="lane_gr_qa" isHorizontal="true">
<dc:Bounds x="50" y="260" width="1390" height="130" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_gr_fin_di" bpmnElement="lane_gr_fin" isHorizontal="true">
<dc:Bounds x="50" y="390" width="1390" height="130" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="start_gr_di" bpmnElement="start_gr">
<dc:Bounds x="112" y="59" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="91" y="101" width="79" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_unload_di" bpmnElement="t_gr_unload">
<dc:Bounds x="230" y="37" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_match_di" bpmnElement="t_gr_match">
<dc:Bounds x="380" y="37" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="g_gr_match_di" bpmnElement="g_gr_match">
<dc:Bounds x="555" y="52" width="50" height="50" />
<bpmndi:BPMNLabel><dc:Bounds x="524" y="32" width="112" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_inspect_di" bpmnElement="t_gr_inspect">
<dc:Bounds x="680" y="277" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="g_gr_cond_di" bpmnElement="g_gr_cond">
<dc:Bounds x="855" y="292" width="50" height="50" />
<bpmndi:BPMNLabel><dc:Bounds x="829" y="272" width="102" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_discrep_di" bpmnElement="t_gr_discrep">
<dc:Bounds x="980" y="37" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_notify_di" bpmnElement="t_gr_notify">
<dc:Bounds x="1130" y="37" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="end_gr_rej_di" bpmnElement="end_gr_rej">
<dc:Bounds x="1312" y="59" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="1288" y="101" width="84" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_putaway_di" bpmnElement="t_gr_putaway">
<dc:Bounds x="980" y="147" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_gr_grn_di" bpmnElement="t_gr_grn">
<dc:Bounds x="1130" y="407" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="end_gr_ok_di" bpmnElement="end_gr_ok">
<dc:Bounds x="1312" y="429" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="1292" y="471" width="76" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="fgr1_di" bpmnElement="fgr1">
<di:waypoint x="148" y="77" />
<di:waypoint x="230" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr2_di" bpmnElement="fgr2">
<di:waypoint x="330" y="77" />
<di:waypoint x="380" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr3_di" bpmnElement="fgr3">
<di:waypoint x="480" y="77" />
<di:waypoint x="555" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr4_di" bpmnElement="fgr4">
<di:waypoint x="605" y="77" />
<di:waypoint x="660" y="77" />
<di:waypoint x="660" y="317" />
<di:waypoint x="680" y="317" />
<bpmndi:BPMNLabel><dc:Bounds x="611" y="57" width="21" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr5_di" bpmnElement="fgr5">
<di:waypoint x="605" y="77" />
<di:waypoint x="980" y="77" />
<bpmndi:BPMNLabel><dc:Bounds x="611" y="83" width="17" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr6_di" bpmnElement="fgr6">
<di:waypoint x="780" y="317" />
<di:waypoint x="855" y="317" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr7_di" bpmnElement="fgr7">
<di:waypoint x="905" y="317" />
<di:waypoint x="960" y="317" />
<di:waypoint x="960" y="187" />
<di:waypoint x="980" y="187" />
<bpmndi:BPMNLabel><dc:Bounds x="911" y="297" width="21" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr8_di" bpmnElement="fgr8">
<di:waypoint x="905" y="317" />
<di:waypoint x="960" y="317" />
<di:waypoint x="960" y="77" />
<di:waypoint x="980" y="77" />
<bpmndi:BPMNLabel><dc:Bounds x="911" y="323" width="17" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr9_di" bpmnElement="fgr9">
<di:waypoint x="1080" y="77" />
<di:waypoint x="1130" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr10_di" bpmnElement="fgr10">
<di:waypoint x="1230" y="77" />
<di:waypoint x="1312" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr11_di" bpmnElement="fgr11">
<di:waypoint x="1080" y="187" />
<di:waypoint x="1110" y="187" />
<di:waypoint x="1110" y="447" />
<di:waypoint x="1130" y="447" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="fgr12_di" bpmnElement="fgr12">
<di:waypoint x="1230" y="447" />
<di:waypoint x="1312" y="447" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>Frequently asked questions
Is it valid for two gateways to route to the same rejection task?
Yes. BPMN allows any number of sequence flows to target one activity, and the merge is implicit: each arriving token simply runs the task. Reusing the discrepancy path keeps the model compact and guarantees both failure modes follow the identical procedure, which is usually exactly what the warehouse intends in practice.
Why is the condition check a user task rather than a plain task?
A user task signals work performed by a named person through some system, here an inspector recording results against acceptance criteria. A plain task is deliberately vague about who or what performs it. Marking inspection as a user task tells readers, and any future workflow engine, that a human decision sits at this point.
Where would a timer belong if the supplier never responds?
Attach the wait after "Notify supplier": add an intermediate timer catch event on a path that escalates to procurement if no credit note arrives within, say, ten working days. Swimdraft validates that the event has both incoming and outgoing flows, one of the 19 BPMN 2.0.2 rules it checks with clause citations.
Related BPMN examples
Order fulfilment
An order fulfilment process as a BPMN 2.0 diagram: stock check, backorder loop, picking, and dispatch confirmation. View the swimlanes and download the .bpmn file free.
Shipping and dispatch
A shipping and dispatch process as a BPMN 2.0 diagram: parallel packing and paperwork, customs branch, and departure. View the swimlanes and download the .bpmn free.
Inventory replenishment
An inventory replenishment process as a BPMN 2.0 diagram: reorder trigger, policy rules, approval branch, and supplier confirmation. Free .bpmn file download included.
Quality inspection
A quality inspection process as a BPMN 2.0 diagram: sampling, testing, tolerance decision, and a rework loop back through inspection. Download the .bpmn file free.
Generate your own version of this diagram
Describe how the process works in your organisation: plain English, meeting notes, a transcript, or a spreadsheet. Swimdraft turns it into a spec-validated BPMN 2.0 diagram you can edit in the browser and export as .bpmn, SVG, or PNG.
Start freeNo credit card required