# Validation Report: URS-039

**Title:** Returns form supports multiple item questionnaires
**Date:** 2026-04-23T03:42:20.319Z
**Duration:** 61.0s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall support submission and processing of returns

*Source: `User_Requirement_Specifications_ZuriMED_DeviceFlow.xlsx` — the run below proves the system meets this requirement.*

## Environment

- **Inbox URL:** http://localhost:64510
- **Database:** localhost:64511/cc_repinbox_dev

## Setup

Status: ✅ PASS

## 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 navigate to returns — ✅ PASS

**What this step proves:**

A sales rep logs in and navigates to the returns list. This verifies the returns feature is accessible and that the rep's permissions permit viewing returns.

**Audit events generated by this step:**

*(Evidence matched by declared name — step timing not available or no events fell in window)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-04-23 03:42:22Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:42:29Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:43:01Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:43:14Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |

**Screenshots:**

![step 01 logged in](screenshots/step-01-logged-in.png)

![step 01 returns list](screenshots/step-01-returns-list.png)

**Video recording:**

[▶ Watch step recording](videos/step-01-navigate-returns.webm)

---

### 2. Step 2: Submit return request with multiple item questionnaires — ✅ PASS

**What this step proves:**

The rep completes the multi-step return form with two different products. Each product has its own return question, so the per-item questionnaire step renders one distinct card per returned item. The rep fills a different answer per item and submits the return. This verifies the URS-039 requirement that the form supports submitting multiple individual item questionnaires.

**Screenshots:**

![step 02 new return form](screenshots/step-02-new-return-form.png)

![step 02 products selected](screenshots/step-02-products-selected.png)

![step 02 per item cards rendered](screenshots/step-02-per-item-cards-rendered.png)

![step 02 per item questions filled](screenshots/step-02-per-item-questions-filled.png)

![step 02 review](screenshots/step-02-review.png)

![step 02 submission success](screenshots/step-02-submission-success.png)

**Video recording:**

[▶ Watch step recording](videos/step-02-submit-return.webm)

---

### 3. Step 3: View output form for each returned item — ✅ PASS

**What this step proves:**

Immediately after submission, the rep opens the return detail page — the "output form" that URS-039 asks the system to generate per returned item. The detail page shows each item with its product, lot number, and the per-item questionnaire response captured on the previous step. This is the primary URS-039 evidence that one form is generated per returned item.

**Screenshots:**

![step 03 return detail top](screenshots/step-03-return-detail-top.png)

![step 03 return detail items visible](screenshots/step-03-return-detail-items-visible.png)

![step 03 return detail bottom](screenshots/step-03-return-detail-bottom.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-view-output-form.webm)

---

### 4. Step 4: Verify return appears in returns list — ✅ PASS

**What this step proves:**

The rep returns to the Returns list and confirms the new return appears with Submitted status. This verifies the system persisted the return and that it is discoverable for follow-up actions.

**Screenshots:**

![step 04 returns list with return](screenshots/step-04-returns-list-with-return.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-verify-in-list.webm)

---

## 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.

### Return created for StellarTech → ZuriMED — ✅ PASS

**Assertion:** A URS-039 return with status=submitted should exist (marker: "URS-039 validation run").

```sql
SELECT id, return_number, status, date_of_event, notes, created_at
    FROM returns
    WHERE sales_organization_id = $1
      AND manufacturer_organization_id = $2
      AND notes LIKE '%URS-039%'
      AND created_at > NOW() - INTERVAL '2 hours'
    ORDER BY created_at DESC
```

| id | return_number | status | date_of_event | notes | created_at |
| --- | --- | --- | --- | --- | --- |
| 019db86f-111e-7aab-838a-681ae885f1ff | RET-1 | submitted | 2026-04-22T05:00:00.000Z | URS-039 validation run — submitted at 2026-04-23T03:42:41.530Z | 2026-04-23T03:42:59.841Z |

### Return number generated — ✅ PASS

**Assertion:** Return should have a return number in RET-XXXXX format.

```sql
-- return_number from the row above
```

| return_number |
| --- |
| RET-1 |

### One return_items row per returned product — ✅ PASS

**Assertion:** Expected 2 return_items rows (one per returned product).

```sql
SELECT ri.id, ri.product_id, op.sku, op.title, ri.lot_number,
      ri.return_item_number, ri.created_at
    FROM return_items ri
    JOIN org_products op ON op.id = ri.product_id
    WHERE ri.return_id = $1
    ORDER BY op.sku, ri.lot_number
```

