# Validation Report: URS-028

**Title:** Initiate Return Requests for Products
**Date:** 2026-04-23T03:39:16.900Z
**Duration:** 125.8s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall support initiating return requests for products.

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

## Environment

- **Inbox URL:** http://localhost:63629
- **Database:** localhost:63630/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: Navigate to returns — ✅ PASS

**What this step proves:**

A sales rep navigates to the returns section of the application. This verifies the returns feature is accessible and that the navigation flow works correctly.

**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:39:19Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:39:28Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:40:23Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:41:11Z | 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: Fill return form — ✅ PASS

**What this step proves:**

The sales rep fills out the multi-step return request form with product and return reason details. This verifies all required fields are present and that form data can be entered correctly.

**Screenshots:**

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

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

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

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

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

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

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

**Video recording:**

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

---

### 3. Step 3: Submit return — ✅ PASS

**What this step proves:**

The completed return form is submitted. This verifies the system accepts the return request and processes the submission through the multi-step form flow.

**Screenshots:**

![step 03 review before submit](screenshots/step-03-review-before-submit.png)

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

**Video recording:**

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

---

### 4. Step 4: Verify return recorded — ✅ PASS

**What this step proves:**

The submitted return request is confirmed to appear in the returns list. This verifies the return data was persisted correctly and is visible to the requesting user, satisfying the requirement that return requests can be initiated and tracked.

**Screenshots:**

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

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

**Video recording:**

