Add public token-gated kitchen display for POS devices.
Deploy Ladill POS / deploy (push) Successful in 46s

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.
This commit is contained in:
isaacclad
2026-07-15 22:52:28 +00:00
parent c01518b0ee
commit ede4aaa10c
8 changed files with 425 additions and 78 deletions
+85
View File
@@ -154,4 +154,89 @@ class PosDeviceTest extends TestCase
$this->assertSame('online', $device->status);
$this->assertNotNull($device->last_online_at);
}
public function test_kitchen_display_device_opens_public_url_without_auth(): void
{
$user = $this->user();
$location = $this->location($user);
$device = app(DeviceService::class)->register([
'owner_ref' => $user->public_id,
'name' => 'Pass tablet',
'type' => 'kitchen_display',
'location_id' => $location->id,
]);
$this->assertNotEmpty($device->device_token);
$this->get(route('pos.kitchen-display.show', ['token' => $device->device_token]))
->assertOk()
->assertSee('Kitchen display')
->assertSee('Main register');
$this->getJson(route('pos.kitchen-display.feed', ['token' => $device->device_token]))
->assertOk()
->assertJsonStructure(['tickets', 'server_time']);
$device->refresh();
$this->assertSame('online', $device->status);
}
public function test_kitchen_display_bump_advances_line_state(): void
{
$user = $this->user();
$location = $this->location($user);
$device = app(DeviceService::class)->register([
'owner_ref' => $user->public_id,
'name' => 'KDS',
'type' => 'kitchen_display',
'location_id' => $location->id,
]);
$sale = \App\Models\PosSale::create([
'owner_ref' => $user->public_id,
'location_id' => $location->id,
'reference' => 'POS-KDS-1',
'currency' => 'GHS',
'status' => 'pending',
'payment_method' => 'cash',
'order_type' => 'dine_in',
'kitchen_status' => \App\Models\PosSale::KITCHEN_ACTIVE,
'kitchen_sent_at' => now(),
'total_minor' => 1000,
'subtotal_minor' => 1000,
]);
$line = \App\Models\PosSaleLine::create([
'pos_sale_id' => $sale->id,
'name' => 'Jollof',
'unit_price_minor' => 1000,
'quantity' => 1,
'line_total_minor' => 1000,
'position' => 0,
'kitchen_state' => \App\Models\PosSaleLine::KITCHEN_QUEUED,
]);
$this->postJson(route('pos.kitchen-display.bump', [
'token' => $device->device_token,
'line' => $line->id,
]))->assertOk()->assertJsonPath('state', 'preparing');
$this->assertSame('preparing', $line->fresh()->kitchen_state);
}
public function test_device_service_open_url_for_kitchen_is_public(): void
{
$user = $this->user();
$location = $this->location($user);
$device = app(DeviceService::class)->register([
'owner_ref' => $user->public_id,
'name' => 'KDS',
'type' => 'kitchen_display',
'location_id' => $location->id,
]);
$url = app(DeviceService::class)->openUrl($device);
$this->assertNotNull($url);
$this->assertStringContainsString('/kitchen-display/', $url);
$this->assertStringContainsString($device->device_token, $url);
}
}