Skip to content

URS-071 · Distributor returns expiring, expired, or recalled stock to the manufacturer

Title: Distributor returns expiring, expired, or recalled stock to the manufacturer Date: 2026-08-03T23:05:12.565Z Duration: 28.2s Overall Status: ✅ PASS

The system shall let a distributor return expiring, expired, or recalled stock to the manufacturer through a dedicated returns flow that records the return type, derives the return location from the selected lots, requires no sales account, and creates no replacement order; and shall record an audit decision when the replacement-order step is skipped.

Source: User_Requirement_Specifications_Vantis_DeviceFlow.xlsx — the run below proves the system meets this requirement.

Status: ✅ PASS

Each step below corresponds to one Playwright test that ran sequentially. Screenshots and video recordings provide visual evidence of the UI behaviour.

1. Step 1: Login and open the expiry return flow — ✅ PASS

Section titled “1. Step 1: Login and open the expiry return flow — ✅ PASS”

What this step proves:

A Corveta sales rep (Blair Bennett) logs in and opens the dedicated expiry/recall returns flow at /returns/new?type=expiry. The first step asks why the stock is coming back (Expiring or Recall) and which manufacturer it belongs to. This verifies the lean flow is reachable and gated by the rep’s returns permissions and the returns feature flag.

Screenshots:

step 01 logged in

step 01 reason manufacturer step

Video recording:


2. Step 2: Select manufacturer and expiring lots — ✅ PASS

Section titled “2. Step 2: Select manufacturer and expiring lots — ✅ PASS”

What this step proves:

The rep selects Vantis as the manufacturer (auto-selected when Corveta stocks a single manufacturer) and advances to the lot picker. The picker lists the distributor’s own returnable inventory with expiration status badges; the seeded URS-071 lot renders as “expiring soon”. The rep uses “Select all expiring” to choose it. This verifies the flow surfaces the distributor’s own expiring stock and lets the rep pick the lots to return.

Screenshots:

step 02 lot picker

step 02 lots selected

Video recording:


3. Step 3: Review and submit the expiry return — ✅ PASS

Section titled “3. Step 3: Review and submit the expiry return — ✅ PASS”

What this step proves:

The rep reviews the return — manufacturer, reason, and selected lots — adds notes, and submits. The submit path creates a return with return_type=expiry, derives the return location from the selected lots, attaches no sales account, and creates no replacement order. Because the replacement-order step is skipped, the service writes a decision audit row (create_replacement_order_on_return, performed=false, reason=return_type_not_incident). This is the primary URS-071 evidence that the lean return persists correctly and the skip is audited.

Audit events generated by this step:

(Evidence scoped to step execution window: 2026-08-03T23:05:37.084Z → 2026-08-03T23:05:39.074Z)

TimeTypeActionUserOrgPerformed
2026-08-03 23:05:38Zdecisioncreate_replacement_order_on_returnblair.bennett@corvetasurgical.comVantisno
2026-08-03 23:05:38Zreturn_requestcreatedblair.bennett@corvetasurgical.comVantis

Screenshots:

step 03 review

step 03 submission success

Video recording:


The following SQL queries ran against the application database after the Playwright scenarios completed. Each query asserts a specific condition that proves the feature under test persisted its data correctly.

Expiry return created for Corveta → Vantis — ✅ PASS

Section titled “Expiry return created for Corveta → Vantis — ✅ PASS”

Assertion: A URS-071 return with return_type=expiry and status=submitted should exist (marker: “URS-071 validation run”).

SELECT id, return_number, status, return_type, sales_account_id,
return_location_id, replacement_order_id, notes, created_at
FROM returns
WHERE sales_organization_id = $1
AND manufacturer_organization_id = $2
AND return_type = 'expiry'
AND notes LIKE '%URS-071%'
AND created_at > NOW() - INTERVAL '2 hours'
ORDER BY created_at DESC
idreturn_numberstatusreturn_typesales_account_idreturn_location_idreplacement_order_idnotescreated_at
019fc9e0-2997-7e03-b5c1-23a27310fb16RET-1submittedexpiryNULLa6e7f8a9-b0c1-2345-0123-456789012345NULLURS-071 validation run — submitted at 2026-08-03T23:05:36.507Z2026-08-03T23:05:38.943Z

No replacement order created for the expiry return — ✅ PASS

Section titled “No replacement order created for the expiry return — ✅ PASS”

Assertion: Expiry/recall returns never create a replacement order, so replacement_order_id must be NULL.

-- replacement_order_id from the return row above
replacement_order_id
NULL

Return location derived from lots and no sales account required — ✅ PASS

Section titled “Return location derived from lots and no sales account required — ✅ PASS”

Assertion: The return location should be derived from the selected lots (return_location_id NOT NULL) and no account should be attached (sales_account_id NULL).

-- return_location_id and sales_account_id from the return row above
return_location_idsales_account_id
a6e7f8a9-b0c1-2345-0123-456789012345NULL

Return item carries the seeded lot, manufacturer, and location — ✅ PASS

Section titled “Return item carries the seeded lot, manufacturer, and location — ✅ PASS”

Assertion: At least one return_items row should carry lot_number=URS071-SHV-001, manufacturer_organization_id=Vantis, and location_id=TRUNK-25 (the lot the picker selected).

