fix(projects-bulk): treat empty scope.filter as valid scope

Replace !empty() check with has()+is_array() so scope:{filter:{}} is
accepted as "all projects" rather than rejected as missing selection.
Expand scope.filter to IDs in the controller (500-row limit guard) so
the service receives a typed array[]; add Pest coverage for this case.
Update phpstan baseline count for new actingAs() call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-12 14:43:45 +03:00
parent 40202caf34
commit 08f02100fe
4 changed files with 41 additions and 7 deletions
@@ -142,11 +142,33 @@ class ProjectController extends Controller
/** POST /api/projects/bulk — batch pause/resume/archive */
public function bulk(BulkProjectActionRequest $request): JsonResponse
{
$updated = $this->projects->bulkAction(
$request->user()->tenant_id,
$request->validated('action'),
$request->validated('ids'),
);
$tenantId = $request->user()->tenant_id;
$action = $request->validated('action');
// Resolve target IDs: explicit list takes priority; otherwise expand from scope.filter.
if ($request->has('scope.filter')) {
$filter = $request->validated('scope.filter') ?? [];
$query = Project::where('tenant_id', $tenantId);
if (! empty($filter['signal_type'])) {
$query->where('signal_type', $filter['signal_type']);
}
if (! empty($filter['status'])) {
match ($filter['status']) {
'active' => $query->whereNull('archived_at')->where('is_active', true),
'paused' => $query->whereNull('archived_at')->where('is_active', false),
'archived' => $query->whereNotNull('archived_at'),
default => null,
};
}
if (! empty($filter['search'])) {
$query->where('name', 'ilike', '%'.$filter['search'].'%');
}
$ids = $query->limit(500)->pluck('id')->all();
} else {
$ids = $request->validated('ids') ?? [];
}
$updated = $this->projects->bulkAction($tenantId, $action, $ids);
return response()->json(['updated' => $updated]);
}