93 lines
4.2 KiB
PHP
93 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Opportunity;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
/** Catalogue versions are not interchangeable: historical positions keep their meaning. */
|
|
final class OpportunityMaturity
|
|
{
|
|
public const VERSION = 'spec-v2';
|
|
|
|
public const LEGACY = 'legacy-v1';
|
|
|
|
public const STAGES = [
|
|
'idea' => 'Ideia',
|
|
'concept' => 'Conceito',
|
|
'prefeasibility' => 'Pré-viabilidade',
|
|
'feasibility' => 'Viabilidade',
|
|
'structured' => 'Estruturado',
|
|
'investment_ready' => 'Pronto para investimento',
|
|
'implementation' => 'Implementação',
|
|
'operational' => 'Operacional',
|
|
];
|
|
|
|
public const LEGACY_LABELS = [1 => 'Ideia identificada', 'Pré-estudo disponível', 'Estudo de viabilidade em curso', 'Projecto estruturado', 'Pronto para investimento', 'Em negociação ou implementação'];
|
|
|
|
/** Public selection is explicit; historical numbers never stand for current stages.
|
|
* @return array<array-key, mixed>
|
|
*/
|
|
public static function searchOptions(): array
|
|
{
|
|
$options = [];
|
|
foreach (self::STAGES as $code => $label) {
|
|
$options[] = ['value' => 'stage:'.$code, 'label' => $label, 'group' => 'Etapas de preparação'];
|
|
}
|
|
foreach (self::LEGACY_LABELS as $level => $label) {
|
|
$options[] = ['value' => 'historical:'.$level, 'label' => $label.' — registo histórico', 'group' => 'Classificações históricas'];
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* @param Builder<Opportunity> $query
|
|
*/
|
|
public static function constrainSearch(Builder $query, string $selection): void
|
|
{
|
|
[$kind, $value] = explode(':', $selection, 2);
|
|
if ($kind === 'stage') {
|
|
$query->where('workflow_context->publication->maturity->catalogue_version', self::VERSION)
|
|
->where('workflow_context->publication->maturity->stage', $value);
|
|
} else {
|
|
$query->where(fn ($q) => $q->where('workflow_context->publication->maturity->catalogue_version', self::LEGACY)
|
|
->orWhere(fn ($old) => $old->whereNull('workflow_context->publication->maturity->catalogue_version')->whereNull('workflow_context->publication->maturity->stage')))
|
|
->where('maturity_level', (int) $value);
|
|
}
|
|
}
|
|
|
|
/** @param array<string,mixed> $data
|
|
* @return array<string,mixed> */
|
|
public function normalize(array $data): array
|
|
{
|
|
if (! array_key_exists('maturity_level', $data) && ! array_key_exists('maturity_stage', $data)) {
|
|
if (isset($data['maturity_catalogue_version'])) {
|
|
throw ValidationException::withMessages(['maturity_catalogue_version' => 'Seleccione também a etapa; mudar só a versão não converte o valor histórico.']);
|
|
}
|
|
unset($data['maturity_catalogue_version']);
|
|
|
|
return $data;
|
|
}
|
|
$level = isset($data['maturity_level']) ? (int) $data['maturity_level'] : null;
|
|
$version = $data['maturity_catalogue_version'] ?? ((isset($data['maturity_stage']) || ($level ?? 0) > 6) ? self::VERSION : self::LEGACY);
|
|
if ($version === self::LEGACY) {
|
|
if (($level ?? 0) > 6 || isset($data['maturity_stage'])) {
|
|
throw ValidationException::withMessages(['maturity_level' => 'O catálogo histórico tem seis níveis; seleccione explicitamente o catálogo de oito etapas.']);
|
|
}
|
|
|
|
return [...$data, 'maturity_catalogue_version' => self::LEGACY, 'maturity_stage' => null, 'maturity_label' => self::LEGACY_LABELS[$level ?? 0] ?? null];
|
|
}
|
|
$codes = array_keys(self::STAGES);
|
|
$stage = $data['maturity_stage'] ?? ($level !== null ? $codes[$level - 1] : null);
|
|
if ($stage !== null && $level !== null && $codes[$level - 1] !== $stage) {
|
|
throw ValidationException::withMessages(['maturity_stage' => 'O código da etapa e a posição no catálogo não correspondem.']);
|
|
}
|
|
|
|
return [...$data, 'maturity_catalogue_version' => self::VERSION, 'maturity_stage' => $stage,
|
|
'maturity_level' => $stage !== null ? array_search($stage, $codes, true) + 1 : null,
|
|
'maturity_label' => $stage !== null ? self::STAGES[$stage] : null];
|
|
}
|
|
}
|