77 lines
4.0 KiB
PHP
77 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
final class InvestorPathDefinition
|
|
{
|
|
public const STATES = ['not_started', 'preparing', 'ready_to_submit', 'submitted', 'reviewing', 'correction_required', 'waiting_external', 'approved', 'rejected', 'dispensed', 'completed', 'expired'];
|
|
|
|
/** @return array<string,mixed> */
|
|
public static function snapshot(): array
|
|
{
|
|
$titles = ['Sistematizar a ideia', 'Análise preliminar', 'Decisão sobre a viabilidade', 'Estruturar o investimento',
|
|
'Constituição e registo', 'Preparar o dossier', 'Submeter quando aplicável', 'Licenciamento prévio',
|
|
'Necessidade de terra', 'Regularização da terra', 'Confirmar regularização aplicável',
|
|
'Necessidade e estrutura de financiamento', 'Diligência e negociação financeira', 'Decisão do financiador',
|
|
'Fecho e desembolso', 'Implementação', 'Inspecções, testes e licença de operação', 'Início de operação', 'Acompanhamento recorrente'];
|
|
$steps = [];
|
|
foreach ($titles as $index => $title) {
|
|
$n = $index + 1;
|
|
$steps[] = ['code' => sprintf('S%02d', $n), 'sequence' => $n, 'title' => $title,
|
|
'phase' => $n <= 4 ? 1 : ($n <= 7 ? 2 : ($n <= 11 ? 3 : ($n <= 15 ? 4 : 5))),
|
|
'source_paragraph' => 21 + $n,
|
|
'branch' => $n === 10 ? 'land_needed' : (in_array($n, [13, 14, 15], true) ? 'external_funding' : null),
|
|
// Preparation has no dependencies. These only constrain the named consequential action.
|
|
'dependencies' => match ($n) {
|
|
7 => ['submit' => ['S06']],
|
|
15 => ['execute' => ['S14']],
|
|
18 => ['operate' => ['S17']],
|
|
default => [],
|
|
}];
|
|
}
|
|
|
|
return ['kind' => 'investor-path', 'version' => 1,
|
|
'source_sha256' => 'aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364',
|
|
'phases' => [1 => 'Ideia e viabilidade', 2 => 'Formalização e dossier', 3 => 'Licenciamento e terra', 4 => 'Financiamento', 5 => 'Execução e acompanhamento'],
|
|
'states' => self::STATES, 'steps' => $steps,
|
|
'legacy_roadmaps' => ['virtual-desk:E0-E11', 'investor-guidance:7-phases', 'investment-roadmap:14-activities']];
|
|
}
|
|
|
|
/** @param array<string,mixed> $definition */
|
|
public static function validate(array $definition): void
|
|
{
|
|
$steps = $definition['steps'] ?? [];
|
|
$expected = array_map(fn ($n) => sprintf('S%02d', $n), range(1, 19));
|
|
if (count($definition['phases'] ?? []) !== 5 || array_column($steps, 'code') !== $expected
|
|
|| array_column($steps, 'sequence') !== range(1, 19)) {
|
|
throw new \LogicException('The five phases and nineteen source stages must remain traceable.');
|
|
}
|
|
$edges = [];
|
|
foreach ($steps as $step) {
|
|
if (! in_array($step['phase'], range(1, 5), true)
|
|
|| ! in_array($step['branch'], [null, 'land_needed', 'external_funding'], true)) {
|
|
throw new \LogicException('Unknown phase or applicability field.');
|
|
}
|
|
$edges[$step['code']] = [];
|
|
foreach ($step['dependencies'] as $action => $dependencies) {
|
|
if (! in_array($action, ['submit', 'execute', 'operate'], true)
|
|
|| array_diff($dependencies, $expected)) {
|
|
throw new \LogicException('Unknown action/dependency; preparation cannot be blocked.');
|
|
}
|
|
$edges[$step['code']] = array_merge($edges[$step['code']], $dependencies);
|
|
}
|
|
}
|
|
$visit = function (string $code, array $trail) use (&$visit, $edges): void {
|
|
if (in_array($code, $trail, true)) {
|
|
throw new \LogicException('Cyclic action dependencies.');
|
|
}
|
|
foreach ($edges[$code] as $next) {
|
|
$visit($next, [...$trail, $code]);
|
|
}
|
|
};
|
|
foreach ($expected as $code) {
|
|
$visit($code, []);
|
|
}
|
|
}
|
|
}
|