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-09-29T02:30:53.995Z Duration: 39.8s 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-09-29T02:31:24.084Z → 2026-09-29T02:31:31.167Z)

TimeTypeActionUserOrgPerformed
2026-09-29 02:31:26Zdecisionrepresentatives.gate_rep_actionblair.bennett@corvetasurgical.comVantisno
2026-09-29 02:31:26Zdecisioncreate_replacement_order_on_returnblair.bennett@corvetasurgical.comVantisno
2026-09-29 02:31:26Zdecisionpartition_return_submissionblair.bennett@corvetasurgical.comVantisno
2026-09-29 02:31:26Zdecisiontickets.checklist_item_resolve.auto_resolve_ticket—Corveta Surgical Groupno
2026-09-29 02:31:26Zdecisiontickets.checklist_item_resolve.auto_resolve_ticket—Corveta Surgical Groupno
2026-09-29 02:31:26Zreturn_requestcreatedblair.bennett@corvetasurgical.comVantis—
2026-09-29 02:31:26Zdecisionlink_return_to_location_sales_accountblair.bennett@corvetasurgical.comCorveta Surgical Groupno
2026-09-29 02:31:26Zdecisionopen_item_movement_on_return_submissionblair.bennett@corvetasurgical.comCorveta Surgical Groupyes
2026-09-29 02:31:27Zdecisionreturns.notifications.cc_incident_recipients—Vantisno
2026-09-29 02:31:27Zdecisionextensiv_return_push.skipped—Vantisno
2026-09-29 02:31:29Ztransactional_emailreturn_submitted—Corveta Surgical Group—

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
01a0eb00-b0c8-7523-ace4-bafc30249d40RET-1submittedexpiryNULLa6e7f8a9-b0c1-2345-0123-456789012345NULLURS-071 validation run — submitted at 2026-09-29T02:31:23.447Z2026-09-29T02:31:26.093Z

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
01a0eb00-b0ce-79d3-9f97-b98257f468d301989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-8
01a0eb00-b0ce-79d3-9f97-b9865864068101989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-12
01a0eb00-b0ce-79d3-9f97-b9859862b96e01989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-11
01a0eb00-b0ce-79d3-9f97-b9843bb2f6a601989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-10
01a0eb00-b0ce-79d3-9f97-b9831af86ec801989c9e-fb9b-7f7e-a345-ee490ddfc1ccURS071-SHV-001a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-9
01a0eb00-b0ce-79d3-9f97-b990a7c30ceb01989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-4
01a0eb00-b0ce-79d3-9f97-b98d394e477001989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-1
01a0eb00-b0ce-79d3-9f97-b98e1e529de601989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-2
01a0eb00-b0ce-79d3-9f97-b98f11bbcfd101989c9e-9ccf-7a73-8ff7-b60007f2de85VM-PMX-2418a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200616-3
01a0eb00-b0ce-79d3-9f97-b97fb1dd249a01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-5
01a0eb00-b0ce-79d3-9f97-b98061b1931a01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-6
01a0eb00-b0ce-79d3-9f97-b981343c654701989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2390a1b2c3d4-e5f6-7890-abcd-ef1234567890b7f8a9b0-c1d2-3456-1234-567890123456RET-1-72200873-7
01a0eb00-b0ce-79d3-9f97-b97eb45773cb01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-4
01a0eb00-b0ce-79d3-9f97-b97d0e091d3b01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-3
01a0eb00-b0ce-79d3-9f97-b97c27ab13b401989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-2
01a0eb00-b0ce-79d3-9f97-b97b31c495a001989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2401a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-1
01a0eb00-b0ce-79d3-9f97-b98b2a0e89b101989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-17
01a0eb00-b0ce-79d3-9f97-b98c6ecbccb101989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-18
01a0eb00-b0ce-79d3-9f97-b987ea0bde8101989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-13
01a0eb00-b0ce-79d3-9f97-b9895b5cce0401989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-15
01a0eb00-b0ce-79d3-9f97-b9885fbb014a01989c9e-fb9b-7f7e-a345-ee490ddfc1ccVM-SHV-2415a1b2c3d4-e5f6-7890-abcd-ef1234567890a6e7f8a9-b0c1-2345-0123-456789012345RET-1-72200873-14
01a0eb00-b0ce-79d3-9f97-b98a34785cf101989c9e-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
01a0eb00-b147-7384-90fb-697b42898b0cdecisioncreate_replacement_order_on_return01a0eb00-b0c8-7523-ace4-bafc30249d40a1b2c3d4-e5f6-7890-abcd-ef1234567890{"reason":"return_type_not_incident","performed":false,"entityType":"return"}2026-09-29T02:31:26.093Z

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-09-29T02:30:52.237Z

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

14 event(s) captured:

TimeTypeActionUserOrgObject IDPerformedReason
2026-09-29 02:30:58Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group——
2026-09-29 02:31:07Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group——
2026-09-29 02:31:16Zuser_loguser:loginblair.bennett@corvetasurgical.comCorveta Surgical Group——
2026-09-29 02:31:26Zdecisionrepresentatives.gate_rep_actionblair.bennett@corvetasurgical.comVantisa1b2c3d4-e5f6-7890-abcd-ef1234567890nono_blocking_relationship
2026-09-29 02:31:26Zdecisioncreate_replacement_order_on_returnblair.bennett@corvetasurgical.comVantis01a0eb00-b0c8-7523-ace4-bafc30249d40noreturn_type_not_incident
2026-09-29 02:31:26Zdecisionpartition_return_submissionblair.bennett@corvetasurgical.comVantis01a0eb00-b0c8-7523-ace4-bafc30249d40nono_org_submission_policy
2026-09-29 02:31:26Zdecisiontickets.checklist_item_resolve.auto_resolve_ticket—Corveta Surgical Groupfa000009-0000-4000-8000-000000000009noChecklist item is not linked to any ticket.
2026-09-29 02:31:26Zdecisiontickets.checklist_item_resolve.auto_resolve_ticket—Corveta Surgical Group01a0eaff-fdfc-7aa9-967a-a9d000b20b33noChecklist item is not linked to any ticket.
2026-09-29 02:31:26Zreturn_requestcreatedblair.bennett@corvetasurgical.comVantis01a0eb00-b0c8-7523-ace4-bafc30249d40—
2026-09-29 02:31:26Zdecisionlink_return_to_location_sales_accountblair.bennett@corvetasurgical.comCorveta Surgical Group01a0eb00-b0c8-7523-ace4-bafc30249d40nolocation_not_account_linked
2026-09-29 02:31:26Zdecisionopen_item_movement_on_return_submissionblair.bennett@corvetasurgical.comCorveta Surgical Group01a0eb00-b0c8-7523-ace4-bafc30249d40yesreturn_movement_opened
2026-09-29 02:31:27Zdecisionreturns.notifications.cc_incident_recipients—Vantis01a0eb00-b0c8-7523-ace4-bafc30249d40noreturn is not an incident return
2026-09-29 02:31:27Zdecisionextensiv_return_push.skipped—Vantis01a0eb00-b0c8-7523-ace4-bafc30249d40nowms_feature_flag_disabled
2026-09-29 02:31:29Ztransactional_emailreturn_submitted—Corveta Surgical Group01a0eb00-b0c8-7523-ace4-bafc30249d40—

1 notification email(s) were captured during this test run. Each email is rendered as a screenshot for compliance review.

Template: Return_Submitted_-_RET-1

Return Submitted - RET-1