@@ -15,6 +15,7 @@ use App\Services\VerifiedDocumentBinary;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@@ -55,8 +56,17 @@ class LandAssistanceController extends Controller
|
||||
|
||||
public function create(Request $request): Response
|
||||
{
|
||||
$context = $request->validate(['context' => ['nullable', 'uuid']])['context'] ?? null;
|
||||
$dossier = null;
|
||||
if ($context !== null) {
|
||||
$case = app(\App\Services\VirtualDesk::class)->case($request->user(), $context);
|
||||
abort_unless(config('investor-path.enabled') && (int) $case->user_id === $request->user()->id && ! $case->closed_at && $case->journey_id
|
||||
&& DB::table('investor_journeys')->where('id', $case->journey_id)->whereNotNull('path_definition_id')->whereNull('deleted_at')->exists(), 403);
|
||||
$dossier = ['id' => $case->id, 'title' => $case->title, 'url' => '/investimentos/'.$case->id];
|
||||
}
|
||||
return Inertia::render('land-assistance/form', [
|
||||
'case' => null,
|
||||
'returnDossier' => $dossier,
|
||||
'user' => ['name' => $request->user()->name, 'email' => $request->user()->email],
|
||||
'disclaimer' => self::DISCLAIMER,
|
||||
'modelVersion' => 'land-assistance-v1',
|
||||
@@ -71,6 +81,7 @@ class LandAssistanceController extends Controller
|
||||
|
||||
return Inertia::render('land-assistance/form', [
|
||||
'case' => $case->only(['id', 'reference', 'version', 'status', 'payload']),
|
||||
'returnDossier' => $this->dossierContext($case),
|
||||
'user' => ['name' => $request->user()->name, 'email' => $request->user()->email],
|
||||
'disclaimer' => self::DISCLAIMER,
|
||||
'modelVersion' => 'land-assistance-v1',
|
||||
@@ -152,8 +163,11 @@ class LandAssistanceController extends Controller
|
||||
$submittedPayload = $request->payload();
|
||||
$case = DB::transaction(function () use ($request, $id, $data, $submission, $submittedPayload): LandAssistanceCase {
|
||||
$case = $this->owned($request, $id, true);
|
||||
abort_unless(in_array($case->status, ['draft', 'waiting_applicant'], true), 409, 'Este pedido já não pode ser submetido neste estado.');
|
||||
$this->checkVersion($case, (int) $data['version']);
|
||||
$replaying = $case->status === 'support_requested';
|
||||
abort_unless(in_array($case->status, ['draft', 'waiting_applicant', 'support_requested'], true), 409, 'Este pedido já não pode ser submetido neste estado.');
|
||||
if (! $replaying) {
|
||||
$this->checkVersion($case, (int) $data['version']);
|
||||
}
|
||||
$payload = [...$case->payload, ...$submittedPayload];
|
||||
$payload['full_name'] = $payload['full_name'] ?? $request->user()->name;
|
||||
if (! array_key_exists('email', $payload)) {
|
||||
@@ -161,6 +175,14 @@ class LandAssistanceController extends Controller
|
||||
}
|
||||
$payload['email'] = is_string($payload['email']) && trim($payload['email']) !== '' ? strtolower(trim($payload['email'])) : null;
|
||||
abort_if(empty($payload['email']) && empty($payload['phone']), 422, 'Indique pelo menos um contacto valido.');
|
||||
if ($replaying) {
|
||||
// A retry of the same accepted attempt recovers its original receipt.
|
||||
// Changed data, another version or a missing receipt must not reopen the case.
|
||||
abort_unless((int) $case->version === (int) $data['version'] + 1 && $case->interest_request_id
|
||||
&& hash_equals(hash('sha256', json_encode(Arr::sortRecursive($case->payload), JSON_THROW_ON_ERROR)),
|
||||
hash('sha256', json_encode(Arr::sortRecursive($payload), JSON_THROW_ON_ERROR))),
|
||||
409, 'O pedido mudou; recupere o estado atual antes de voltar a enviar.');
|
||||
}
|
||||
$message = trim(($payload['request_description'] ?? 'Pedido de apoio sobre Terra e DUAT.')."\nReferência interna: {$case->reference}. Tipo: ".($payload['support_kind'] ?? 'não indicado').'.');
|
||||
$interest = $submission->receive([
|
||||
'kind' => 'support', 'fullName' => $payload['full_name'], 'email' => $payload['email'],
|
||||
@@ -172,13 +194,25 @@ class LandAssistanceController extends Controller
|
||||
], $case->crm_submission_key, fn () => InterestRequest::create([
|
||||
'reference' => 'AP-'.now()->year.'-'.Str::ulid(), 'full_name' => $payload['full_name'],
|
||||
'email' => $payload['email'], 'phone' => $payload['phone'] ?? null,
|
||||
'country' => $payload['country'] ?? 'Não indicado', 'investor_type' => 'individual',
|
||||
'country' => $payload['country'] ?? 'Não indicado',
|
||||
// Use the existing intake vocabulary; retain the more specific declared category.
|
||||
// This factory only runs for a new receipt. Older submissions/replay hashes stay intact.
|
||||
'investor_type' => match ($payload['applicant_category'] ?? null) {
|
||||
'individual' => 'individual', 'entity' => 'empresa', default => 'outro',
|
||||
},
|
||||
'sector_interest' => 'Terra e DUAT', 'message' => mb_substr($message, 0, 2000),
|
||||
'privacy_consent' => true, 'consented_at' => now(), 'status' => 'received', 'source_page' => '/terra-duat',
|
||||
'metadata' => ['kind' => 'support', 'portal_user_id' => $request->user()->id,
|
||||
'land_case_id' => $case->id, 'land_case_reference' => $case->reference,
|
||||
'applicant_category' => $payload['applicant_category'] ?? null,
|
||||
'declared_origin_country_code' => $payload['declared_origin_country_code'] ?? null],
|
||||
]));
|
||||
if ($replaying) {
|
||||
abort_unless((int) $interest->getKey() === (int) $case->interest_request_id && ! $interest->trashed(),
|
||||
409, 'O recibo original não está disponível; recupere o estado do pedido.');
|
||||
|
||||
return $case;
|
||||
}
|
||||
$case->forceFill([
|
||||
'payload' => $payload,
|
||||
'status' => 'support_requested',
|
||||
@@ -287,7 +321,13 @@ class LandAssistanceController extends Controller
|
||||
|
||||
public function download(Request $request, string $id, string $attachment): \Illuminate\Http\Response|BinaryFileResponse
|
||||
{
|
||||
$case = $this->owned($request, $id);
|
||||
// Management uses its existing explicit permission; the owner URL stays owner-only.
|
||||
if ($request->routeIs('land-assistance.manage.download')) {
|
||||
abort_unless($request->user()->can('manage-portal'), 403);
|
||||
$case = LandAssistanceCase::whereKey($id)->firstOrFail();
|
||||
} else {
|
||||
$case = $this->owned($request, $id);
|
||||
}
|
||||
$document = DB::table('land_assistance_documents as link')->join('documents as document', 'document.id', '=', 'link.document_id')
|
||||
->where('link.case_id', $id)->where('link.id', $attachment)->where('document.status', 'active')->whereNull('document.deleted_at')
|
||||
->where('document.malware_scan_status', 'clean')->whereColumn('document.malware_scanned_sha256', 'document.sha256')
|
||||
@@ -327,7 +367,18 @@ class LandAssistanceController extends Controller
|
||||
}
|
||||
|
||||
return ['countryName' => $country['code'] !== null ? $country['name'] : ($payload['country'] ?? 'Não informado'),
|
||||
'declaredOrigin' => $countries->describe($payload['declared_origin_country_code'] ?? null), 'territoryPaths' => $paths];
|
||||
'declaredOrigin' => $countries->describe($payload['declared_origin_country_code'] ?? null), 'territoryPaths' => $paths, 'returnDossier' => $this->dossierContext($case)];
|
||||
}
|
||||
|
||||
private function dossierContext(LandAssistanceCase $case): ?array
|
||||
{
|
||||
$id = $case->payload['investor_path_case_id'] ?? null;
|
||||
$actor = request()->user();
|
||||
if (! $actor || (int) $case->user_id !== $actor->id || ! is_string($id) || ! Str::isUuid($id) || ! config('investor-path.enabled')) {
|
||||
return null;
|
||||
}
|
||||
$dossier = DB::table('desk_cases')->where('id', $id)->where('user_id', $actor->id)->first();
|
||||
return $dossier ? ['id' => $dossier->id, 'title' => $dossier->title, 'url' => '/investimentos/'.$dossier->id] : null;
|
||||
}
|
||||
|
||||
public function manage(Request $request): Response
|
||||
|
||||
Reference in New Issue
Block a user