86 lines
5.9 KiB
PHP
86 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Support\Arr;
|
|
|
|
/** An identified opportunity within the authorised dossier, never the account's last choice. */
|
|
final class InvestmentConsumerScope
|
|
{
|
|
public function key(array $context, ?string $key, bool $required = false): ?string
|
|
{
|
|
$choices = $context['opportunity_choices'] ?? [];
|
|
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
|
|
abort_if($key && !collect($choices)->contains('opportunity.key', $key), 422, 'Escolha uma oportunidade deste dossier.');
|
|
abort_if($required && count($choices) > 1 && !$key, 422, 'Escolha a oportunidade em tratamento.');
|
|
return $key;
|
|
}
|
|
|
|
public function facts(array $payload, array $context, ?string $key): array
|
|
{
|
|
$key = $this->key($context, $key);
|
|
$path = $payload['investor_path'] ?? [];
|
|
$defaults = ['land_needed' => 'unknown', 'external_funding' => 'unknown', 'viability' => 'unknown'];
|
|
// A dossier-wide dispensation cannot decide a distinct opportunity's needs.
|
|
if ($key && count($context['opportunity_choices'] ?? []) > 1) return [...$defaults, ...($path['opportunity_facts'][$key] ?? [])];
|
|
if ($key && isset($path['opportunity_facts'][$key])) return [...$defaults, ...$path['opportunity_facts'][$key]];
|
|
if (count($context['opportunity_choices'] ?? []) > 1) return $defaults;
|
|
return [...$defaults, ...($path['facts'] ?? [])];
|
|
}
|
|
|
|
public function context(array $context, ?string $key): array
|
|
{
|
|
$choices = $context['opportunity_choices'] ?? [];
|
|
if (!$choices) return $context;
|
|
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
|
|
$choice = $key ? collect($choices)->firstWhere('opportunity.key', $key) : null;
|
|
abort_if($key && !$choice, 422, 'Escolha uma oportunidade deste dossier.');
|
|
$specific = ['project_summary', 'sector_id', 'sector', 'province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location', 'special_zone_id', 'investment_regime'];
|
|
$context['fields'] = Arr::except($context['fields'], $specific);
|
|
$context['provenance'] = Arr::except($context['provenance'] ?? [], $specific);
|
|
$context['selection'] = Arr::except($context['selection'], ['opportunity', 'territory', 'park']);
|
|
if (!$choice) {
|
|
$context['opportunity_choices'] = [];
|
|
$context['requirements_assessment']['requirements'] = [];
|
|
return $context;
|
|
}
|
|
$context['selection']['opportunity'] = $choice['opportunity'];
|
|
$context['fields'] = [...$context['fields'], ...Arr::only($choice['opportunity']['fields'], $specific)];
|
|
foreach (Arr::only($choice['opportunity']['fields'], $specific) as $field => $value) $context['provenance'][$field] = Arr::only($choice['opportunity'], ['key','kind','id','title','version','sha256']);
|
|
unset($context['selection']['sector']);
|
|
if (!empty($context['fields']['sector_id'])) $context['selection']['sector'] = app(InvestorContext::class)->reference('sector:'.$context['fields']['sector_id']);
|
|
if ($choice['territory']) {
|
|
$context['selection']['territory'] = $choice['territory'];
|
|
$context['fields'] = [...Arr::except($context['fields'], array_keys(InvestmentGeography::FIELDS)), ...$choice['territory']['fields']];
|
|
foreach ($choice['territory']['fields'] as $field => $value) $context['provenance'][$field] = Arr::only($choice['territory'], ['key','kind','id','title','version','sha256']);
|
|
} else {
|
|
$context['fields'] = Arr::except($context['fields'], ['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location']);
|
|
}
|
|
$park = $choice['park'] ?? null;
|
|
if ($park) $context['selection']['park'] = $park;
|
|
$context['fields']['special_zone_id'] = $park['id'] ?? '';
|
|
$context['fields']['investment_regime'] = $park['fields']['investment_regime'] ?? 'general';
|
|
$context['opportunity_choices'] = [$choice];
|
|
$context['requirements_assessment']['requirements'] = array_values(array_filter($context['requirements_assessment']['requirements'] ?? [], fn($r) => $r['opportunity_key'] === $key));
|
|
$context['consumer_opportunity'] = $choice;
|
|
$context['complements'] = array_values(array_filter($context['complements'] ?? [], fn($c) => ($c['origin']['key'] ?? null) === $key || ($c['target']['key'] ?? null) === $key || in_array(substr($c['origin']['key'] ?? '',10),array_column($choice['portfolio_origins'] ?? [],'id'),true)));
|
|
$context['dependency_hash'] = app(InvestorContext::class)->dependencyHash(['opportunity_choices'=>[$choice], 'fields'=>Arr::except($context['fields'],['project_title','project_summary']), 'complements'=>$context['complements']]);
|
|
return $context;
|
|
}
|
|
|
|
public function bind(User $actor, string $id, array $payload, bool $required = false): array
|
|
{
|
|
$case = app(VirtualDesk::class)->case($actor, $id, true);
|
|
$context = app(InvestorContext::class)->state($case);
|
|
$scoped = $this->context($context, $payload['context_opportunity'] ?? null);
|
|
$choice = $scoped['consumer_opportunity'] ?? null;
|
|
abort_if($required && count($context['opportunity_choices'] ?? []) > 1 && !$choice, 422, 'Escolha a oportunidade em tratamento antes de submeter.');
|
|
if (!$choice) return Arr::except($payload, ['context_opportunity', 'context_opportunity_snapshot']);
|
|
// Canonical server snapshot; client text cannot establish a different origin or territory.
|
|
$payload['context_opportunity'] = $choice['opportunity']['key'];
|
|
$payload['context_opportunity_snapshot'] = json_encode(['context_id' => $id, 'revision' => $context['revision'], 'choice' => $choice, 'requirements' => $scoped['requirements_assessment'] ?? null], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
|
|
return $payload;
|
|
}
|
|
}
|