SELECT ri.id, ri.product_id, ri.lot_number, ri.manufacturer_organization_id,
ri.location_id, ri.return_item_number
FROM return_items ri
WHERE ri.return_id = $1
ORDER BY ri.lot_number
idproduct_idlot_numbermanufacturer_organization_idlocation_idreturn_item_number
019fc9e0-299b-75dc-982e-664efc11eecb01989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-8
019fc9e0-299b-75dc-982e-665294c9f11d01989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-12
019fc9e0-299b-75dc-982e-6651658e730201989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-11
019fc9e0-299b-75dc-982e-6650b75279a801989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-10
019fc9e0-299b-75dc-982e-664f6e00d9c501989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-9
019fc9e0-299b-75dc-982e-665c5a717eb501989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-4
019fc9e0-299b-75dc-982e-6659ec7ce25b01989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-1
019fc9e0-299b-75dc-982e-665a01f5455301989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-2
019fc9e0-299b-75dc-982e-665b9cdbac7701989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-3
019fc9e0-299b-75dc-982e-664bbaa6eade01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-5
019fc9e0-299b-75dc-982e-664cc63a9eed01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-6
019fc9e0-299b-75dc-982e-664d867d9f4401989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-7
019fc9e0-299b-75dc-982e-664a849d2cd201989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-4
019fc9e0-299b-75dc-982e-66498ea9104e01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-3
019fc9e0-299b-75dc-982e-66481e62b90601989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-2
019fc9e0-299b-75dc-982e-66478d45c65e01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-1
019fc9e0-299b-75dc-982e-6657cc237b0601989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-17
019fc9e0-299b-75dc-982e-6658dec5eb7b01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-18
019fc9e0-299b-75dc-982e-665399c7050601989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-13
019fc9e0-299b-75dc-982e-6655b399b61901989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-15
019fc9e0-299b-75dc-982e-6654deba9be401989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-14
019fc9e0-299b-75dc-982e-665628b2bfb001989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-16

Replacement-order skip recorded as an audit decision — ✅ PASS

Section titled “Replacement-order skip recorded as an audit decision — ✅ PASS”

Assertion: Submitting an expiry return should write a decision audit_events row with action=‘create_replacement_order_on_return’, performed=false, reason=‘return_type_not_incident’.

SELECT id, event_type, action, object_id, organization_id, payload, created_at
FROM audit_events
WHERE created_at >= $1
AND event_type = 'decision'
AND action = 'create_replacement_order_on_return'
AND payload->>'performed' = 'false'
AND payload->>'reason' = 'return_type_not_incident'
ORDER BY created_at DESC
idevent_typeactionobject_idorganization_idpayloadcreated_at
019fc9e0-29a1-7639-ada5-3d164c6cb348decisioncreate_replacement_order_on_return019fc9e0-2997-7e03-b5c1-23a27310fb16a1b2c3d4-e5f6-7890-abcd-ef1234567890{"reason":"return_type_not_incident","performed":false,"entityType":"return"}2026-08-03T23:05:38.943Z

Per-declaration outcome of every expectedAuditActions and expectedEmailTemplates entry written into the orchestrator. Missing evidence here is a real test failure, not a soft warning.

Each row asserts that a declared expectedAuditActions entry produced a matching row in audit_events. A ❌ flips overall status to FAIL — the declaration is real proof, not just an annotation.

StepExpected Audit ActionFound
Step 3: Review and submit the expiry returndecision:create_replacement_order_on_return

Every row written to audit_events while this test was running (scoped to the demo organizations). Provides compliance evidence that user actions are traced end-to-end (URS-003).

Capture window start: 2026-08-03T23:05:10.689Z

SELECT
ae.created_at,
ae.event_type,
ae.action,
ae.user_id,
u.email AS user_email,
ae.organization_id,
o.name AS organization_name,
ae.object_id,
ae.secondary_object_id,
ae.payload,
ae.route,
ae.trace_id
FROM audit_events ae
LEFT JOIN users u ON u.id = ae.user_id
LEFT JOIN organizations o ON o.id = ae.organization_id
WHERE ae.created_at >= $1
AND ae.organization_id = ANY($2::uuid[])
ORDER BY ae.created_at ASC

7 event(s) captured:

TimeTypeActionUserOrgObject IDPerformedReason
2026-08-03 23:05:10Zchecklistchecklists.createCorveta Surgical Group019fc9df-bbde-795b-b31d-9d52feabc8bb
2026-08-03 23:05:10Zdecisionensure_lot_expiration_checklistCorveta Surgical Groupb2c3d4e5-f6a7-8901-bcde-f12345678901yescreated_1_reopened_0_already_open_1
2026-08-03 23:05:16Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group
2026-08-03 23:05:22Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group
2026-08-03 23:05:30Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group
2026-08-03 23:05:38Zdecisioncreate_replacement_order_on_returnblair.bennett@corvetasurgical.comVantis019fc9e0-2997-7e03-b5c1-23a27310fb16noreturn_type_not_incident
2026-08-03 23:05:38Zreturn_requestcreatedblair.bennett@corvetasurgical.comVantis019fc9e0-2997-7e03-b5c1-23a27310fb16