Deploy Ladill POS / deploy (push) Successful in 2m15s
Enforce plan location caps in SubscriptionService, surface upgrade copy on plans and branch settings, and cover the limits in tests.
260 lines
7.7 KiB
PHP
260 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Http\Middleware\EnsurePlatformSession;
|
|
use App\Models\Pos\ProSubscription;
|
|
use App\Models\PosLocation;
|
|
use App\Models\PosMember;
|
|
use App\Models\PosSale;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class PosMultiBranchTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function owner(): User
|
|
{
|
|
return User::create([
|
|
'public_id' => '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(),
|
|
]);
|
|
}
|
|
|
|
private function activateBusiness(User $user): void
|
|
{
|
|
ProSubscription::create([
|
|
'user_id' => $user->id,
|
|
'plan' => ProSubscription::PLAN_ENTERPRISE,
|
|
'status' => ProSubscription::STATUS_ACTIVE,
|
|
'price_minor' => 24900,
|
|
'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_pro_account_cannot_add_fourth_branch(): void
|
|
{
|
|
$owner = $this->owner();
|
|
$this->activatePro($owner);
|
|
|
|
foreach (['Main', 'Mall', 'Airport'] as $i => $name) {
|
|
PosLocation::create([
|
|
'owner_ref' => $owner->public_id,
|
|
'name' => $name,
|
|
'currency' => 'GHS',
|
|
'is_default' => $i === 0,
|
|
]);
|
|
}
|
|
|
|
$this->assertSame(3, PosLocation::owned($owner->public_id)->count());
|
|
|
|
$this->actingAs($owner)
|
|
->post(route('pos.branches.store'), [
|
|
'name' => 'Fourth branch',
|
|
'currency' => 'GHS',
|
|
'service_style' => 'retail',
|
|
])
|
|
->assertRedirect(route('pos.pro.index'));
|
|
|
|
$this->assertSame(3, PosLocation::owned($owner->public_id)->count());
|
|
}
|
|
|
|
public function test_business_account_can_add_beyond_three_branches(): void
|
|
{
|
|
$owner = $this->owner();
|
|
$this->activateBusiness($owner);
|
|
|
|
foreach (['Main', 'Mall', 'Airport'] as $i => $name) {
|
|
PosLocation::create([
|
|
'owner_ref' => $owner->public_id,
|
|
'name' => $name,
|
|
'currency' => 'GHS',
|
|
'is_default' => $i === 0,
|
|
]);
|
|
}
|
|
|
|
$this->actingAs($owner)
|
|
->post(route('pos.branches.store'), [
|
|
'name' => 'Fourth branch',
|
|
'currency' => 'GHS',
|
|
'service_style' => 'retail',
|
|
])
|
|
->assertRedirect(route('pos.settings').'#branches');
|
|
|
|
$this->assertSame(4, 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();
|
|
}
|
|
}
|