a6c03a091e
Moved from gov-agreg/src/pages/achizitii/* to root (drop prefix). - 22 pages migrated, 127 files total - All internal links: /achizitii/X → /X (176 occurrences fixed) - AchizitiiLayout subnav rewritten: /X paths, top-right link to vreaudigital.ro hub - BaseLayout new (vreau.digital branding, OG tags, site URL) - astro.config.mjs: site https://vreau.digital, server output (was static) - docker-compose: port 5096 (vreaudigital is 5095), container vreau-digital - deploy.sh: paths /opt/vreau-digital, log /var/log/vreau-digital-deploy.log Backend shared with gov-agreg: - PostgreSQL satra (same schemas: seap, firms, anaf, anre, ...) - Photon, Martin tiles - Infisical /vreaudigital path (DATABASE_URL etc. shared) build: PASS (npx astro check 0 errors, npm run build 5s vite + 10s server)
124 lines
7.3 KiB
SQL
124 lines
7.3 KiB
SQL
-- 034_asf.sql
|
||
-- ASF — Autoritatea de Supraveghere Financiară.
|
||
-- Public registries of authorized financial entities (insurers, brokers, pension
|
||
-- funds, asset managers, intermediaries) scraped from data.asfromania.ro.
|
||
--
|
||
-- Sources (all return JSON{raspuns:HTML, status:100} via POST cautare):
|
||
-- 1. /scr/ra/cautare?l=ro (Registrul asigurătorilor + intermediarilor)
|
||
-- sectiune=1 tipCompanie=0 → Societăți de asigurare - companii active
|
||
-- sectiune=2 tipCompanie=0 → Societăți de asigurare - companii radiate
|
||
-- sectiune=1 tipCompanie=1 → Intermediari principali - companii active
|
||
-- sectiune=2 tipCompanie=1 → Intermediari principali - companii radiate
|
||
-- Fields per panel: register_no (RA-XXX/RBK-XXX), LEI, CUI, RC code,
|
||
-- authorization no/date, registration date, radiation date, type, legal form,
|
||
-- address, phone, fax, observations, authorized classes (general/life),
|
||
-- executives. Total: ~768 insurers + ~801 brokers ≈ 1.5K entities.
|
||
--
|
||
-- 2. /scr/ra/cautare endpoint accepts free-text 'termen' (≥4 chars). Search
|
||
-- hits denumire, CUI, adresă, județ, classes. NO captcha required when
|
||
-- 'g-recaptcha-response' field is OMITTED from the POST body. (When sent
|
||
-- with any non-empty value the server tries to verify and returns
|
||
-- "Verificare captcha eșuată".)
|
||
--
|
||
-- 3. Pension funds + AIFM/UCITS register pages exist on asfromania.ro/ro/a/...
|
||
-- but most are F5-WAF-protected from non-browser clients. We start with the
|
||
-- ra portal which has cleanest data; document handoff for additional
|
||
-- registers in ASF-PLAN.md.
|
||
--
|
||
-- Cross-source value: asf.entitati.cui (extracted directly from response, no
|
||
-- fuzzy match needed) × seap.announcements.supplier_cui = "ASF-licensed firms
|
||
-- with state contracts". Red-flag: insurance firm wins SEAP contract for state
|
||
-- insurance services but has been radiated by ASF; broker active in SEAP but
|
||
-- with suspended/withdrawn ASF authorization.
|
||
|
||
CREATE SCHEMA IF NOT EXISTS asf;
|
||
|
||
-- ── 1. Authorized entities (insurers, brokers, pension funds, AIFM, UCITS) ──
|
||
-- One row per distinct ASF register entry. Every entity has a register_no
|
||
-- (RA-NNN for insurers, RBK-NNN for brokers, etc.) which is globally unique
|
||
-- per register_type.
|
||
CREATE TABLE IF NOT EXISTS asf.entitati (
|
||
id bigserial PRIMARY KEY,
|
||
register_type text NOT NULL, -- 'asigurator' | 'broker' | 'fond_pensii' | 'aifm' | 'ucits' | 'intermediar_secundar'
|
||
section_status text NOT NULL, -- 'activ' | 'radiat' (mirrors source sectiune=1/2 split)
|
||
register_no text NOT NULL, -- e.g. "RA-057", "RBK-123" (unique within register_type)
|
||
name text NOT NULL, -- raw "Denumire"
|
||
name_normalized text, -- firms.normalize_company_name(name) — for trigram fallback
|
||
cui text, -- "Cod unic de identificare (CUI)"
|
||
cod_rc text, -- "Cod unic RC" (e.g. J40/2226/2006)
|
||
cod_lei text, -- LEI 20-char
|
||
nr_autorizatie text, -- "Număr autorizație" (e.g. 114.146)
|
||
data_autorizare date, -- "Dată autorizare"
|
||
data_inmatriculare date, -- "Dată înmatriculare"
|
||
data_radiere date, -- "Dată radiere" (NULL when active)
|
||
tip_companie text, -- "Tip companie" (Societate de asigurare / Intermediar principal / etc.)
|
||
forma_juridica text, -- "Formă juridică"
|
||
adresa text, -- "Adresă"
|
||
telefon text,
|
||
fax text,
|
||
email text,
|
||
web text,
|
||
observatii text, -- free-text remarks
|
||
clase_autorizate jsonb, -- {"asigurari_generale":[...], "asigurari_viata":[...]}
|
||
conducere jsonb, -- [{"nume":"X","functie":"Y","din":"DD.MM.YYYY"}]
|
||
raw_html text, -- raw panel HTML for traceability
|
||
fetched_at timestamptz NOT NULL DEFAULT now(),
|
||
UNIQUE (register_type, register_no)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_cui ON asf.entitati(cui) WHERE cui IS NOT NULL;
|
||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_name_norm_trgm ON asf.entitati USING gin (name_normalized gin_trgm_ops);
|
||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_type_status ON asf.entitati(register_type, section_status);
|
||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_radiere ON asf.entitati(data_radiere) WHERE data_radiere IS NOT NULL;
|
||
|
||
COMMENT ON TABLE asf.entitati IS
|
||
'ASF authorized entities — insurers, brokers, pension funds, AIFM/UCITS, intermediaries. Source: data.asfromania.ro/scr/ra (and other registers).';
|
||
COMMENT ON COLUMN asf.entitati.register_type IS
|
||
'asigurator (RA-NNN) / broker (RBK-NNN) / fond_pensii / aifm / ucits / intermediar_secundar';
|
||
COMMENT ON COLUMN asf.entitati.section_status IS
|
||
'activ / radiat — mirrors source sectiune=1/sectiune=2 split. Active record has data_radiere=NULL.';
|
||
|
||
-- ── 2. Scrape log (mirrors anre.scrape_log convention) ──────────────────────
|
||
CREATE TABLE IF NOT EXISTS asf.scrape_log (
|
||
id bigserial PRIMARY KEY,
|
||
scraper text NOT NULL, -- 'asigurator_activ' / 'asigurator_radiat' / 'broker_activ' / ...
|
||
source_url text NOT NULL,
|
||
rows_seen integer NOT NULL DEFAULT 0,
|
||
rows_inserted integer NOT NULL DEFAULT 0,
|
||
rows_updated integer NOT NULL DEFAULT 0,
|
||
rows_skipped integer NOT NULL DEFAULT 0,
|
||
duration_ms integer NOT NULL DEFAULT 0,
|
||
started_at timestamptz NOT NULL,
|
||
finished_at timestamptz NOT NULL DEFAULT now(),
|
||
error text
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_asf_scrape_log_started ON asf.scrape_log(started_at DESC);
|
||
|
||
-- ── 3. Materialized view: per-CUI ASF rollup ────────────────────────────────
|
||
-- Joinable with seap.announcements.supplier_cui to detect financial firms
|
||
-- holding state contracts.
|
||
CREATE MATERIALIZED VIEW IF NOT EXISTS asf.mv_entitati_per_cui AS
|
||
SELECT
|
||
cui,
|
||
COUNT(*) AS nr_total,
|
||
COUNT(*) FILTER (WHERE register_type = 'asigurator') AS nr_asigurator,
|
||
COUNT(*) FILTER (WHERE register_type = 'broker') AS nr_broker,
|
||
COUNT(*) FILTER (WHERE register_type = 'fond_pensii') AS nr_fond_pensii,
|
||
COUNT(*) FILTER (WHERE register_type = 'aifm') AS nr_aifm,
|
||
COUNT(*) FILTER (WHERE register_type = 'ucits') AS nr_ucits,
|
||
COUNT(*) FILTER (WHERE section_status = 'activ') AS nr_active,
|
||
COUNT(*) FILTER (WHERE section_status = 'radiat') AS nr_radiate,
|
||
array_agg(DISTINCT register_type) AS register_types,
|
||
array_agg(DISTINCT register_no ORDER BY register_no) AS register_numbers,
|
||
MIN(data_autorizare) AS prima_autorizare,
|
||
MAX(data_radiere) AS ultima_radiere
|
||
FROM asf.entitati
|
||
WHERE cui IS NOT NULL
|
||
GROUP BY cui;
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_asf_mv_entitati_per_cui ON asf.mv_entitati_per_cui(cui);
|
||
|
||
COMMENT ON MATERIALIZED VIEW asf.mv_entitati_per_cui IS
|
||
'Rollup of ASF entities per CUI. Refresh: REFRESH MATERIALIZED VIEW CONCURRENTLY asf.mv_entitati_per_cui';
|