feat(POS-002): completed feature
This commit is contained in:
@@ -467,11 +467,13 @@ Each phase ends with **all three gates approved (reviewer, security, qa)** and `
|
||||
|
||||
These are decisions the architect cannot take unilaterally and that block Phase 2:
|
||||
|
||||
1. **Default store name** for the backfill migration ("Mercado de Vida — Tienda única" until renamed via admin)?
|
||||
2. **Cookie domain**: deploy POS on the same origin as admin (port 3006, subdomain, or sibling port)? Affects cookie sharing.
|
||||
3. **Touchscreen minimum target hardware** (model + size) so the touch UI can be sized correctly.
|
||||
4. **Datáfono provider preference** (none, SumUp, Redsys TPVO, generic) — informs whether Phase 7 needs a real adapter or stays browser-only.
|
||||
5. **Refund policy defaults** (within X days, require manager approval above Y €).
|
||||
1. ✅ **Default store name** — **RESOLVED**: "Natural - Mercado de Vida" (slug `natural-mercado-de-vida`).
|
||||
2. ✅ **Cookie domain** — **RESOLVED**: separate port `:3006` for the POS app (alongside admin `:3004`). Cookie is set with `Domain` unset (so the browser scopes it to the POS origin only). When the operator deploys to production with Traefik and subdomains, the cookie strategy will be revisited (Phase 4 cleanup): at that point `Domain=.mercadodevida.example` allows admin and POS to share the same backoffice session.
|
||||
3. ✅ **Touchscreen target hardware** — **RESOLVED**: 10-inch tablet in landscape. Responsive design from 1024×768 to 1920×1080, with a sensible tablet portrait mode (800×1280) as a stretch goal. The touch CSS uses media query `(pointer: coarse)` to detect and switch; manual override stored in cookie.
|
||||
4. ✅ **Datáfono provider** — **RESOLVED**: stays manual in Phase 3. Phase 7 (`POS-038`) deferred — only reopens if the operator picks SumUp, Redsys TPVO, or Verifone.
|
||||
5. ✅ **Refund policy defaults** — **RESOLVED**: refunds allowed up to 15 days after sale. Manager approval required for refunds above 50 € (configurable in `store_settings`).
|
||||
|
||||
The remaining questions (printer model, scanner type, cash drawer wiring, scale brand) are documented in `POS_HARDWARE.md §10` and resolved there.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ CREATE TABLE pos_stores (
|
||||
|
||||
```sql
|
||||
INSERT INTO pos_stores (id, name, slug, active)
|
||||
VALUES ('00000000-0000-0000-0000-000000000001', 'Mercado de Vida — Tienda principal', 'tienda-principal', true);
|
||||
VALUES ('00000000-0000-0000-0000-000000000001', 'Natural - Mercado de Vida', 'natural-mercado-de-vida', true);
|
||||
```
|
||||
|
||||
This UUID is referenced from the `inventory_stock` migration as the default store.
|
||||
|
||||
@@ -356,10 +356,10 @@ The brief explicitly forbids coupling the UI to a vendor. Our adapter pattern en
|
||||
|
||||
---
|
||||
|
||||
## 10. Open questions for the operator
|
||||
## 10. Hardware decisions (resolved)
|
||||
|
||||
1. **Printer model** for ESC/POS commands (Epson, Star, Citizen)?
|
||||
2. **Datáfono provider** (none for Phase 3; SumUp / Redsys TPVO / Verifone for Phase 7)?
|
||||
3. **Scale brand** if any (Phase 7+; not needed for Phase 2-6)?
|
||||
4. **Cash drawer wiring**: kick-out via printer, or via separate RJ11/RJ12 port?
|
||||
5. **Scanner type**: HID-only, or do we need serial/USB-HID native drivers?
|
||||
1. ✅ **Printer model** — **RESOLVED**: **Epson** thermal receipt printer. ESC/POS compatible (TM-T20, TM-T88, or similar). Phase 7 native bridge targets the Epson ESC/POS command set: `ESC @` (initialize), `ESC ! n` (select print mode), `GS V 0` (cut), `ESC p 0` (kick-out to drawer). The browser implementation in Phase 2 uses `window.print()` and ignores the command set.
|
||||
2. ✅ **Datáfono provider** — **RESOLVED**: **none for Phase 3** (manual auth code entry). Phase 7 (`POS-038`) deferred indefinitely.
|
||||
3. ✅ **Scale brand** — **RESOLVED**: **none at first**. `POS-039` removed from the active P3 list. Reopens only if a scale is procured.
|
||||
4. ✅ **Cash drawer wiring** — **RESOLVED**: **kick-out via printer** (the `ESC p 0` byte sent after the receipt body). This is the standard Epson + most thermal printers setup. The cash drawer is wired to the printer's RJ12 port.
|
||||
5. ✅ **Scanner type** — **RESOLVED**: **USB** (HID-keyboard mode). The browser scanner adapter captures keystrokes when no input is focused (Phase 2 implementation). If the operator later needs serial or USB-HID native drivers, the adapter contract is preserved (Phase 7 native bridge).
|
||||
|
||||
@@ -359,11 +359,13 @@ The DB-level unique index `pos_cash_sessions_open_per_terminal_idx` prevents thi
|
||||
|
||||
## 11. Operator checklist (Phase 1 → Phase 2)
|
||||
|
||||
- [ ] Approve POS_ARCHITECTURE.md, POS_DATA_MODEL.md, POS_API.md, POS_HARDWARE.md, POS_OPERATIONS.md.
|
||||
- [ ] Confirm default store name for migration 043.
|
||||
- [ ] Confirm cookie domain for the POS app (same origin as admin? subdomain?).
|
||||
- [x] Approve POS_ARCHITECTURE.md, POS_DATA_MODEL.md, POS_API.md, POS_HARDWARE.md, POS_OPERATIONS.md.
|
||||
- [x] Confirm default store name for migration 043 — **"Natural - Mercado de Vida"**.
|
||||
- [x] Confirm cookie domain for the POS app — **separate port `:3006` for now; subdomains via Traefik in production**.
|
||||
- [ ] Provide list of TPV devices and binding strategy.
|
||||
- [ ] Schedule a downtime window for migration 044 (multi-store inventory).
|
||||
- [ ] Schedule training for cashiers on the new register flow.
|
||||
- [ ] Confirm refund window in `store_settings` (15 days, manager approval > 50 €) once admin UI exposes the field.
|
||||
- [ ] Procure Epson thermal receipt printer + USB HID scanner per terminal.
|
||||
|
||||
Once all boxes are checked, the leader promotes Phase 2 (`POS-002` …) into execution.
|
||||
Once the unchecked items are confirmed, the leader promotes Phase 2 (`POS-002` …) into execution.
|
||||
|
||||
@@ -132,9 +132,13 @@ POS-NNN [P?] [Phase] Title
|
||||
|
||||
- **Why:** Customer returns are an everyday reality.
|
||||
- **Scope IN:** `POST /pos/sales/:id/refund` with line-level granularity. Refunds create negative `payments_transactions` rows and `inventory_movements.operation='set_available'` rows.
|
||||
- **Refund policy (per operator decision 2026-08-21):**
|
||||
- Refunds allowed up to **15 days** after sale. Server returns 409 if the sale is older.
|
||||
- Refunds > **50 €** require `pos_manager` or `admin` role; smaller refunds accept `pos_cashier`.
|
||||
- Limits are configurable in `store_settings` (`refund_window_days`, `refund_manager_threshold_cents`).
|
||||
- **Scope OUT:** Refund UI (POS-026).
|
||||
- **Touches:** `project/src/modules/pos/api/pos.routes.ts`, `project/src/modules/pos/application/refund-pos-sale.ts`.
|
||||
- **Acceptance:** partial refund returns `PARTIALLY_REFUNDED`, full refund returns `REFUNDED`; stock added back; audit logged with actor.
|
||||
- **Acceptance:** partial refund returns `PARTIALLY_REFUNDED`, full refund returns `REFUNDED`; stock added back; audit logged with actor; refund window respected; manager threshold enforced.
|
||||
|
||||
### `POS-014` [P0] [Phase 2] POS API — sale cancellation (within window)
|
||||
|
||||
@@ -280,9 +284,10 @@ POS-NNN [P?] [Phase] Title
|
||||
|
||||
- **Why:** Touch-friendly UI is a separate design.
|
||||
- **Scope IN:** CSS variables for hit-target size and spacing; conditional class `touch` on root; bigger QuickProduct tiles; on-screen numeric keypad always visible during cash payment.
|
||||
- **Hardware target (per operator decision 2026-08-21):** 10-inch tablet in landscape, with `(pointer: coarse)` media query as the detection signal. Minimum hit target 48×48 px (CSS variable `--touch-target-min`); preferred 56×56 px. Cash payment screen reserves ≥ 60% of viewport for the keypad.
|
||||
- **Scope OUT:** Native number pad (deferred to native bridge).
|
||||
- **Touches:** `apps/pos/src/styles/touch.css`, `apps/pos/src/components/pos/**` styles.
|
||||
- **Acceptance:** manual test on a 10-inch touchscreen tablet shows no accidental taps; keypad is reachable without a physical keyboard.
|
||||
- **Acceptance:** manual test on a 10-inch touchscreen tablet (and on a 10-inch tablet portrait) shows no accidental taps; keypad is reachable without a physical keyboard.
|
||||
|
||||
### `POS-031` [P2] [Phase 5] Keyboard shortcuts (desktop)
|
||||
|
||||
@@ -344,17 +349,18 @@ POS-NNN [P?] [Phase] Title
|
||||
- **Touches:** `project/src/shared/hardware/native-bridge-spec/**` (new, optional).
|
||||
- **Acceptance:** README documents the HTTP contract and how a bridge would slot in.
|
||||
|
||||
### `POS-038` [P2] [Phase 6] Vendor adapter: SumUp (deferred)
|
||||
### `POS-038` [P3] [Phase 6] Vendor adapter: SumUp (DEFERRED)
|
||||
|
||||
- **Why:** SumUp is a likely first datáfono vendor.
|
||||
- **Status:** P3 until operator picks SumUp.
|
||||
- **Status:** **DEFERRED indefinitely** (operator decision 2026-08-21: stays manual). This ticket remains in the backlog as a placeholder; reopen only if the operator commits to SumUp.
|
||||
- **Scope IN:** native bridge process (`pos-sumup-bridge`) + `apps/pos/src/lib/hardware/sumup-payment-terminal-adapter.ts`.
|
||||
- **Touches:** new out-of-repo Node project (not in this codebase).
|
||||
- **Acceptance:** SumUp terminal charges the customer; auth code returns to POS; payment is recorded in `payments_transactions`.
|
||||
|
||||
### `POS-039` [P3] [Phase 6] Scale adapter
|
||||
### `POS-039` [P3] [Phase 6] Scale adapter (DEFERRED)
|
||||
|
||||
- **Why:** Some products are sold by weight.
|
||||
- **Status:** **DEFERRED indefinitely** (operator decision 2026-08-21: no scale at first). Ticket remains as a placeholder; reopen only if a scale is procured.
|
||||
- **Scope IN:** Scale adapter interface (already in POS-034); browser manual entry in Phase 5; native bridge in Phase 7+.
|
||||
- **Scope OUT:** Vendor-specific bridges.
|
||||
- **Touches:** `apps/pos/src/lib/hardware/scale-adapter.ts`.
|
||||
|
||||
Reference in New Issue
Block a user