# Manual QA Checklist — Vehicle Lifecycle (Admin/Seller)

Use after changes to `AuctionVehicleSyncService`, `VehicleReservationService`, admin/seller checkout, or seller assignment.

**Scope:** admin/seller operational flows only.  
**Out of scope (smoke-only — must remain unchanged):** customer checkout, customer dashboard, public listings, invoice PDF layout, payment rules, database schema.

---

## Pre-requisites

- [ ] Staging/local has at least one **complete** auction car (make, model, chassis, selling price) with **no** linked vehicle.
- [ ] Staging/local has at least one auction car with a **draft** vehicle already linked (from prior seller assign).
- [ ] Admin account, seller account, and customer account available.
- [ ] Mail/SMTP configured if testing reservation invoice email (optional; PDF record still created without email).
- [ ] Note reservation expiry setting (`reservation_expiry_days`) for time-sensitive tests.

---

## 1. Admin assigns seller to auction car

| | |
|---|---|
| **Starting condition** | Auction car: make/model/chassis filled, **no** `vehicles` row OR existing draft vehicle without seller. No active reservation. |
| **Action** | Admin intake → assign seller (POST assign-seller with valid `seller_id`). |
| **Expected DB** | `vehicles` row exists with `auction_car_id` set, `seller_id` = chosen seller, `status` = `draft`, `is_locked` = 0, `stock_status` = `available`, catalog fields populated from auction (make, model, chassis, etc.). |
| **Expected UI** | Intake row shows linked vehicle + seller name; vehicle not in seller pool (pool requires **no** linked vehicle). |
| **Regression warnings** | Vehicle not created when chassis missing; seller shown on UI but `vehicles.seller_id` null; duplicate vehicles for same `auction_car_id`. |

- [ ] Pass / Fail / Notes: _______________

---

## 2. Admin clears seller assignment

| | |
|---|---|
| **Starting condition** | Auction car with linked draft vehicle, `vehicles.seller_id` set, vehicle **not** reserved/locked/sold. |
| **Action** | Admin intake → assign seller with explicit `seller_id: null` (clear/unassign). |
| **Expected DB** | Same vehicle row retained; `vehicles.seller_id` = **NULL**; vehicle remains `draft` unless other flows changed it. |
| **Expected UI** | Seller column empty on intake row; linked vehicle still shown if not deleted elsewhere. |
| **Regression warnings** | Old seller_id still present after clear; vehicle deleted unexpectedly; reserved vehicle seller cleared (should not be tested on locked/reserved stock). |

- [ ] Pass / Fail / Notes: _______________

---

## 3. Seller reserves auction pool vehicle

| | |
|---|---|
| **Starting condition** | Auction in **seller pool**: no linked vehicle, no active reservation, no order-linked reservation. Seller has customer selected. |
| **Action** | Seller → auction pool → create reservation (commission/wallet as per normal UI). |
| **Expected DB** | `vehicle_reservations`: `status` = `active`, `auction_car_id` set, **`vehicle_id` populated** (not null). `vehicles`: new row, `status` = `reserved`, `is_locked` = 1, `seller_id` = reservation seller, normalized fields from auction. Reservation pricing: `admin_price`, `seller_price`, `commission_amount` set. |
| **Expected UI** | Reservation appears in seller list; auction **removed from pool**; reservation invoice email/PDF if configured. |
| **Regression warnings** | `vehicle_id` null on reservation; invoice with blank make/model/chassis; pool still shows auction; vehicle `draft` + unlocked after reserve. |

- [ ] Pass / Fail / Notes: _______________

---

## 4. Admin reserves auction intake vehicle

| | |
|---|---|
| **Starting condition** | Auction car in intake (may or may not have draft vehicle from seller assign). No active reservation on target. Customer selected in admin reserve modal. |
| **Action** | Admin → create reservation on `auction_car_id` (or linked vehicle). |
| **Expected DB** | Same as seller reserve: active reservation with `vehicle_id`, locked reserved vehicle, pricing snapshot, optional wallet debit. |
| **Expected UI** | Reservation created JSON/UI success; invoice generated (check `invoices` type `reservation` linked to reservation id). |
| **Regression warnings** | Invoice sent before vehicle exists (missing vehicle fields on PDF); duplicate active reservations for same auction. |

