*/ public function ids(): array { return $this->ownedTenantIds($this->u); } /** @return list|null */ public function visible(Request $request): ?array { return $this->visibleTenantIds($this->u, $request); } public function scoped(Builder $query): Builder { return $this->scopeByOwnership($query, $this->u); } } // ── helpers ──────────────────────────────────────────────────────────────── function makeSalesUserOwn(string $role = 'manager'): SalesUser { return SalesUser::create([ 'name' => ucfirst($role).' '.uniqid(), 'email' => $role.uniqid().'@scope.local', 'password' => Hash::make('secret'), 'role' => $role, ]); } // ── 1. ownedTenantIds ────────────────────────────────────────────────────── test('ownedTenantIds для менеджера возвращает список его tenant_id', function () { $manager = makeSalesUserOwn('manager'); $t1 = Tenant::factory()->create(); $t2 = Tenant::factory()->create(); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t1->id, 'tariff_params' => [], 'assigned_at' => now(), ]); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t2->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $probe = new OwnershipProbe($manager); $ids = $probe->ids(); expect($ids)->toBeArray() ->toEqualCanonicalizing([$t1->id, $t2->id]); }); test('ownedTenantIds для head возвращает ЕГО ЛИЧНЫЕ привязки, а не весь отдел', function () { $head = makeSalesUserOwn('head'); $manager = makeSalesUserOwn('manager'); $mine = Tenant::factory()->create(); $his = Tenant::factory()->create(); SalesClientAssignment::create([ 'sales_user_id' => $head->id, 'tenant_id' => $mine->id, 'tariff_params' => [], 'assigned_at' => now(), ]); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $his->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $ids = (new OwnershipProbe($head))->ids(); expect($ids)->toContain($mine->id)->not->toContain($his->id); }); test('visibleTenantIds: весь отдел только начальнику и только по scope=department', function () { $head = makeSalesUserOwn('head'); $manager = makeSalesUserOwn('manager'); $probe = fn (SalesUser $u, string $qs) => (new OwnershipProbe($u)) ->visible(Request::create('/api/sales/clients'.$qs)); // Начальник без scope — только личное (у него привязок нет → пусто). expect($probe($head, ''))->toBe([]); // Начальник с scope=department — без ограничения. expect($probe($head, '?scope=department'))->toBeNull(); // Менеджеру scope не помогает. expect($probe($manager, '?scope=department'))->toBe([]); }); test('ownedTenantIds для менеджера без клиентов возвращает пустой массив', function () { $manager = makeSalesUserOwn('manager'); $probe = new OwnershipProbe($manager); $ids = $probe->ids(); expect($ids)->toBeArray()->toBeEmpty(); }); // ── 2. scopeByOwnership ──────────────────────────────────────────────────── test('scopeByOwnership для менеджера ограничивает запрос его tenant_id', function () { $manager = makeSalesUserOwn('manager'); $other = makeSalesUserOwn('manager'); $t1 = Tenant::factory()->create(); $t2 = Tenant::factory()->create(); $t3 = Tenant::factory()->create(); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t1->id, 'tariff_params' => [], 'assigned_at' => now(), ]); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t2->id, 'tariff_params' => [], 'assigned_at' => now(), ]); // t3 принадлежит другому менеджеру SalesClientAssignment::create([ 'sales_user_id' => $other->id, 'tenant_id' => $t3->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $probe = new OwnershipProbe($manager); $results = $probe->scoped(SalesClientAssignment::query())->get(); $tenantIds = $results->pluck('tenant_id')->sort()->values()->all(); expect($tenantIds)->toEqualCanonicalizing([$t1->id, $t2->id]); }); test('scopeByOwnership ограничивает и начальника — только его привязки', function () { $head = makeSalesUserOwn('head'); $manager = makeSalesUserOwn('manager'); $t1 = Tenant::factory()->create(); $t2 = Tenant::factory()->create(); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t1->id, 'tariff_params' => [], 'assigned_at' => now(), ]); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $t2->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $probe = new OwnershipProbe($head); $results = $probe->scoped(SalesClientAssignment::query())->get(); // У начальника своих привязок нет → чужие записи менеджера не видны. expect($results->pluck('tenant_id')->all()) ->not->toContain($t1->id) ->not->toContain($t2->id); }); test('scopeByOwnership для менеджера без клиентов возвращает пустую коллекцию', function () { $manager = makeSalesUserOwn('manager'); // Создаём другого менеджера с клиентом, чтобы таблица не была пустой $other = makeSalesUserOwn('manager'); $t1 = Tenant::factory()->create(); SalesClientAssignment::create([ 'sales_user_id' => $other->id, 'tenant_id' => $t1->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $probe = new OwnershipProbe($manager); $results = $probe->scoped(SalesClientAssignment::query())->get(); expect($results)->toBeEmpty(); });