Files
Investidor-V2/app/Services/FundingInstitutionClassification.php

74 lines
4.9 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
/** Documentary classification and physical presence; neither is lending eligibility. */
final class FundingInstitutionClassification
{
public const CATEGORIES = ['banking' => 'Banca', 'credit' => 'Crédito e microfinanças', 'investment' => 'Gestão de investimento', 'pensions' => 'Fundos de pensões', 'insurance' => 'Seguros e resseguros', 'intermediation' => 'Mediação de seguros', 'exchange' => 'Câmbio', 'payments' => 'Pagamentos e serviços interbancários', 'supervision' => 'Supervisão', 'other' => 'Outras instituições'];
public const TYPES = ['commercial_bank' => 'Banco comercial', 'investment_bank' => 'Banco de investimento', 'bank' => 'Banco (tipo não especificado)', 'microbank' => 'Microbanco', 'cooperative' => 'Cooperativa de crédito', 'savings' => 'Organização de poupança e empréstimo', 'investment_manager' => 'Gestora de fundos de investimento', 'investment_company' => 'Sociedade de investimento', 'pension_manager' => 'Gestora de fundos de pensões', 'insurer' => 'Seguradora', 'reinsurer' => 'Resseguradora', 'microinsurer' => 'Micro-seguradora', 'broker' => 'Corretora de seguros', 'agent' => 'Agente de seguros', 'reinsurance_broker' => 'Corretor de resseguro', 'exchange_house' => 'Casa de câmbio', 'electronic_money' => 'Instituição de moeda electrónica', 'interbank' => 'Serviços interbancários', 'supervisor' => 'Supervisor', 'other' => 'Outro tipo documentado'];
/** @param array<string,mixed> $input
* @return array<string,mixed> */
public function normalize(array $input): array
{
return Validator::make($input, [
'institution_categories' => 'array|max:10', 'institution_categories.*' => ['required', 'distinct', Rule::in(array_keys(self::CATEGORIES))],
'institution_types' => 'array|max:10', 'institution_types.*' => ['required', 'distinct', Rule::in(array_keys(self::TYPES))],
'institution_services' => 'array|max:12', 'institution_services.*' => ['required', 'distinct', Rule::in(array_keys(FundingInstitutionDetails::NEEDS))],
'institution_status' => 'nullable|in:reported,historical,merged,unknown', 'successor_key' => 'nullable|string|max:100',
'register_reference' => 'nullable|string|max:2000', 'aliases' => 'array|max:100', 'aliases.*' => 'required|string|max:500',
'source_rows' => 'array|max:250', 'source_rows.*' => 'required|array:id,section,text', 'source_rows.*.id' => 'required|string|max:100',
'source_rows.*.section' => 'required|string|max:250', 'source_rows.*.text' => 'required|string|max:8000',
])->validate();
}
/** @param array<string,mixed> $filters */
public function filter(Builder $query, array $filters): void
{
foreach (['category' => 'institution_categories', 'institution_type' => 'institution_types'] as $key => $field) {
if (! empty($filters[$key])) {
$query->whereRaw('v.payload->? @> ?::jsonb', [$field, json_encode([$filters[$key]], JSON_THROW_ON_ERROR)]);
}
}
if (empty($filters['include_historical'])) {
$query->whereRaw("COALESCE(v.payload->>'institution_status','reported') NOT IN ('historical','merged')");
}
if (($filters['location_mode'] ?? 'coverage') !== 'physical') {
return;
}
$query->whereRaw("v.payload->>'kind'='institution'");
if (empty($filters['territory'])) {
return;
}
$unknown = ($filters['certainty'] ?? 'include_unknown') === 'include_unknown';
$path = array_column(app(InvestmentGeography::class)->path($filters['territory']), 'id');
$clauses = ["l->'territory_path' @> ?::jsonb"];
$bindings = [json_encode([['id' => $filters['territory']]], JSON_THROW_ON_ERROR)];
if ($unknown) {
foreach ($path as $id) {
$clauses[] = "l->>'territory_id' = ?";
$bindings[] = $id;
}
}
$status = $unknown ? '' : " AND COALESCE(l->>'evidence_status','reported') NOT IN ('to_confirm','historical','conflict','unlocated')";
$query->where(function (Builder $q) use ($clauses, $bindings, $status, $unknown): void {
$q->whereRaw("EXISTS (SELECT 1 FROM jsonb_array_elements(COALESCE(v.payload->'locations','[]'::jsonb)) l WHERE (".implode(' OR ', $clauses).')'.$status.')', $bindings);
if ($unknown) {
$q->orWhereRaw("NOT EXISTS (SELECT 1 FROM jsonb_array_elements(COALESCE(v.payload->'locations','[]'::jsonb)) l WHERE NULLIF(l->>'territory_id','') IS NOT NULL)");
}
});
}
/** @param array<string,mixed> $payload */
public function permitsUnknownProduct(array $payload, ?string $need): bool
{
return ! $need || ! isset($payload['institution_services']) || in_array($need, $payload['institution_services'], true);
}
}