Link retail POS products to the CRM products API (restaurant stays local)
Deploy Ladill POS / deploy (push) Successful in 28s
Deploy Ladill POS / deploy (push) Successful in 28s
Products are now mode-aware:
- Retail: the catalog lives in Ladill CRM. The Products page proxies CRUD to the
CRM products API (CrmClient gains product/create/update/delete), and the
register reads CRM products live; a sold line is stored as a name/price
snapshot (product_id null, since CRM products aren't local rows). Resilient —
the register shows an empty catalog if CRM is unreachable. CRM import is hidden
in Settings (not needed when reading live).
- Restaurant: unchanged — the local pos_products catalog keeps its POS-only depth
(category, kitchen station, course, modifier groups).
ProductController routes take a raw {product} id (CRM id in retail, local id in
restaurant). Suite green (17), covering both modes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0d816daed3
commit
5d8e185223
@@ -3,6 +3,7 @@
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\EnsurePlatformSession;
|
||||
use App\Models\PosLocation;
|
||||
use App\Models\PosProduct;
|
||||
use App\Models\PosSale;
|
||||
use App\Models\User;
|
||||
@@ -49,21 +50,50 @@ class PosRegisterTest extends TestCase
|
||||
->assertSee('favicon.ico', false);
|
||||
}
|
||||
|
||||
public function test_register_renders_products(): void
|
||||
public function test_register_renders_local_products_in_restaurant_mode(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
PosProduct::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'name' => 'Coffee',
|
||||
'price_minor' => 1500,
|
||||
'currency' => 'GHS',
|
||||
'is_active' => true,
|
||||
// ensureDefault() matches owner+name 'Main register'.
|
||||
PosLocation::create(['owner_ref' => $user->public_id, 'name' => 'Main register', 'currency' => 'GHS', 'service_style' => 'restaurant']);
|
||||
PosProduct::create(['owner_ref' => $user->public_id, 'name' => 'Coffee', 'price_minor' => 1500, 'currency' => 'GHS', 'is_active' => true]);
|
||||
|
||||
$this->actingAs($user)->get(route('pos.register'))->assertOk()->assertSee('Coffee');
|
||||
}
|
||||
|
||||
public function test_retail_register_reads_crm_products_and_snapshots_lines(): void
|
||||
{
|
||||
Http::fake([
|
||||
'crm.test/api/products*' => Http::response(['data' => [
|
||||
['id' => 7, 'name' => 'Mug', 'unit_price_minor' => 2500, 'currency' => 'GHS', 'active' => true],
|
||||
]], 200),
|
||||
'crm.test/api/customers*' => Http::response(['data' => []], 200),
|
||||
'crm.test/api/*' => Http::response(['id' => 1], 201),
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('pos.register'))
|
||||
->assertOk()
|
||||
->assertSee('Coffee');
|
||||
$user = $this->user(); // retail by default (no restaurant location)
|
||||
$this->actingAs($user)->get(route('pos.register'))->assertOk()->assertSee('Mug');
|
||||
|
||||
// A line built from a CRM product is stored as a snapshot — no local FK.
|
||||
$this->actingAs($user)->post(route('pos.register.charge'), [
|
||||
'payment_method' => 'cash',
|
||||
'lines' => [['product_id' => 7, 'name' => 'Mug', 'unit_price_minor' => 2500, 'quantity' => 1]],
|
||||
])->assertRedirect();
|
||||
|
||||
$line = PosSale::where('owner_ref', $user->public_id)->firstOrFail()->lines()->firstOrFail();
|
||||
$this->assertNull($line->product_id);
|
||||
$this->assertSame('Mug', $line->name);
|
||||
$this->assertSame(2500, $line->unit_price_minor);
|
||||
}
|
||||
|
||||
public function test_retail_products_page_lists_crm_products(): void
|
||||
{
|
||||
Http::fake([
|
||||
'crm.test/api/products*' => Http::response(['data' => [
|
||||
['id' => 7, 'name' => 'Mug', 'sku' => 'M1', 'unit_price_minor' => 2500, 'currency' => 'GHS', 'active' => true],
|
||||
]], 200),
|
||||
]);
|
||||
|
||||
$this->actingAs($this->user())->get(route('pos.products.index'))->assertOk()->assertSee('Mug');
|
||||
}
|
||||
|
||||
public function test_cash_sale_is_recorded(): void
|
||||
|
||||
Reference in New Issue
Block a user