Prepare supplied financial directory with product coverage and native dossier continuity
This commit is contained in:
@@ -18,7 +18,7 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
/** Informational funding catalogue, separate from applications, credit decisions and fiscal calculations. */
|
||||
final class FundingProgrammes
|
||||
{
|
||||
public const KINDS = ['fund' => 'Fundo', 'programme' => 'Programa de apoio', 'incentive' => 'Incentivo'];
|
||||
public const KINDS = ['institution' => 'Instituição financeira', 'fund' => 'Fundo', 'programme' => 'Programa de apoio', 'incentive' => 'Incentivo'];
|
||||
|
||||
public const WINDOWS = ['dated' => 'Datas documentadas', 'rolling' => 'Recepção contínua documentada', 'unknown' => 'Janela por confirmar', 'closed' => 'Encerrada segundo a fonte'];
|
||||
|
||||
@@ -56,6 +56,7 @@ final class FundingProgrammes
|
||||
public function catalogueQuery(array $filters): Builder
|
||||
{
|
||||
$query = $this->publicQuery();
|
||||
app(FundingInstitutionDetails::class)->applyFilters($query, $filters);
|
||||
$includeUnknown = ($filters['certainty'] ?? 'include_unknown') === 'include_unknown';
|
||||
if (! empty($filters['sector'])) {
|
||||
$query->where(function (Builder $scope) use ($filters, $includeUnknown): void {
|
||||
@@ -69,7 +70,7 @@ final class FundingProgrammes
|
||||
if (! empty($filters['territory'])) {
|
||||
$path = array_column(app(InvestmentGeography::class)->path($filters['territory']), 'id');
|
||||
$query->where(function (Builder $scope) use ($filters, $path, $includeUnknown): void {
|
||||
$scope->whereRaw("v.payload->>'coverage' = 'national'")
|
||||
$scope->whereRaw("v.payload->>'kind' = 'institution'")->orWhereRaw("v.payload->>'coverage' = 'national'")
|
||||
->orWhereJsonContains('v.payload->territory_ancestor_ids', $filters['territory']);
|
||||
foreach ($path as $id) {
|
||||
$scope->orWhereJsonContains('v.payload->territory_ids', $id);
|
||||
@@ -102,6 +103,11 @@ final class FundingProgrammes
|
||||
public function filterExplanation(array $record, array $filters): array
|
||||
{
|
||||
$payload = $record['payload'];
|
||||
if ($payload['kind'] === 'institution') {
|
||||
$products = array_values(array_filter($payload['products'] ?? [], fn ($p) => app(FundingInstitutionDetails::class)->match($p, $filters)));
|
||||
|
||||
return ['institution' => $products === [] ? 'Instituição identificada; produtos, cobertura e disponibilidade por confirmar. Não é uma correspondência confirmada.' : 'Consulte os produtos correspondentes e as condições por confirmar. Sede e balcões não determinam a cobertura do financiamento.'];
|
||||
}
|
||||
$result = [];
|
||||
if (! empty($filters['sector'])) {
|
||||
$result['sector'] = $payload['sectors_scope'] === 'unknown'
|
||||
@@ -200,6 +206,13 @@ final class FundingProgrammes
|
||||
if (! $row && DB::table('funding_programmes')->where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages(['code' => 'Este identificador já pertence a uma ficha. Abra-a para actualizar ou acrescentar uma janela.']);
|
||||
}
|
||||
if ($draft['kind'] === 'institution') {
|
||||
DB::select('select pg_advisory_xact_lock(261102, hashtext(?))', ['institution:'.$draft['institution_key']]);
|
||||
$duplicate = DB::table('funding_programmes')->whereRaw("draft->>'kind' = 'institution'")->whereRaw("draft->>'institution_key' = ?", [$draft['institution_key']])->when($id, fn ($q) => $q->where('id', '<>', $id))->exists();
|
||||
if ($duplicate) {
|
||||
throw ValidationException::withMessages(['institution_key' => 'A instituição já tem ficha. Reutilize a identidade existente; não substitua as suas edições.']);
|
||||
}
|
||||
}
|
||||
$id ??= (string) Str::uuid();
|
||||
DB::table('funding_programmes')->updateOrInsert(['id' => $id], ['code' => $data['code'], 'version' => (int) $data['version'] + 1,
|
||||
'draft' => json_encode($draft, JSON_THROW_ON_ERROR), 'created_by' => $row->created_by ?? $actor->id,
|
||||
@@ -225,6 +238,7 @@ final class FundingProgrammes
|
||||
'sectors_scope' => 'required|in:all,selected,unknown', 'sectors_text' => 'nullable|string|max:2000', 'sector_ids' => 'array|max:40',
|
||||
'sector_ids.*' => ['required', 'integer', 'distinct', Rule::in(Sector::choices()->whereNotNull('published_at')->pluck('id')->all())],
|
||||
'resource_ids' => 'array|max:30', 'resource_ids.*' => 'required|integer|distinct|exists:portal_resources,id',
|
||||
'funding_needs' => 'array|max:6', 'funding_needs.*' => ['required', 'distinct', Rule::in(array_keys(FundingInstitutionDetails::NEEDS))],
|
||||
'criteria' => 'array|max:30', 'windows' => 'array|max:20',
|
||||
'windows.*' => 'required|array:code,title,mode,start_on,end_on,coverage,coverage_text,territory_ids,source_url,source_reference,checked_on,application_url,criteria',
|
||||
'windows.*.code' => 'required|string|regex:/^[a-z0-9][a-z0-9-]{0,79}$/D|distinct', 'windows.*.title' => "$required|string|max:250",
|
||||
@@ -244,6 +258,9 @@ final class FundingProgrammes
|
||||
$rules[$prefix.'.*.explanation'] = "$required|string|max:2000";
|
||||
}
|
||||
$data = Validator::make($input, $rules)->validate();
|
||||
if ($data['kind'] === 'institution') {
|
||||
$data = [...$data, ...app(FundingInstitutionDetails::class)->normalize($input, $publishing)];
|
||||
}
|
||||
$data = [...$data, 'territory_ids' => $data['territory_ids'] ?? [], 'sector_ids' => $data['sector_ids'] ?? [], 'resource_ids' => $data['resource_ids'] ?? [],
|
||||
'criteria' => $data['criteria'] ?? [], 'windows' => $data['windows'] ?? []];
|
||||
if ($data['coverage'] !== 'territorial' && $data['territory_ids'] !== []) {
|
||||
|
||||
Reference in New Issue
Block a user