Files
ladill-pos/resources/views/pos/kitchen/index.blade.php
T
isaaccladandClaude Opus 4.8 9780591e74
Deploy Ladill POS / deploy (push) Successful in 36s
Split bills + kitchen ingest for online orders
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>
2026-06-24 23:49:01 +00:00

74 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-app-layout title="Kitchen">
<div x-data="posKitchen(@js([
'feedUrl' => route('pos.kitchen.feed'),
'streamUrl' => route('pos.kitchen.stream'),
'bumpUrl' => route('pos.kitchen.bump', ['line' => '__ID__']),
]))" class="space-y-4">
<div class="flex items-center justify-between">
<div>
<h1 class="text-lg font-semibold text-slate-900">Kitchen</h1>
<p class="mt-1 text-sm text-slate-500">Live tickets tap an item to advance it. Refreshes automatically.</p>
</div>
<button type="button" @click="load()" class="rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-50">Refresh</button>
</div>
@if($stations->isNotEmpty())
<div class="flex flex-wrap gap-1.5">
<button type="button" @click="activeStation = ''" :class="activeStation === '' ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'"
class="rounded-full px-3 py-1 text-xs font-medium">All stations</button>
@foreach($stations as $station)
<button type="button" @click="activeStation = '{{ $station->id }}'"
:class="activeStation === '{{ $station->id }}' ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'"
class="rounded-full px-3 py-1 text-xs font-medium">{{ $station->name }}</button>
@endforeach
</div>
@endif
<template x-if="loaded && visibleTickets.length === 0">
<div class="rounded-2xl border border-dashed border-slate-200 bg-white px-6 py-16 text-center">
<p class="text-sm text-slate-500">No active tickets. Fired orders will appear here.</p>
</div>
</template>
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<template x-for="t in visibleTickets" :key="t.id">
<div class="flex flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white">
<div class="flex items-center justify-between border-b border-slate-100 bg-slate-50 px-4 py-2.5">
<div>
<p class="text-sm font-semibold text-slate-900" x-text="t.table ? t.table : t.order_type.replace('_',' ')"></p>
<p class="text-[11px] text-slate-400" x-text="t.reference"></p>
</div>
<span class="rounded-full bg-slate-900/5 px-2 py-0.5 text-xs font-medium text-slate-600" x-text="elapsed(t.sent_at)"></span>
</div>
<div class="flex-1 divide-y divide-slate-100">
<template x-for="line in t.lines" :key="line.id">
<div class="flex items-center justify-between gap-2 px-4 py-2.5"
:class="line.state === 'ready' ? 'bg-emerald-50' : (line.state === 'preparing' ? 'bg-amber-50/60' : '')">
<div class="min-w-0">
<p class="text-sm font-medium text-slate-900">
<span x-text="line.quantity + '×'"></span>
<span x-text="line.name"></span>
</p>
<p x-show="line.modifiers.length" x-cloak class="text-xs text-slate-500" x-text="line.modifiers.join(', ')"></p>
<p x-show="line.notes" x-cloak class="text-xs text-rose-600" x-text="line.notes"></p>
<div class="mt-0.5 flex items-center gap-1.5">
<span x-show="line.course" x-cloak class="rounded bg-slate-100 px-1.5 text-[10px] font-medium text-slate-500" x-text="line.course"></span>
<span x-show="line.station" x-cloak class="rounded bg-indigo-50 px-1.5 text-[10px] font-medium text-indigo-600" x-text="line.station"></span>
<span x-show="line.source === 'guest'" x-cloak class="rounded bg-violet-50 px-1.5 text-[10px] font-medium text-violet-700">guest</span>
<span x-show="line.source === 'online'" x-cloak class="rounded bg-blue-50 px-1.5 text-[10px] font-medium text-blue-700">online</span>
<span class="text-[11px] uppercase tracking-wide text-slate-400" x-text="line.state"></span>
</div>
</div>
<button type="button" @click="bump(line)"
class="shrink-0 rounded-lg border border-slate-200 bg-white px-2.5 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50"
x-text="nextLabel(line.state)"></button>
</div>
</template>
</div>
</div>
</template>
</div>
</div>
</x-app-layout>