63 lines
3.5 KiB
PHP
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']);
|
|
});
|
|
}
|
|
}
|