126 lines
6.7 KiB
PHP
126 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\User;
|
|
use App\Support\StructuredData;
|
|
use Illuminate\Support\Arr;
|
|
|
|
/** An identified opportunity within the authorised dossier, never the account's last choice. */
|
|
final class InvestmentConsumerScope
|
|
{
|
|
/**
|
|
* @param array<array-key, mixed> $context
|
|
*/
|
|
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(StructuredData::collectionItems($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;
|
|
}
|
|
|
|
/**
|
|
* @param array<array-key, mixed> $context
|
|
* @param array<array-key, mixed> $payload
|
|
* @return array<array-key, mixed>
|
|
*/
|
|
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'] ?? [])];
|
|
}
|
|
|
|
/**
|
|
* @param array<array-key, mixed> $context
|
|
* @return array<array-key, mixed>
|
|
*/
|
|
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(StructuredData::collectionItems($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;
|
|
}
|
|
|
|
/**
|
|
* @param array<array-key, mixed> $payload
|
|
* @return array<array-key, mixed>
|
|
*/
|
|
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;
|
|
}
|
|
}
|