- [ ] Pass / Fail / Notes: _______________

---

## 5. Reservation release by admin

| | |
|---|---|
| **Starting condition** | Active reservation with `vehicle_id`, vehicle `status` = `reserved`, `is_locked` = 1. No converted order. |
| **Action** | Admin → delete/release reservation. |
| **Expected DB** | Reservation: `status` = `expired`, `expires_at` = null. Vehicle: `status` = `available`, `is_locked` = 0. **`stock_status` unchanged** (typically still `available`). Wallet **not** refunded (`wallet_amount_used` unchanged). |
| **Expected UI** | Reservation removed from active lists; vehicle unlock allows new reservation. |
| **Regression warnings** | 500 error when `vehicle_id` null; vehicle stays locked; reservation stays `active`. |

- [ ] Pass / Fail / Notes: _______________

---

## 6. Reservation cancel/release by seller

| | |
|---|---|
| **Starting condition** | Active reservation owned by seller (`seller_id` = auth seller), vehicle locked. |
| **Action** | Seller → release/delete reservation. |
| **Expected DB** | Same as admin release: reservation `expired`, vehicle `available` + unlocked. **Not** `published` (prior duplicate reset removed; effective behavior is `available`). |
| **Expected UI** | Success message; reservation no longer active; seller can create new reservation if business rules allow. |
| **Regression warnings** | Vehicle remains `reserved`/locked; crash on missing vehicle; unexpected `published` status (would indicate unintended behavior change). |

- [ ] Pass / Fail / Notes: _______________

---

## 7. Repeated reservation attempts for same auction_car

| | |
|---|---|
| **Starting condition** | One **active** reservation already exists for auction car (or same vehicle). |
| **Action** | Attempt second reserve (admin or seller) on same target. |
| **Expected DB** | No second active reservation; first reservation unchanged. |
| **Expected UI** | Validation error: duplicate reservation message (422). |
| **Regression warnings** | Two active reservations; stale reservation not expired before new one. |

**Sub-test — stale expiry:**

| | |
|---|---|
| **Starting condition** | Prior reservation `active` but `expires_at` in the past. |
| **Action** | New reserve on same auction_car. |
| **Expected DB** | Stale row → `expired`; new row → `active`. |
| **Regression warnings** | Duplicate guard blocks despite expired timestamp. |

- [ ] Pass / Fail / Notes: _______________

---

## 8. Invoice generation after minimal vehicle materialization

| | |
|---|---|
| **Starting condition** | Auction-only reservation (no pre-existing vehicle before reserve). |
| **Action** | Create reservation (admin or seller); wait for post-commit invoice job. |
| **Expected DB** | `invoices`: `type` = `reservation`, `vehicle_reservation_id` set, **`vehicle_id` populated**, `pdf_path` set. Vehicle has `rec_no`, make, model, chassis before invoice row created. |
| **Expected UI** | Customer/admin invoice list shows reservation invoice; PDF contains make/model/chassis/year (not all `-`). Email sent if SMTP + customer email present. |
| **Regression warnings** | Invoice `vehicle_id` null; PDF vehicle section mostly `-`; duplicate reservation invoices on retry. |

- [ ] Pass / Fail / Notes: _______________

---

## 9. Checkout operational vehicle resolution

| | |
|---|---|
| **Starting condition A** | Active reservation **with** `vehicle_id` already set (normal post-change path). |
| **Starting condition B** | Legacy reservation with `auction_car_id` but **`vehicle_id` null** (if any exist in DB). |
| **Action** | Admin **or** seller reservation checkout (not customer checkout). |
| **Expected DB** | Checkout transaction uses resolved vehicle; if B, `vehicle_id` backfilled on reservation after materialize. Order created with correct vehicle linkage. |
| **Expected UI** | Checkout completes without “vehicle generation failed”; order visible in admin/seller order views. |
| **Regression warnings** | Checkout fails despite valid auction data; duplicate vehicle created for same `auction_car_id`. |

- [ ] Pass / Fail — Admin checkout: _______________
- [ ] Pass / Fail — Seller checkout: _______________

---

## 10. Fully paid order marking vehicle sold

