Kitchen display devices open a full-screen KDS without staff login,
with feed/stream/bump over the device token. Shared kitchen board
logic is extracted so the signed-in Kitchen page stays in sync.
Register tills, customer displays, kitchen screens, printers, scanners,
and tablets per branch. Customer displays share the branch display token
and mark online when the public screen polls; stale devices go offline
on a schedule.
Retail still reads live CRM products only (not services), products mode follows the acting branch, and suite Pro/Business defaults match the tenfold price update.
Card/MoMo always initializes with the merchant email, and Paystack/Flutterwave/Hubtel open in-page (desktop modal, mobile bottomsheet) instead of a full redirect.
Co-authored-by: Cursor <cursoragent@cursor.com>
Register Card/MoMo payments through merchant Paystack, Flutterwave, or Hubtel settings so takings settle 100% to the business.
Co-authored-by: Cursor <cursoragent@cursor.com>
Pro and Business users can manage branches, invite cashiers with branch assignment, and switch registers; sales and register flows respect acting location.
Co-authored-by: Cursor <cursoragent@cursor.com>
Register supports USB keyboard-wedge scanners with SKU lookup (local catalog
and CRM in retail mode). Sales get a thermal receipt print template (58/80mm)
with configurable header/footer, plus optional auto-print after cash sales.
Co-authored-by: Cursor <cursoragent@cursor.com>
On a sale's detail page, unpaid sales (retail or restaurant) can now be
cancelled or deleted:
- Cancel (pending only) marks it cancelled and frees its table / clears it from
the kitchen (PosSaleService::cancelSale).
- Delete removes the sale and cascades its lines, modifiers and payments, freeing
the table first (deleteSale). Paid sales are protected — they can't be deleted.
Status badge now distinguishes cancelled/failed. Covered by PosRestaurantTest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guard ingestExternalOrder: skip (200, no ticket created) when the owner has no
restaurant-mode POS location, so pushing from Merchant is harmless for accounts
that don't use the POS kitchen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split bills (restaurant tickets):
- New pos_payments ledger; a tab is settled across one or more cash/Ladill Pay
payments. The ticket shows total / paid / balance, an amount field with Full /
½ / ⅓ / ¼ helpers, and the payments taken. Partial payments keep the tab open;
the sale finalises (and frees the table) only when the balance hits zero.
Pay splits get their own checkout + callback (pos.payments.callback).
Pipe online orders to the KDS:
- POST /api/kitchen/orders — a first-party, service-keyed ingest
(config pos.kitchen_api_keys, scoped by owner, idempotent by external_ref) that
creates a paid, already-fired ticket (order_type=online, lines source=online).
- The KDS feed is now payment-agnostic (any kitchen-active sale), so paid online
orders sit on the board next to dine-in tabs and bump the same way; they're
badged "online".
Schema additive: pos_payments, pos_sales.external_ref. Suite green (14).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "links" slice — a guest scans a table's QR, browses the menu (with
modifiers), and submits an order that lands on that table's open tab and fires
straight to the Kitchen Display.
- Public, auth-free flow scoped by an unguessable table short_code:
GET /t/{code} (menu + client cart), POST /t/{code}/order (throttled),
GET /t/{code}/done. Orders open/append the table's dine-in tab, add lines as
source=guest, and send to the kitchen.
- Staff print a per-table QR (Settings → table → QR; renders client-side to the
public menu URL). short_code is generated lazily.
- Guest lines are badged on the ticket and the KDS so staff can tell them apart;
staff still settle the tab as usual (cash / Ladill Pay).
- Extracted PosSaleService::buildProductLine as the single product+modifier
price resolver, now shared by staff and guest ordering (client prices never
trusted).
Schema additive: pos_tables.short_code, pos_sale_lines.source. New
PosRestaurantTest covers the guest order firing to the kitchen; suite green (12).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Builds on Phase 1 with the menu structure restaurants need:
- Menu setup page (restaurant mode): categories, kitchen stations, and modifier
groups with options (price deltas).
- Products gain category, kitchen station, default course, and attached modifier
groups (managed on the product form).
- Ordering: the ticket groups the catalog by category and, when a product has
modifier groups, opens a picker (respects min/max select) for options + notes +
course before adding. Effective price = base + modifier deltas (resolved
server-side; client prices are never trusted).
- Fire-by-course: send the whole tab or just one course to the kitchen.
- KDS: filter by station; each item shows its station, course, modifiers and notes.
Schema additive (pos_categories, pos_stations, pos_modifier_groups, pos_modifiers,
product↔group pivot, pos_sale_line_modifiers; category/station/course columns on
products and lines). PosRestaurantTest covers modifiers, course and station routing;
suite green (11 passed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gated by a per-location service_style (retail | restaurant). Restaurant mode adds:
- Floor screen with tables (areas, seats, status) — tap a free table to open a
dine-in tab; takeaway/counter orders open from the same screen.
- Open tickets (tabs): a sale stays pending while items are added; lines persist
as you go (posTicket Alpine component posts each change to the server).
- Send-to-kitchen fires un-sent lines; a polling Kitchen Display (KDS) shows
active tickets and bumps items queued → preparing → ready → served.
- Settlement reuses the existing cash / Ladill Pay flow; paying closes the tab
and frees the table (PosSaleService::closeTicket, wired into both pay paths).
- Settings gains the mode toggle and a tables manager.
Schema is additive (new pos_tables; service_style on locations; order/kitchen
columns on sales + lines). Retail flow is untouched. Sidebar surfaces Floor +
Kitchen only in restaurant mode. New PosRestaurantTest covers the dine-in
lifecycle end to end; suite green (10 passed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>