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
User Requirement
Section titled “User Requirement”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.
Environment
Section titled “Environment”- Inbox URL: http://localhost:35551
- Database: localhost:46175/cc_repinbox_dev
Status: ✅ PASS
Test Steps
Section titled “Test Steps”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:


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:


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)
| Time | Type | Action | User | Org | Performed |
|---|---|---|---|---|---|
| 2026-08-03 23:05:38Z | decision | create_replacement_order_on_return | blair.bennett@corvetasurgical.com | Vantis | no |
| 2026-08-03 23:05:38Z | return_request | created | blair.bennett@corvetasurgical.com | Vantis | — |
Screenshots:


Video recording:
Database Validations
Section titled “Database Validations”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| id | return_number | status | return_type | sales_account_id | return_location_id | replacement_order_id | notes | created_at |
|---|---|---|---|---|---|---|---|---|
| 019fc9e0-2997-7e03-b5c1-23a27310fb16 | RET-1 | submitted | expiry | NULL | a6e7f8a9-b0c1-2345-0123-456789012345 | NULL | URS-071 validation run — submitted at 2026-08-03T23:05:36.507Z | 2026-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_id | sales_account_id |
|---|---|
| a6e7f8a9-b0c1-2345-0123-456789012345 | NULL |
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| id | product_id | lot_number | manufacturer_organization_id | location_id | return_item_number |
|---|---|---|---|---|---|
| 019fc9e0-299b-75dc-982e-664efc11eecb | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | URS071-SHV-001 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-8 |
| 019fc9e0-299b-75dc-982e-665294c9f11d | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | URS071-SHV-001 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-12 |
| 019fc9e0-299b-75dc-982e-6651658e7302 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | URS071-SHV-001 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-11 |
| 019fc9e0-299b-75dc-982e-6650b75279a8 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | URS071-SHV-001 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-10 |
| 019fc9e0-299b-75dc-982e-664f6e00d9c5 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | URS071-SHV-001 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-9 |
| 019fc9e0-299b-75dc-982e-665c5a717eb5 | 01989c9e-9ccf-7a73-8ff7-b60007f2de85 | VM-PMX-2418 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200616-4 |
| 019fc9e0-299b-75dc-982e-6659ec7ce25b | 01989c9e-9ccf-7a73-8ff7-b60007f2de85 | VM-PMX-2418 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200616-1 |
| 019fc9e0-299b-75dc-982e-665a01f54553 | 01989c9e-9ccf-7a73-8ff7-b60007f2de85 | VM-PMX-2418 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200616-2 |
| 019fc9e0-299b-75dc-982e-665b9cdbac77 | 01989c9e-9ccf-7a73-8ff7-b60007f2de85 | VM-PMX-2418 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200616-3 |
| 019fc9e0-299b-75dc-982e-664bbaa6eade | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2390 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200873-5 |
| 019fc9e0-299b-75dc-982e-664cc63a9eed | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2390 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200873-6 |
| 019fc9e0-299b-75dc-982e-664d867d9f44 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2390 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b7f8a9b0-c1d2-3456-1234-567890123456 | RET-1-72200873-7 |
| 019fc9e0-299b-75dc-982e-664a849d2cd2 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2401 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-4 |
| 019fc9e0-299b-75dc-982e-66498ea9104e | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2401 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-3 |
| 019fc9e0-299b-75dc-982e-66481e62b906 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2401 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-2 |
| 019fc9e0-299b-75dc-982e-66478d45c65e | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2401 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-1 |
| 019fc9e0-299b-75dc-982e-6657cc237b06 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-17 |
| 019fc9e0-299b-75dc-982e-6658dec5eb7b | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-18 |
| 019fc9e0-299b-75dc-982e-665399c70506 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-13 |
| 019fc9e0-299b-75dc-982e-6655b399b619 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-15 |
| 019fc9e0-299b-75dc-982e-6654deba9be4 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-1-72200873-14 |
| 019fc9e0-299b-75dc-982e-665628b2bfb0 | 01989c9e-fb9b-7f7e-a345-ee490ddfc1cc | VM-SHV-2415 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | a6e7f8a9-b0c1-2345-0123-456789012345 | RET-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| id | event_type | action | object_id | organization_id | payload | created_at |
|---|---|---|---|---|---|---|
| 019fc9e0-29a1-7639-ada5-3d164c6cb348 | decision | create_replacement_order_on_return | 019fc9e0-2997-7e03-b5c1-23a27310fb16 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | {"reason":"return_type_not_incident","performed":false,"entityType":"return"} | 2026-08-03T23:05:38.943Z |
Audit & Email Assertion Ledger
Section titled “Audit & Email Assertion Ledger”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.
Audit Action Assertions
Section titled “Audit Action Assertions”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.
| Step | Expected Audit Action | Found |
|---|---|---|
| Step 3: Review and submit the expiry return | decision:create_replacement_order_on_return | ✅ |
Audit Log Events
Section titled “Audit Log Events”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 ASC7 event(s) captured:
| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|---|---|---|---|---|---|---|---|
| 2026-08-03 23:05:10Z | checklist | checklists.create | — | Corveta Surgical Group | 019fc9df-bbde-795b-b31d-9d52feabc8bb | — | |
| 2026-08-03 23:05:10Z | decision | ensure_lot_expiration_checklist | — | Corveta Surgical Group | b2c3d4e5-f6a7-8901-bcde-f12345678901 | yes | created_1_reopened_0_already_open_1 |
| 2026-08-03 23:05:16Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — | |
| 2026-08-03 23:05:22Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — | |
| 2026-08-03 23:05:30Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — | |
| 2026-08-03 23:05:38Z | decision | create_replacement_order_on_return | blair.bennett@corvetasurgical.com | Vantis | 019fc9e0-2997-7e03-b5c1-23a27310fb16 | no | return_type_not_incident |
| 2026-08-03 23:05:38Z | return_request | created | blair.bennett@corvetasurgical.com | Vantis | 019fc9e0-2997-7e03-b5c1-23a27310fb16 | — |