| | |
|---|---|
| **Starting condition** | Order from reservation checkout with pending/partial payments; vehicle `stock_status` = `available`, may be `status` = `reserved`. |
| **Action** | Complete payments until order fully paid (admin mark-paid and/or approve seller checkout + payment completion — use existing production path). |
| **Expected DB** | Order: `status` = `paid`, `remaining_balance` = 0. Vehicle: `stock_status` = `sold`, `status` = `sold`. Reservation: `converted` (if not already). |
| **Expected UI** | Order shows paid; vehicle in sold inventory filters; reservation not active. |
| **Regression warnings** | Order paid but vehicle still `available`; reservation stuck `active` after full payment. |

- [ ] Pass / Fail / Notes: _______________

---

## Untouched systems — smoke verification

Run quick checks that recent lifecycle work did **not** regress adjacent systems. Fail if behavior differs from pre-change baseline.

### Customer checkout

| | |
|---|---|
| **Action** | Customer reservation checkout OR direct vehicle purchase (existing happy path). |
| **Expected** | Same flow, pricing, and order creation as before; no new validation errors. |
| **Regression warnings** | New errors on checkout; changed deposit/wallet rules; broken consignee step. |

- [ ] Pass / Fail / Notes: _______________

### Customer dashboard

| | |
|---|---|
| **Action** | Customer login → dashboard loads. |
| **Expected** | Orders/reservations/wallet display unchanged. |
| **Regression warnings** | Missing data, new errors, layout breakage. |

- [ ] Pass / Fail / Notes: _______________

### Public vehicle listings

| | |
|---|---|
| **Action** | Browse public catalog + open published vehicle detail. |
| **Expected** | Same visibility rules (`published`/`reserved` + available stock); inquiry vs purchase mode unchanged. |
| **Regression warnings** | Reserved/draft vehicles incorrectly public; purchase mode changed without data change. |

- [ ] Pass / Fail / Notes: _______________

### Invoice PDF design

| | |
|---|---|
| **Action** | Download existing reservation or partial invoice PDF. |
| **Expected** | Layout/branding unchanged; only data fields differ by record. |
| **Regression warnings** | Broken layout, missing background/fonts, Browsershot errors. |

- [ ] Pass / Fail / Notes: _______________

### Payment logic

| | |
|---|---|
| **Action** | Create partial payment; verify `syncOrderPaymentTotals` status transitions (`reserved` → `payment_pending` → `paid`). |
| **Expected** | Same amounts, statuses, and reservation conversion rules as before. |
| **Regression warnings** | Order status skips steps; reservation not converted on first completed payment. |

- [ ] Pass / Fail / Notes: _______________

### Database schema

| | |
|---|---|
| **Action** | `php artisan migrate:status` (or review migration list). |
| **Expected** | No new migrations from lifecycle patch; existing columns unchanged. |
| **Regression warnings** | New pending migrations; required columns missing on staging. |

- [ ] Pass / Fail / Notes: _______________

---

## Quick DB inspection queries (optional)

Use after each scenario to confirm state without guessing UI:

```sql
-- Reservation + vehicle for an auction car
SELECT vr.id, vr.status, vr.vehicle_id, vr.auction_car_id, vr.seller_price,
       v.status AS vehicle_status, v.is_locked, v.seller_id, v.stock_status, v.rec_no
FROM vehicle_reservations vr
LEFT JOIN vehicles v ON v.id = vr.vehicle_id
WHERE vr.auction_car_id = :auction_car_id
ORDER BY vr.id DESC;

-- Invoice linked to reservation
SELECT id, type, invoice_number, vehicle_id, vehicle_reservation_id, pdf_path, email_sent_at
FROM invoices
WHERE vehicle_reservation_id = :reservation_id;

-- Seller assignment
SELECT id, auction_car_id, seller_id, status, is_locked
FROM vehicles
WHERE auction_car_id = :auction_car_id;
```

---

## Sign-off

| Role | Name | Date | Result |
|------|------|------|--------|
| QA / Engineer | | | |
| Admin flow spot-check | | | |
| Seller flow spot-check | | | |

**Overall result:** Pass / Fail / Pass with notes

**Blocking issues:**

**Non-blocking issues:**
