Deploy Ladill POS / deploy (push) Successful in 23s
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>
56 lines
1.5 KiB
PHP
56 lines
1.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Pos;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Controllers\Pos\Concerns\ScopesToAccount;
|
|
use App\Models\PosSale;
|
|
use App\Models\PosTable;
|
|
use App\Services\Pos\PosLocationService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
|
|
class TableController extends Controller
|
|
{
|
|
use ScopesToAccount;
|
|
|
|
public function __construct(private PosLocationService $locations) {}
|
|
|
|
public function index(Request $request): View
|
|
{
|
|
$owner = $this->ownerRef($request);
|
|
$location = $this->locations->ensureDefault($owner);
|
|
|
|
$tables = PosTable::owned($owner)
|
|
->with('currentSale')
|
|
->orderBy('area')
|
|
->orderBy('position')
|
|
->orderBy('label')
|
|
->get();
|
|
|
|
$openTickets = PosSale::owned($owner)
|
|
->openTickets()
|
|
->with('table')
|
|
->withCount('lines')
|
|
->latest('opened_at')
|
|
->get();
|
|
|
|
return view('pos.floor', [
|
|
'location' => $location,
|
|
'tables' => $tables,
|
|
'tablesByArea' => $tables->groupBy(fn (PosTable $t) => $t->area ?: 'Floor'),
|
|
'openTickets' => $openTickets,
|
|
]);
|
|
}
|
|
|
|
public function qr(Request $request, PosTable $table): View
|
|
{
|
|
$this->authorizeOwner($request, $table);
|
|
|
|
return view('pos.tables.qr', [
|
|
'table' => $table,
|
|
'url' => route('pos.table.menu', $table->ensureShortCode()),
|
|
]);
|
|
}
|
|
}
|