fix: complete InvesteMoz validation and error corrections

This commit is contained in:
2026-10-29 21:47:33 +02:00
parent 63147312e2
commit daf8623441
718 changed files with 127308 additions and 20959 deletions
+20 -13
View File
@@ -10,6 +10,7 @@ use App\Services\CountryCatalogue;
use App\Services\InstitutionalLinkMonitor;
use App\Services\InvestmentGeography;
use App\Services\InvestorContextConsumers;
use App\Services\ScopedPortalAdministration;
use App\Services\VerifiedDocumentBinary;
use App\Services\VirtualDesk;
use Illuminate\Http\JsonResponse;
@@ -21,6 +22,7 @@ use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -148,7 +150,7 @@ class VirtualDeskController extends Controller
$data = ['boundContextRevision' => app(InvestorContextConsumers::class)->requestRevision($row), 'countries' => app(CountryCatalogue::class)->all(), 'toolPrefill' => $desk->requestToolPrefill($request->user(), $row), 'request' => [...(array) $row, 'payload' => $payload, 'submitted_snapshot' => $desk->decode($row->submitted_snapshot), 'editable_fields' => json_decode($row->editable_fields ?? '[]', true)],
'case' => ['id' => $case->id, 'title' => $case->title], 'caseVersion' => $case->version, 'definition' => $definition, 'territoryPaths' => $territoryPaths,
'serviceSource' => json_decode(DB::table('desk_service_versions')->where('id', $row->service_version_id)->value('source'), true),
'owner' => $desk->owns($request->user(), $case), 'manager' => app(\App\Services\ScopedPortalAdministration::class)->deskDecision($request->user(),$row), 'analyst' => (int) $row->analyst_id === $request->user()->id,
'owner' => $desk->owns($request->user(), $case), 'manager' => app(ScopedPortalAdministration::class)->deskDecision($request->user(), $row), 'analyst' => (int) $row->analyst_id === $request->user()->id,
'fieldsEditable' => in_array($row->status, ['draft', 'returned'], true), 'states' => config('virtual-desk.request_states'), 'transitions' => config('virtual-desk.transitions.'.$row->status, []),
'findings' => $desk->findings($payload), 'ai' => config('virtual-desk.ai'), 'documents' => $this->documents($case->id, $request->user())->filter(fn ($d) => ! $d->request_id || $d->request_id === $id)->values(),
'messages' => DB::table('desk_messages as m')->join('users as u', 'u.id', '=', 'm.actor_id')->where('request_id', $id)->orderBy('m.created_at')->get(['m.id', 'm.actor_id', 'm.body', 'm.created_at', 'u.name'])->map(fn ($m) => [...(array) $m, 'body' => Crypt::decryptString($m->body),
@@ -178,24 +180,29 @@ class VirtualDeskController extends Controller
public function assignments(Request $request): JsonResponse|Response
{
abort_unless(app(\App\Services\ScopedPortalAdministration::class)->administrative($request->user()),403);
abort_unless(app(ScopedPortalAdministration::class)->administrative($request->user()), 403);
// Triage projection deliberately excludes payloads, documents, investor identity and case titles.
$data=['requests'=>DB::table('desk_requests')->whereNotIn('status',['draft','cancelled','closed'])->orderBy('created_at')->get(['id','protocol','status','version','analyst_id','due_at']),
'analysts'=>User::whereNotNull('email_verified_at')->orderBy('name')->get(['id','name'])];
return $request->expectsJson()?response()->json($data):Inertia::render('management/desk-assignments',$data);
$data = ['requests' => DB::table('desk_requests')->whereNotIn('status', ['draft', 'cancelled', 'closed'])->orderBy('created_at')->get(['id', 'protocol', 'status', 'version', 'analyst_id', 'due_at']),
'analysts' => User::whereNotNull('email_verified_at')->orderBy('name')->get(['id', 'name'])];
return $request->expectsJson() ? response()->json($data) : Inertia::render('management/desk-assignments', $data);
}
public function assign(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
abort_unless(app(\App\Services\ScopedPortalAdministration::class)->administrative($request->user()), 403);
$data = $request->validate(['version' => 'required|integer', 'analyst_id' => 'required|integer|exists:users,id', 'reason' => 'required|string|min:3|max:3000', 'due_at' => 'nullable|date'], ['reason.required'=>'Explique o motivo da atribuição.','reason.min'=>'Explique o motivo da atribuição com pelo menos 3 caracteres.','analyst_id.required'=>'Seleccione o responsável.','analyst_id.exists'=>'Seleccione um responsável com conta disponível.']);
abort_unless(app(ScopedPortalAdministration::class)->administrative($request->user()), 403);
$data = $request->validate(['version' => 'required|integer', 'analyst_id' => 'required|integer|exists:users,id', 'reason' => 'required|string|min:3|max:3000', 'due_at' => 'nullable|date'], ['reason.required' => 'Explique o motivo da atribuição.', 'reason.min' => 'Explique o motivo da atribuição com pelo menos 3 caracteres.', 'analyst_id.required' => 'Seleccione o responsável.', 'analyst_id.exists' => 'Seleccione um responsável com conta disponível.']);
DB::transaction(function () use ($request, $id, $desk, $data) {
$row = DB::table('desk_requests')->where('id',$id)->lockForUpdate()->first();
abort_unless($row,404);
$case = DB::table('desk_cases')->where('id',$row->case_id)->first();
abort_unless($case,404);
if ((int)$row->version !== (int)$data['version']) throw \Illuminate\Validation\ValidationException::withMessages(['version'=>'Este pedido foi actualizado. Recupere a lista e tente novamente.']);
if (in_array($row->status,['draft','cancelled','closed'],true)) throw \Illuminate\Validation\ValidationException::withMessages(['status'=>'Este pedido já não permite uma nova atribuição. Recupere a lista actual.']);
$row = DB::table('desk_requests')->where('id', $id)->lockForUpdate()->first();
abort_unless($row !== null, 404);
$case = DB::table('desk_cases')->where('id', $row->case_id)->first();
abort_unless($case !== null, 404);
if ((int) $row->version !== (int) $data['version']) {
throw ValidationException::withMessages(['version' => 'Este pedido foi actualizado. Recupere a lista e tente novamente.']);
}
if (in_array($row->status, ['draft', 'cancelled', 'closed'], true)) {
throw ValidationException::withMessages(['status' => 'Este pedido já não permite uma nova atribuição. Recupere a lista actual.']);
}
$analyst = User::where('id', $data['analyst_id'])->firstOrFail();
abort_unless($analyst->hasVerifiedEmail(), 422, 'O responsável deve ter conta verificada.');
abort_if($desk->owns($analyst, $case, false), 422, 'O proponente não pode ser o analista.');