Files
Investidor-V2/app/Services/InvestmentZonePathContext.php
T

63 lines
3.5 KiB
PHP

<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
class InvestmentZonePathContext
{
public const NOTICE = 'Referência para preparação; não constitui reserva de lote, confirmação de disponibilidade ou autorização de instalação.';
/**
* @return array<array-key, mixed>
*/
public function context(string $id, int $version): array
{
$zone = app(InvestmentZones::class)->visible()->where('category', 'industrial_park')->findOrFail($id);
abort_unless((int) $zone->version_no === $version, 409, 'A ficha pública mudou. Consulte a versão atual e confirme novamente; a seleção anterior não foi substituída.');
return ['zone_id' => $zone->id, 'consulted_public_version' => (int) $zone->version_no, 'title' => $zone->name, 'href' => '/zonas/'.$zone->id,
'province' => $zone->province, 'district' => $zone->district, 'notice' => self::NOTICE];
}
/**
* @param array<array-key, mixed> $input
* @return array<array-key, mixed>
*/
public function input(array $input): array
{
return Validator::make($input, ['zone_id' => 'required|uuid', 'consulted_public_version' => 'required|integer|min:1'])->validate();
}
/**
* @param array<array-key, mixed> $input
*/
public function attach(User $actor, string $id, array $input): void
{
abort_unless(app(InvestorPath::class)->available(), 404);
$data = Validator::make($input, ['zone_id' => 'required|uuid', 'consulted_public_version' => 'required|integer|min:1', 'version' => 'required|integer|min:1', 'confirm' => 'required|accepted'])->validate();
DB::transaction(function () use ($actor, $id, $data) {
$desk = app(VirtualDesk::class);
$case = $desk->case($actor, $id, true, true);
abort_if($case->closed_at, 409, 'O dossier está encerrado.');
abort_unless(DB::table('investor_journeys')->where('id', $case->journey_id)->whereNotNull('path_definition_id')->whereNull('deleted_at')->exists(), 409, 'Este dossier conserva outro roteiro.');
$payload = $desk->decode($case->payload);
foreach ($payload['investor_path']['zone_contexts'] ?? [] as $existing) {
if ($existing['zone_id'] === $data['zone_id'] && (int) $existing['consulted_public_version'] === (int) $data['consulted_public_version']) {
return;
}
}
abort_unless((int) $case->version === (int) $data['version'], 409, 'O dossier mudou; recupere a versão atual.');
// Lock the public record while checking the consulted version and recording its reference.
DB::table('investment_zones')->where('id', $data['zone_id'])->lockForUpdate()->firstOrFail();
$context = $this->context($data['zone_id'], (int) $data['consulted_public_version']);
abort_unless(count($payload['investor_path']['zone_contexts'] ?? []) < 100, 422, 'Limite de referências deste dossier atingido.');
$payload['investor_path']['zone_contexts'][] = [...$context, 'selected_at' => now()->toIso8601String()];
DB::table('desk_cases')->where('id', $id)->update(['payload' => $desk->encode($payload), 'version' => $case->version + 1, 'updated_at' => now()]);
$desk->event($desk->case($actor, $id), $actor, 'park_reference_selected', ['zone_id' => $context['zone_id'], 'consulted_public_version' => $context['consulted_public_version'], 'scope' => 'preparation_reference_only']);
});
}
}