Add per-store managers for Woo Business accounts.
Deploy Ladill Woo Manager / deploy (push) Successful in 39s
Deploy Ladill Woo Manager / deploy (push) Successful in 39s
Agencies can invite store-scoped managers via Identity, with access limited to one WooCommerce store while owners retain full multi-store control. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\EnsurePlatformSession;
|
||||
use App\Models\User;
|
||||
use App\Models\Woo\ProSubscription;
|
||||
use App\Models\WooOrder;
|
||||
use App\Models\WooStore;
|
||||
use App\Models\WooStoreMember;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WooStoreTeamTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
$this->withoutVite();
|
||||
|
||||
config([
|
||||
'woo.pro.enabled' => true,
|
||||
'billing.api_url' => 'https://billing.test',
|
||||
'billing.api_key' => 'test-key',
|
||||
'identity.api_url' => 'https://identity.test/api',
|
||||
'identity.api_key' => 'test-key',
|
||||
]);
|
||||
}
|
||||
|
||||
private function owner(): User
|
||||
{
|
||||
return User::factory()->create();
|
||||
}
|
||||
|
||||
private function manager(): User
|
||||
{
|
||||
return User::factory()->create();
|
||||
}
|
||||
|
||||
private function activateBusiness(User $user): void
|
||||
{
|
||||
ProSubscription::create([
|
||||
'user_id' => $user->id,
|
||||
'plan' => ProSubscription::PLAN_ENTERPRISE,
|
||||
'status' => ProSubscription::STATUS_ACTIVE,
|
||||
'price_minor' => 14900,
|
||||
'currency' => 'GHS',
|
||||
'auto_renew' => true,
|
||||
'started_at' => now(),
|
||||
'current_period_end' => now()->addMonth(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_pro_account_cannot_invite_store_manager(): void
|
||||
{
|
||||
$owner = $this->owner();
|
||||
ProSubscription::create([
|
||||
'user_id' => $owner->id,
|
||||
'plan' => ProSubscription::PLAN_PRO,
|
||||
'status' => ProSubscription::STATUS_ACTIVE,
|
||||
'price_minor' => 4900,
|
||||
'currency' => 'GHS',
|
||||
'auto_renew' => true,
|
||||
'started_at' => now(),
|
||||
'current_period_end' => now()->addMonth(),
|
||||
]);
|
||||
|
||||
$store = WooStore::create([
|
||||
'user_id' => $owner->id,
|
||||
'site_url' => 'https://shop-a.example.com',
|
||||
'site_name' => 'Shop A',
|
||||
'status' => WooStore::STATUS_ACTIVE,
|
||||
'connected_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($owner)
|
||||
->post(route('woo.team.store'), [
|
||||
'email' => 'client@example.com',
|
||||
'woo_store_id' => $store->id,
|
||||
])
|
||||
->assertRedirect(route('woo.pro.index'));
|
||||
|
||||
$this->assertDatabaseCount('woo_store_members', 0);
|
||||
}
|
||||
|
||||
public function test_business_owner_can_invite_store_manager(): void
|
||||
{
|
||||
$owner = $this->owner();
|
||||
$this->activateBusiness($owner);
|
||||
|
||||
$store = WooStore::create([
|
||||
'user_id' => $owner->id,
|
||||
'site_url' => 'https://shop-a.example.com',
|
||||
'site_name' => 'Shop A',
|
||||
'status' => WooStore::STATUS_ACTIVE,
|
||||
'connected_at' => now(),
|
||||
]);
|
||||
|
||||
Http::fake([
|
||||
'identity.test/*' => Http::response(['data' => []], 200),
|
||||
]);
|
||||
|
||||
$this->actingAs($owner)
|
||||
->from(route('woo.settings'))
|
||||
->post(route('woo.team.store'), [
|
||||
'email' => 'client@example.com',
|
||||
'woo_store_id' => $store->id,
|
||||
])
|
||||
->assertRedirect(route('woo.settings').'#store-team');
|
||||
|
||||
$this->assertDatabaseHas('woo_store_members', [
|
||||
'owner_ref' => $owner->public_id,
|
||||
'user_ref' => 'client@example.com',
|
||||
'woo_store_id' => $store->id,
|
||||
'role' => WooStoreMember::ROLE_MANAGER,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_store_manager_only_sees_assigned_store(): void
|
||||
{
|
||||
$owner = $this->owner();
|
||||
$this->activateBusiness($owner);
|
||||
$manager = $this->manager();
|
||||
|
||||
$storeA = WooStore::create([
|
||||
'user_id' => $owner->id,
|
||||
'site_url' => 'https://shop-a.example.com',
|
||||
'site_name' => 'Shop A',
|
||||
'status' => WooStore::STATUS_ACTIVE,
|
||||
'connected_at' => now(),
|
||||
]);
|
||||
$storeB = WooStore::create([
|
||||
'user_id' => $owner->id,
|
||||
'site_url' => 'https://shop-b.example.com',
|
||||
'site_name' => 'Shop B',
|
||||
'status' => WooStore::STATUS_ACTIVE,
|
||||
'connected_at' => now(),
|
||||
]);
|
||||
|
||||
WooStoreMember::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'user_ref' => $manager->public_id,
|
||||
'woo_store_id' => $storeA->id,
|
||||
'role' => WooStoreMember::ROLE_MANAGER,
|
||||
]);
|
||||
|
||||
WooOrder::create([
|
||||
'woo_store_id' => $storeA->id,
|
||||
'external_order_id' => 1,
|
||||
'order_number' => '1001',
|
||||
'customer_name' => 'Customer A',
|
||||
'line_items' => [],
|
||||
'currency' => 'GHS',
|
||||
'total_minor' => 1000,
|
||||
]);
|
||||
WooOrder::create([
|
||||
'woo_store_id' => $storeB->id,
|
||||
'external_order_id' => 2,
|
||||
'order_number' => '2002',
|
||||
'customer_name' => 'Customer B',
|
||||
'line_items' => [],
|
||||
'currency' => 'GHS',
|
||||
'total_minor' => 2000,
|
||||
]);
|
||||
|
||||
$this->actingAs($manager)
|
||||
->withSession(['ladill_account' => $owner->id])
|
||||
->get(route('woo.orders.index'))
|
||||
->assertOk()
|
||||
->assertSee('1001')
|
||||
->assertSee('Customer A')
|
||||
->assertDontSee('2002')
|
||||
->assertDontSee('Customer B');
|
||||
}
|
||||
|
||||
public function test_store_manager_cannot_disconnect_store(): void
|
||||
{
|
||||
$owner = $this->owner();
|
||||
$this->activateBusiness($owner);
|
||||
$manager = $this->manager();
|
||||
|
||||
$store = WooStore::create([
|
||||
'user_id' => $owner->id,
|
||||
'site_url' => 'https://shop-a.example.com',
|
||||
'site_name' => 'Shop A',
|
||||
'status' => WooStore::STATUS_ACTIVE,
|
||||
'connected_at' => now(),
|
||||
]);
|
||||
|
||||
WooStoreMember::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'user_ref' => $manager->public_id,
|
||||
'woo_store_id' => $store->id,
|
||||
'role' => WooStoreMember::ROLE_MANAGER,
|
||||
]);
|
||||
|
||||
$this->actingAs($manager)
|
||||
->withSession(['ladill_account' => $owner->id])
|
||||
->delete(route('woo.stores.destroy', $store))
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertSame(WooStore::STATUS_ACTIVE, $store->fresh()->status);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user