| id | product_id | sku | title | lot_number | return_item_number | created_at |
| --- | --- | --- | --- | --- | --- | --- |
| 019db86f-1120-78bf-baae-b07d9bd8b5e3 | 01989ca1-f2f8-7ab7-8269-7179342797cc | FL516SNA | FiberLocker® Instrument SN | URS039-FL-001 | RET-1-FL516SNA-1 | 2026-04-23T03:42:59.841Z |
| 019db86f-1120-78bf-baae-b07c8818435d | 01989ca2-6a54-7834-8376-06a0251bacd8 | SP019N1A | SpeedPatch® PET | URS039-SP-001 | RET-1-SP019N1A-1 | 2026-04-23T03:42:59.841Z |

### Each returned item has its own distinct lot number — ✅ PASS

**Assertion:** All expected per-item lot numbers should appear exactly once, proving per-item data was stored.

```sql
-- Expected lot numbers: URS039-SP-001, URS039-FL-001
```

| lot_number | sku | title |
| --- | --- | --- |
| URS039-FL-001 | FL516SNA | FiberLocker® Instrument SN |
| URS039-SP-001 | SP019N1A | SpeedPatch® PET |

### Each returned item has its own questionnaire response — ✅ PASS

**Assertion:** Every return_items row should have at least one return_item_question_responses row, proving one questionnaire was generated per returned item.

```sql
SELECT riqr.id, riqr.return_item_id, riqr.question_version_id,
      riqr.response_text, ri.lot_number, rpqv.question_text, rpqv.question_type
    FROM return_item_question_responses riqr
    JOIN return_items ri ON ri.id = riqr.return_item_id
    JOIN return_product_question_versions rpqv ON rpqv.id = riqr.question_version_id
    WHERE ri.return_id = $1
    ORDER BY ri.lot_number
```

| id | return_item_id | question_version_id | response_text | lot_number | question_text | question_type |
| --- | --- | --- | --- | --- | --- | --- |
| 019db86f-1122-7061-90b1-3ea20d818475 | 019db86f-1120-78bf-baae-b07d9bd8b5e3 | 03922222-2222-4222-8222-222222222222 | URS-039 FiberLocker: instrument returned unopened, customer downgraded procedure plan and no longer needs the unit. | URS039-FL-001 | Describe the condition and reason for returning this FiberLocker unit | text |
| 019db86f-1122-7061-90b1-3ea16405e801 | 019db86f-1120-78bf-baae-b07c8818435d | 03911111-2222-4222-8222-222222222222 | URS-039 SpeedPatch: outer seal ruptured on arrival, adhesive layer contaminated and unusable. | URS039-SP-001 | Describe the defect observed for this SpeedPatch unit | text |

### Per-item answers persisted match the spec input — ✅ PASS

**Assertion:** Each item's saved response should be distinct and match the answer the spec entered for that product.

```sql
-- compares response_text per lot against RETURN_ITEMS definitions
```

| lot_number | question_text | response_text | question_version_id |
| --- | --- | --- | --- |
| URS039-FL-001 | Describe the condition and reason for returning this FiberLocker unit | URS-039 FiberLocker: instrument returned unopened, customer downgraded procedure plan and no longer needs the unit. | 03922222-2222-4222-8222-222222222222 |
| URS039-SP-001 | Describe the defect observed for this SpeedPatch unit | URS-039 SpeedPatch: outer seal ruptured on arrival, adhesive layer contaminated and unusable. | 03911111-2222-4222-8222-222222222222 |

### Return linked to ZuriMED (manufacturer) and StellarTech (distributor) — ✅ PASS

**Assertion:** Return should be linked to ZuriMED (manufacturer) and StellarTech (distributor).

```sql
SELECT r.manufacturer_organization_id, r.sales_organization_id
    FROM returns r
    WHERE r.id = $1
```

| manufacturer_organization_id | sales_organization_id |
| --- | --- |
| a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b2c3d4e5-f6a7-8901-bcde-f12345678901 |

## 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

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 1: Login and navigate to returns | `user_log:user:login` | ✅ |

## 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-04-23T03:42:18.416Z

<details><summary>Query used to capture events</summary>

```sql
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
```
</details>

4 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-04-23 03:42:22Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:42:29Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:43:01Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:43:14Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
