'owner-'.uniqid(), 'name' => 'Owner', 'email' => uniqid().'@owner.example.com', ]); } private function cashier(): User { return User::create([ 'public_id' => 'cashier-'.uniqid(), 'name' => 'Cashier', 'email' => uniqid().'@cashier.example.com', ]); } private function activatePro(User $user): void { ProSubscription::create([ 'user_id' => $user->id, 'plan' => ProSubscription::PLAN_PRO, 'status' => ProSubscription::STATUS_ACTIVE, 'price_minor' => 7900, 'currency' => 'GHS', 'auto_renew' => true, 'started_at' => now(), 'current_period_end' => now()->addMonth(), ]); } protected function setUp(): void { parent::setUp(); $this->withoutMiddleware(EnsurePlatformSession::class); $this->withoutVite(); config([ 'pos.pro.enabled' => true, 'billing.api_url' => 'https://billing.test', 'billing.api_key' => 'test-key', ]); } public function test_free_account_cannot_add_second_branch(): void { $owner = $this->owner(); PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Main register', 'currency' => 'GHS', 'is_default' => true, ]); $this->actingAs($owner) ->post(route('pos.branches.store'), [ 'name' => 'Second branch', 'currency' => 'GHS', 'service_style' => 'retail', ]) ->assertRedirect(route('pos.pro.index')); $this->assertSame(1, PosLocation::owned($owner->public_id)->count()); } public function test_pro_account_can_add_branch(): void { $owner = $this->owner(); $this->activatePro($owner); PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Main register', 'currency' => 'GHS', 'is_default' => true, ]); $this->actingAs($owner) ->post(route('pos.branches.store'), [ 'name' => 'Mall kiosk', 'currency' => 'GHS', 'service_style' => 'retail', ]) ->assertRedirect(route('pos.settings').'#branches'); $this->assertSame(2, PosLocation::owned($owner->public_id)->count()); } public function test_cashier_is_limited_to_assigned_branch_sales(): void { $owner = $this->owner(); $this->activatePro($owner); $branchA = PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Downtown', 'currency' => 'GHS', 'is_default' => true, ]); $branchB = PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Airport', 'currency' => 'GHS', ]); $cashier = $this->cashier(); PosMember::create([ 'owner_ref' => $owner->public_id, 'user_ref' => $cashier->public_id, 'role' => PosMember::ROLE_CASHIER, 'location_id' => $branchB->id, ]); $saleA = PosSale::create([ 'owner_ref' => $owner->public_id, 'location_id' => $branchA->id, 'reference' => 'POS-A', 'currency' => 'GHS', 'status' => 'paid', 'payment_method' => 'cash', 'total_minor' => 1000, ]); $saleB = PosSale::create([ 'owner_ref' => $owner->public_id, 'location_id' => $branchB->id, 'reference' => 'POS-B', 'currency' => 'GHS', 'status' => 'paid', 'payment_method' => 'cash', 'total_minor' => 2000, ]); $this->actingAs($cashier) ->withSession(['ladill_account' => $owner->id]) ->get(route('pos.sales.show', $saleB)) ->assertOk() ->assertSee('POS-B'); $this->actingAs($cashier) ->withSession(['ladill_account' => $owner->id]) ->get(route('pos.sales.show', $saleA)) ->assertNotFound(); } public function test_cashier_cannot_switch_to_other_branch(): void { $owner = $this->owner(); $this->activatePro($owner); $branchA = PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Downtown', 'currency' => 'GHS', 'is_default' => true, ]); $branchB = PosLocation::create([ 'owner_ref' => $owner->public_id, 'name' => 'Airport', 'currency' => 'GHS', ]); $cashier = $this->cashier(); PosMember::create([ 'owner_ref' => $owner->public_id, 'user_ref' => $cashier->public_id, 'role' => PosMember::ROLE_CASHIER, 'location_id' => $branchB->id, ]); $this->actingAs($cashier) ->withSession(['ladill_account' => $owner->id]) ->post(route('pos.location.switch'), ['location' => $branchA->id]) ->assertForbidden(); } }