[▶ Watch step recording](videos/step-04-verify-return.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 record created — ✅ PASS

**Assertion:** At least one return should have been created by Bob Kauffman in the last 30 minutes

```sql
SELECT r.id, r.return_number, r.status, r.date_of_event,
        r.sales_account_id, r.manufacturer_organization_id,
        r.sales_organization_id, r.reporting_user_id,
        r.return_location_id, r.replacement_location_id,
        r.created_at, r.created_by_user_id
      FROM returns r
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC
      LIMIT 5
```

| id | return_number | status | date_of_event | sales_account_id | manufacturer_organization_id | sales_organization_id | reporting_user_id | return_location_id | replacement_location_id | created_at | created_by_user_id |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 | submitted | 2026-04-22T05:00:00.000Z | fea7b8c9-d0e1-2345-0123-456789012345 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | 17b8c9d0-e1f2-3456-1234-567890123456 | 6ea3b4c5-d6e7-8901-6789-012345678901 | 6ea3b4c5-d6e7-8901-6789-012345678901 | 2026-04-23T03:41:06.484Z | 17b8c9d0-e1f2-3456-1234-567890123456 |

### Return number generated — ✅ PASS

**Assertion:** Return should have a return number matching /^RET-\d+$/

```sql
SELECT r.id, r.return_number
      FROM returns r
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
        AND r.return_number IS NOT NULL
        AND r.return_number != ''
      ORDER BY r.created_at DESC
      LIMIT 1
```

| id | return_number |
| --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 |

### Return status is submitted — ✅ PASS

**Assertion:** Return status should be "submitted"

```sql
SELECT r.id, r.return_number, r.status
      FROM returns r
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC
      LIMIT 1
```

| id | return_number | status |
| --- | --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 | submitted |

### Return items created — ✅ PASS

**Assertion:** At least one return item should exist for the submitted return

```sql
SELECT ri.id, ri.return_id, ri.product_id, ri.lot_number,
        ri.return_item_number, op.title as product_name
      FROM return_items ri
      JOIN returns r ON ri.return_id = r.id
      JOIN org_products op ON ri.product_id = op.id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC, ri.created_at DESC
```

| id | return_id | product_id | lot_number | return_item_number | product_name |
| --- | --- | --- | --- | --- | --- |
| 019db86d-5649-72e7-a93c-84c52d27f0ce | 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | 01989ca2-6a54-7834-8376-06a0251bacd8 | URS028-RETURN-001 | RET-1-SP019N1A-1 | SpeedPatch® PET |

### Return item has correct lot number — ✅ PASS

**Assertion:** Return item should have lot number "URS028-RETURN-001"

```sql
SELECT ri.id, ri.lot_number, ri.return_item_number
      FROM return_items ri
      JOIN returns r ON ri.return_id = r.id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
        AND ri.lot_number = $2
      LIMIT 1
```

| id | lot_number | return_item_number |
| --- | --- | --- |
| 019db86d-5649-72e7-a93c-84c52d27f0ce | URS028-RETURN-001 | RET-1-SP019N1A-1 |

### Return linked to correct organizations — ✅ PASS

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

```sql
SELECT r.id, r.return_number,
        r.manufacturer_organization_id, mo.name as manufacturer_name,
        r.sales_organization_id, so.name as sales_org_name
      FROM returns r
      JOIN organizations mo ON r.manufacturer_organization_id = mo.id
      JOIN organizations so ON r.sales_organization_id = so.id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC
      LIMIT 1
```

| id | return_number | manufacturer_organization_id | manufacturer_name | sales_organization_id | sales_org_name |
| --- | --- | --- | --- | --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 | a1b2c3d4-e5f6-7890-abcd-ef1234567890 | ZuriMED | b2c3d4e5-f6a7-8901-bcde-f12345678901 | StellarTech Medical Solutions |

### Return has locations set — ✅ PASS

**Assertion:** Return should have both return and replacement locations set

```sql
SELECT r.id, r.return_number,
        r.return_location_id, rl.name as return_location_name,
        r.replacement_location_id, repl.name as replacement_location_name
      FROM returns r
      JOIN real_world_locations rl ON r.return_location_id = rl.id
      JOIN real_world_locations repl ON r.replacement_location_id = repl.id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC
      LIMIT 1
```

| id | return_number | return_location_id | return_location_name | replacement_location_id | replacement_location_name |
| --- | --- | --- | --- | --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 | 6ea3b4c5-d6e7-8901-6789-012345678901 | BOSS - Shipping | 6ea3b4c5-d6e7-8901-6789-012345678901 | BOSS - Shipping |

### Return has reporting and created_by users — ✅ PASS

**Assertion:** Return should have both reporting_user_id and created_by_user_id set

```sql
SELECT r.id, r.return_number, r.reporting_user_id, r.created_by_user_id,
        u1.name as reporting_user_name, u2.name as created_by_user_name
      FROM returns r
      JOIN users u1 ON r.reporting_user_id = u1.id
      JOIN users u2 ON r.created_by_user_id = u2.id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
      ORDER BY r.created_at DESC
      LIMIT 1
```

| id | return_number | reporting_user_id | created_by_user_id | reporting_user_name | created_by_user_name |
| --- | --- | --- | --- | --- | --- |
| 019db86d-5647-7f7e-bb24-ffa7f6fee9e0 | RET-1 | 17b8c9d0-e1f2-3456-1234-567890123456 | 17b8c9d0-e1f2-3456-1234-567890123456 | Bob Kauffman | Bob Kauffman |

### Return item question response persisted — ✅ PASS

**Assertion:** return_item_question_responses should contain a row for the test question with response_text = "Product packaging was damaged during shipping, device is non-functional"

```sql
SELECT riqr.id, riqr.return_item_id, riqr.question_version_id,
        riqr.response_text, ri.lot_number, rpqv.question_text
      FROM return_item_question_responses riqr
      JOIN return_items ri ON ri.id = riqr.return_item_id
      JOIN returns r ON r.id = ri.return_id
      JOIN return_product_question_versions rpqv ON rpqv.id = riqr.question_version_id
      WHERE r.created_by_user_id = $1
        AND r.created_at > NOW() - INTERVAL '30 minutes'
        AND riqr.question_version_id = $2
      ORDER BY riqr.created_at DESC
```

| id | return_item_id | question_version_id | response_text | lot_number | question_text |
| --- | --- | --- | --- | --- | --- |
| 019db86d-564b-77bc-9a4d-f3d1123ab29f | 019db86d-5649-72e7-a93c-84c52d27f0ce | 02822222-2222-4222-8222-222222222222 | Product packaging was damaged during shipping, device is non-functional | URS028-RETURN-001 | Describe the issue with this product |

## 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: 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:39:15.004Z

<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:39:19Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:39:28Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:40:23Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:41:11Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
