# POS English + retail redesign — UAT checklist

Serve the app over HTTP (not `file://`) so ES modules load. Use a test client with purchases so Phase 5 margin row can appear.

## Visual / copy

- [ ] Page `lang` is `en`; nav shows **Counter sales**; **Dashboard** link works.
- [ ] Summary bar: **Today's POS**, **Sales**, **Total**, **Online/Offline** pills are English; **Reg** field persists; orange **queue** badge when offline checkouts are pending.
- [ ] Product grid: **WEIGHT** tag, **Stock**, **Add** / **No stock**, **No products match** empty state.
- [ ] Cart: English labels; line discount inputs; **Hold cart** / **Recall**; **Complete sale** gradient button; **Preview receipt**; **Clear cart** confirms in English.
- [ ] Modals (scan pick, refund, day close, variant, weight, receipt preview, recall list): titles and buttons in English.

## Money & payments

- [ ] **৳** still prefixes amounts; numbers use `en-US` grouping.
- [ ] **All cash** / **All card** / **All mobile** fill split fields; checkout still writes `Cash` / `Card` / `Mobile banking` in `payment.breakdown` (unchanged for `pos-finance.js`).

## Offline outbox & idempotency

- [ ] Turn off network, complete a valid sale → toast **queued**; cart clears; queue count increments.
- [ ] Go online → queued sale syncs (toast **Synced N**); queue badge clears; order appears in Firebase with `meta.checkoutClientId` and `posCheckoutAck/{id}`.
- [ ] Retry queue button processes remaining rows without double-posting (same `clientRequestId`).

## Hold / recall

- [ ] **Hold cart** saves to device; **Recall** lists cashier + register; load replaces cart; delete removes hold.
- [ ] Another cashier’s hold shows as “other” in list.

## Shift / close segmentation

- [ ] `posShiftCurrent` includes `registerId` + `cashierUid` after load.
- [ ] Day close save writes `posDailyCloses/{date}` (legacy path) **and** `posDailyClosesSegments/{dateKey__reg__uid}`; slip shows register + cashier.

## Checkout guardrails

- [ ] Line discount above gate (or any fixed line $) requires manager PIN when `siteSettings.posSecurity.managerPin` is set.
- [ ] `posSecurity.belowCostMode: 'block'` requires manager PIN (or session unlock) instead of simple confirm.
- [ ] `belowCostMode: 'warn'` keeps confirm dialog.

## Refund picker

- [ ] Orders without `stock_updated` appear with **stock flag** tag; refund still works; extra confirm for legacy rows.

## Analytics

- [ ] Tender cards match POS (or online) scope for selected chart channel.
- [ ] Unknown-channel monitor line appears when `unknownOrders > 0`.
- [ ] Restock hints list populates for POS-filtered range.

## Productivity

- [ ] **F2** focuses barcode; **Alt+H** hold; **Alt+R** recall; **Alt+C** triggers checkout (when not typing in other fields).
- [ ] Recent sales: **Preview** / **Repeat** / **Print** behave correctly.

## Scale (optional)

- [ ] Web Serial message and stable-weight hint in English.

## Related settings

- [ ] **Inventory** → POS global tax & receipt section labels English; save shows **POS global settings saved.**
- [ ] Optional `siteSettings.posSecurity`: `managerPin`, `lineDiscountPctGate` (default 5), `belowCostMode` (`warn`|`block`).

## Regression

- [ ] `node` import `margin-analytics-fixtures.js` → `runMarginAnalyticsFixtureChecks()` and `runPhase5FixtureChecks()` still `ok: true`.
