89 lines
4.8 KiB
PHP
89 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\CrmTask;
|
|
use App\Models\User;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Database\Query\Builder;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
/** Personal follow-up only: assignment never grants authority beyond the destination. */
|
|
final class DashboardWorkQueue
|
|
{
|
|
/**
|
|
* @param array<string, int> $pages
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function forActor(User $actor, array $pages): ?array
|
|
{
|
|
$now = CarbonImmutable::now()->startOfSecond();
|
|
$access = app(PortalProfileAccess::class);
|
|
$manager = $actor->can('manage-portal') && ! $access->has($actor, 'auditor');
|
|
$groups = [];
|
|
if (app(ScopedPortalAdministration::class)->interestOperator($actor)) {
|
|
$query = DB::table('interest_requests')->where('assigned_to', $actor->id)->whereNull('deleted_at')
|
|
->whereNotIn('status', ['closed', 'cancelled', 'refused', 'converted'])
|
|
->select(['id', 'reference', 'next_action as title', 'status', 'next_action_due_at as due_at']);
|
|
$groups['interests'] = $this->group($query, 'interests', $pages, $now);
|
|
}
|
|
if (app(VirtualDesk::class)->installed()) {
|
|
$assigned = DB::table('desk_requests')->where('analyst_id', $actor->id);
|
|
// Direct request consultation already permits the assigned analyst, independently of decision authority.
|
|
if ($manager || $assigned->exists()) {
|
|
$query = DB::table('desk_requests as r')->join('desk_cases as c', 'c.id', '=', 'r.case_id')
|
|
->where('r.analyst_id', $actor->id)->whereNull('c.closed_at')
|
|
->whereNotIn('r.status', ['draft', 'cancelled', 'closed'])
|
|
->select(['r.id', 'r.protocol as reference', 'c.title', 'r.status', 'r.due_at']);
|
|
$groups['desk'] = $this->group($query, 'desk', $pages, $now);
|
|
}
|
|
}
|
|
if ($manager && Schema::hasTable('tasks') && Schema::hasTable('leads')) {
|
|
$query = CrmTask::availableForWork()->join('leads as l', 'l.id', '=', 'tasks.lead_id')
|
|
->where('tasks.assignee_user_id', $actor->id)->whereNull('l.deleted_at')
|
|
->select(['tasks.id', 'tasks.title', 'tasks.status', 'tasks.due_at', 'l.id as parent_id', 'l.title as reference']);
|
|
$groups['crm_tasks'] = $this->group($query->toBase(), 'crm_tasks', $pages, $now);
|
|
}
|
|
|
|
return $groups === [] ? null : ['as_of' => $now->toISOString(), 'groups' => $groups, 'desk_states' => config('virtual-desk.request_states')];
|
|
}
|
|
|
|
/**
|
|
* @param 'interests'|'desk'|'crm_tasks' $kind
|
|
* @param array<string, int> $pages
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function group(Builder $query, string $kind, array $pages, CarbonImmutable $now): array
|
|
{
|
|
[$deadline, $order, $idColumn] = match ($kind) {
|
|
'interests' => ['next_action_due_at', 'next_action_due_at ASC NULLS LAST', 'id'],
|
|
'desk' => ['r.due_at', 'r.due_at ASC NULLS LAST', 'r.id'],
|
|
'crm_tasks' => ['tasks.due_at', 'tasks.due_at ASC NULLS LAST', 'tasks.id'],
|
|
};
|
|
$pageName = $kind.'_page';
|
|
$page = $pages[$pageName] ?? 1;
|
|
$total = (clone $query)->count();
|
|
$overdue = (clone $query)->where($deadline, '<', $now)->count();
|
|
$lastPage = max(1, (int) ceil($total / 5));
|
|
// An assignment may disappear between visits. Recover to an existing page instead of trapping a stale URL.
|
|
$page = min($page, $lastPage);
|
|
$items = (clone $query)->orderByRaw($order)->orderBy($idColumn)
|
|
->offset(($page - 1) * 5)->limit(5)->get()->map(function (\stdClass $row) use ($kind, $now): array {
|
|
$due = $row->due_at === null ? null : CarbonImmutable::parse($row->due_at);
|
|
|
|
return ['id' => (string) $row->id, 'title' => $row->title ?: 'Acompanhar manifestação', 'reference' => $row->reference,
|
|
'status' => $row->status, 'due_at' => $due?->toISOString(), 'overdue' => $due?->lessThan($now) ?? false,
|
|
'href' => match ($kind) {
|
|
'interests' => '/management/interests/'.$row->id,
|
|
'desk' => '/balcao-virtual/pedidos/'.$row->id,
|
|
'crm_tasks' => '/management/crm/leads/'.$row->parent_id.'#crm-task-'.$row->id,
|
|
}];
|
|
})->all();
|
|
|
|
return ['total' => $total, 'overdue' => $overdue, 'items' => $items, 'page' => $page, 'last_page' => $lastPage,
|
|
'previous' => $page > 1 ? route('dashboard', [...$pages, $pageName => $page - 1], absolute: false) : null,
|
|
'next' => $page < $lastPage ? route('dashboard', [...$pages, $pageName => $page + 1], absolute: false) : null];
|
|
}
|
|
}
|