Files
portal/app/app/Http/Controllers/Concerns/ScopesSalesOwnership.php
T
Дмитрий c366614fcd feat(sales): вход (login/me/logout) + маршруты /api/sales
Task 0.5+0.6: SalesAuthController (login 200/422/403, me, logout) + маршруты /api/sales/auth и зона данных. Порядок middleware admin-db ДО auth:sales. Тест SalesAuthTest 7/7, весь sales-набор 25/25. Logout инвалидирует токен (в тесте Auth::forgetGuards() — артефакт мульти-запросов; в бою каждый запрос свежий). Larastan baseline: Pest false-pos SalesAuthTest. Заодно pint-канон моделей/трейта/SalesModelsTest. Один эскейп на сессию.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:07:47 +03:00

69 lines
2.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Concerns;
use App\Models\SalesClientAssignment;
use App\Models\SalesUser;
use Illuminate\Database\Eloquent\Builder;
/**
* Ограничение ownership для портала отдела продаж.
*
* Менеджер видит только клиентов, закреплённых за ним (tenant_ids из
* sales_client_assignments). Начальник (role='head') видит всех — null
* означает «без ограничения».
*
* Используется в контроллерах /api/sales/* для автоматической фильтрации
* данных в зависимости от роли авторизованного пользователя.
*
* Spec: docs/superpowers/plans/2026-06-30-sales-portal.md (Task 0.4)
*/
trait ScopesSalesOwnership
{
/**
* null => начальник (видит всех); массив => менеджер (только эти tenant_id).
*
* @return list<int>|null
*/
protected function ownedTenantIds(SalesUser $user): ?array
{
if ($user->isHead()) {
return null;
}
/** @var list<int> $ids */
$ids = SalesClientAssignment::query()
->where('sales_user_id', $user->id)
->pluck('tenant_id')
->all();
return $ids;
}
/**
* Применяет фильтр владения к Eloquent-запросу.
*
* Для начальника — возвращает запрос без изменений (видит всё).
* Для менеджера — добавляет whereIn по $column.
* Если у менеджера нет закреплённых клиентов — подставляет [-1],
* чтобы запрос вернул пустую коллекцию.
*
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @param Builder<TModel> $query
* @return Builder<TModel>
*/
protected function scopeByOwnership(Builder $query, SalesUser $user, string $column = 'tenant_id'): Builder
{
$ids = $this->ownedTenantIds($user);
if ($ids === null) {
return $query; // начальник — без ограничения
}
return $query->whereIn($column, $ids === [] ? [-1] : $ids); // пустой → ничего
}
}