Add Frontdesk-style Devices registry for POS hardware.
Deploy Ladill POS / deploy (push) Successful in 42s

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.
This commit is contained in:
isaacclad
2026-07-15 21:49:21 +00:00
parent 46c60259c9
commit c01518b0ee
15 changed files with 877 additions and 3 deletions
+157
View File
@@ -0,0 +1,157 @@
<?php
namespace Tests\Feature;
use App\Http\Middleware\EnsurePlatformSession;
use App\Models\PosCustomerDisplay;
use App\Models\PosDevice;
use App\Models\PosLocation;
use App\Models\User;
use App\Services\Pos\DeviceService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PosDeviceTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware(EnsurePlatformSession::class);
$this->withoutVite();
}
private function user(): User
{
return User::create([
'public_id' => 'u-'.uniqid(),
'name' => 'Owner',
'email' => uniqid().'@example.com',
]);
}
private function location(User $user): PosLocation
{
return PosLocation::create([
'owner_ref' => $user->public_id,
'name' => 'Main register',
'currency' => 'GHS',
]);
}
public function test_can_register_register_device_without_token(): void
{
$user = $this->user();
$location = $this->location($user);
$this->actingAs($user)
->post(route('pos.devices.store'), [
'name' => 'Front till',
'type' => 'register',
'location_id' => $location->id,
])
->assertRedirect(route('pos.devices.index'));
$device = PosDevice::query()->where('owner_ref', $user->public_id)->first();
$this->assertNotNull($device);
$this->assertSame('register', $device->type);
$this->assertNull($device->device_token);
}
public function test_customer_display_device_reuses_branch_display_token(): void
{
$user = $this->user();
$location = $this->location($user);
$this->actingAs($user)
->post(route('pos.devices.store'), [
'name' => 'Counter screen',
'type' => 'customer_display',
'location_id' => $location->id,
])
->assertRedirect(route('pos.devices.index'));
$device = PosDevice::query()->where('owner_ref', $user->public_id)->firstOrFail();
$display = PosCustomerDisplay::query()->where('location_id', $location->id)->firstOrFail();
$this->assertNotEmpty($device->device_token);
$this->assertSame($display->token, $device->device_token);
}
public function test_customer_display_device_requires_branch(): void
{
$user = $this->user();
$this->location($user);
$this->actingAs($user)
->from(route('pos.devices.create'))
->post(route('pos.devices.store'), [
'name' => 'Orphan screen',
'type' => 'customer_display',
'location_id' => '',
])
->assertRedirect(route('pos.devices.create'))
->assertSessionHas('error');
}
public function test_devices_index_lists_owned_devices(): void
{
$user = $this->user();
$location = $this->location($user);
PosDevice::create([
'owner_ref' => $user->public_id,
'location_id' => $location->id,
'name' => 'Kitchen pad',
'type' => 'tablet',
'status' => 'offline',
]);
$this->actingAs($user)
->get(route('pos.devices.index'))
->assertOk()
->assertSee('Kitchen pad')
->assertSee('Devices');
}
public function test_regenerate_token_updates_customer_display(): void
{
$user = $this->user();
$location = $this->location($user);
$device = app(DeviceService::class)->register([
'owner_ref' => $user->public_id,
'name' => 'Display',
'type' => 'customer_display',
'location_id' => $location->id,
]);
$old = $device->device_token;
$this->actingAs($user)
->post(route('pos.devices.regenerate-token', $device))
->assertRedirect();
$device->refresh();
$display = PosCustomerDisplay::query()->where('location_id', $location->id)->firstOrFail();
$this->assertNotSame($old, $device->device_token);
$this->assertSame($device->device_token, $display->token);
}
public function test_customer_display_poll_marks_device_online(): void
{
$user = $this->user();
$location = $this->location($user);
$device = app(DeviceService::class)->register([
'owner_ref' => $user->public_id,
'name' => 'Display',
'type' => 'customer_display',
'location_id' => $location->id,
]);
$this->getJson(route('pos.customer-display.state', ['token' => $device->device_token]))
->assertOk();
$device->refresh();
$this->assertSame('online', $device->status);
$this->assertNotNull($device->last_online_at);
}
}