feat(anaf-dedup): ANAF partner dedup + address fix + UI enrichment
Prevent partner duplicates via ANAF CUI verification and dual PL/SQL search. Fix address matching with street-level comparison and diacritics normalization. Show partner/address comparison in order detail modal. - New anaf_service.py: batch ANAF API client with chunking, retry, cache - PL/SQL: dual CUI search (bare/RO+bare/RO space+bare), 3-tier address search (street+city+id_loc → city+id_loc → create), strip_diacritics at storage for addresses and partner names - SQLite: anaf_cache table, 12 new order columns for partner/address data - import_service: cod_fiscal_override param, return partner/address from Oracle - sync_service: ANAF batch integration, denomination mismatch detection, cache pre-population trigger - Router: enriched order_detail with partner_info + addresses JSON - UI: collapsible Detalii Partener + Adrese Comparativ sections in modal, auto-expand on mismatch, ANAF badges, mobile address cards - Dashboard: address quality attention indicator - New scan_duplicate_partners.py script for one-time duplicate audit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ CREATE OR REPLACE PACKAGE PACK_IMPORT_PARTENERI AS
|
||||
|
||||
-- 20.03.2026 - import parteneri GoMag: PJ/PF, shipping/billing, cautare/creare automata
|
||||
-- 31.03.2026 - parser inteligent adrese: split numar in bloc/scara/apart/etaj (fix ORA-12899 pe NUMAR max 10 chars)
|
||||
-- 01.04.2026 - ANAF dedup: cautare duala CUI, adrese pe strada+diacritics, strip diacritics la stocare
|
||||
|
||||
-- ====================================================================
|
||||
-- CONSTANTS
|
||||
@@ -146,10 +147,25 @@ CREATE OR REPLACE PACKAGE PACK_IMPORT_PARTENERI AS
|
||||
*/
|
||||
PROCEDURE clear_error;
|
||||
|
||||
FUNCTION strip_diacritics(p_text IN VARCHAR2) RETURN VARCHAR2;
|
||||
|
||||
END PACK_IMPORT_PARTENERI;
|
||||
/
|
||||
CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS
|
||||
|
||||
-- 01.04.2026 - strip_diacritics la stocare adrese si parteneri
|
||||
FUNCTION strip_diacritics(p_text IN VARCHAR2) RETURN VARCHAR2 IS
|
||||
BEGIN
|
||||
IF p_text IS NULL THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
RETURN TRANSLATE(
|
||||
UPPER(TRIM(p_text)),
|
||||
'ĂăÂâÎîȘșȚțŞşŢţ',
|
||||
'AAAAIISSTTSSTT'
|
||||
);
|
||||
END strip_diacritics;
|
||||
|
||||
-- ================================================================
|
||||
-- ERROR MANAGEMENT FUNCTIONS IMPLEMENTATION
|
||||
-- ================================================================
|
||||
@@ -212,57 +228,52 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS
|
||||
-- PUBLIC FUNCTIONS IMPLEMENTATION
|
||||
-- ====================================================================
|
||||
|
||||
-- 01.04.2026 - cautare duala cod_fiscal cu/fara prefix RO (anti-duplicare parteneri)
|
||||
FUNCTION cauta_partener_dupa_cod_fiscal(p_cod_fiscal IN VARCHAR2)
|
||||
RETURN NUMBER IS
|
||||
v_id_part NUMBER;
|
||||
v_cod_fiscal_curat VARCHAR2(50);
|
||||
v_bare_cui VARCHAR2(50);
|
||||
v_ro_cui VARCHAR2(52);
|
||||
BEGIN
|
||||
-- Validare input
|
||||
IF p_cod_fiscal IS NULL OR
|
||||
LENGTH(TRIM(p_cod_fiscal)) < C_MIN_COD_FISCAL THEN
|
||||
IF p_cod_fiscal IS NULL OR LENGTH(TRIM(p_cod_fiscal)) < C_MIN_COD_FISCAL THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
v_cod_fiscal_curat := curata_text_cautare(p_cod_fiscal);
|
||||
|
||||
-- pINFO('Cautare partener dupa cod_fiscal: ' || v_cod_fiscal_curat, 'IMPORT_PARTENERI');
|
||||
|
||||
-- Cautare in NOM_PARTENERI
|
||||
|
||||
v_cod_fiscal_curat := UPPER(TRIM(p_cod_fiscal));
|
||||
|
||||
-- Extract bare CUI (without RO prefix)
|
||||
IF REGEXP_LIKE(v_cod_fiscal_curat, '^RO\s*\d') THEN
|
||||
v_bare_cui := TRIM(REGEXP_REPLACE(v_cod_fiscal_curat, '^RO\s*', ''));
|
||||
ELSE
|
||||
v_bare_cui := v_cod_fiscal_curat;
|
||||
END IF;
|
||||
v_ro_cui := 'RO' || v_bare_cui;
|
||||
|
||||
-- 01.04.2026 - cautare duala cod_fiscal cu/fara prefix RO (anti-duplicare parteneri)
|
||||
-- Search 3 forms: bare, RO+bare, RO+space+bare (index-friendly)
|
||||
-- Priority: active + exact form > active + alternate > inactive
|
||||
BEGIN
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
SELECT id_part INTO v_id_part FROM (
|
||||
SELECT id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(cod_fiscal)) = v_cod_fiscal_curat
|
||||
AND ROWNUM = 1; -- In caz de duplicate, luam primul
|
||||
|
||||
-- pINFO('Gasit partener cu cod_fiscal ' || v_cod_fiscal_curat || ': ID_PART=' || v_id_part, 'IMPORT_PARTENERI');
|
||||
WHERE UPPER(TRIM(cod_fiscal)) IN (v_bare_cui, v_ro_cui, 'RO ' || v_bare_cui)
|
||||
AND NVL(sters, 0) = 0
|
||||
ORDER BY NVL(inactiv, 0) ASC,
|
||||
CASE WHEN UPPER(TRIM(cod_fiscal)) = v_cod_fiscal_curat THEN 0 ELSE 1 END ASC,
|
||||
id_part DESC
|
||||
) WHERE ROWNUM = 1;
|
||||
|
||||
RETURN v_id_part;
|
||||
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
-- pINFO('Nu s-a gasit partener cu cod_fiscal: ' || v_cod_fiscal_curat, 'IMPORT_PARTENERI');
|
||||
RETURN NULL;
|
||||
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
-- Luam primul gasit
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
FROM (SELECT id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(cod_fiscal)) = v_cod_fiscal_curat
|
||||
ORDER BY id_part)
|
||||
WHERE ROWNUM = 1;
|
||||
|
||||
pINFO('WARNING: Multiple parteneri cu acelasi cod_fiscal ' ||
|
||||
v_cod_fiscal_curat || '. Selectat ID_PART=' || v_id_part,
|
||||
'IMPORT_PARTENERI');
|
||||
RETURN v_id_part;
|
||||
END;
|
||||
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
pINFO('ERROR in cauta_partener_dupa_cod_fiscal: ' || SQLERRM,
|
||||
'IMPORT_PARTENERI');
|
||||
pINFO('ERROR in cauta_partener_dupa_cod_fiscal: ' || SQLERRM, 'IMPORT_PARTENERI');
|
||||
RAISE;
|
||||
END cauta_partener_dupa_cod_fiscal;
|
||||
|
||||
@@ -677,6 +688,9 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS
|
||||
-- pINFO('Nume separat: NUME=' || NVL(v_nume, 'NULL') || ', PRENUME=' || NVL(v_prenume, 'NULL'), 'IMPORT_PARTENERI');
|
||||
END IF;
|
||||
|
||||
-- Strip diacritics from partner name before storage
|
||||
v_denumire_curata := strip_diacritics(v_denumire_curata);
|
||||
|
||||
-- Creare partener prin pack_def
|
||||
BEGIN
|
||||
IF v_este_persoana_fizica = 1 THEN
|
||||
@@ -797,30 +811,37 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS
|
||||
v_apart,
|
||||
v_etaj);
|
||||
|
||||
-- caut prima adresa dupa judet si localitate, ordonate dupa principala = 1
|
||||
-- 01.04.2026 - cautare adresa pe strada + diacritics + id_loc validation
|
||||
-- TIER 1: county + city + street (diacritics normalized) + valid id_loc
|
||||
begin
|
||||
select max(id_adresa) over(order by principala desc)
|
||||
into p_id_adresa
|
||||
from vadrese_parteneri
|
||||
where id_part = p_id_part
|
||||
and judet = v_judet
|
||||
and localitate = v_localitate;
|
||||
exception
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
p_id_adresa := null;
|
||||
end;
|
||||
|
||||
-- caut prima adresa dupa judet, ordonate dupa principala = 1
|
||||
if p_id_adresa is null then
|
||||
begin
|
||||
select max(id_adresa) over(order by principala desc)
|
||||
into p_id_adresa
|
||||
select id_adresa into p_id_adresa from (
|
||||
select id_adresa
|
||||
from vadrese_parteneri
|
||||
where id_part = p_id_part
|
||||
and judet = v_judet;
|
||||
and judet = v_judet
|
||||
and localitate = v_localitate
|
||||
and strip_diacritics(strada) = strip_diacritics(v_strada)
|
||||
and id_loc IS NOT NULL
|
||||
order by principala desc, id_adresa desc
|
||||
) where rownum = 1;
|
||||
exception
|
||||
when NO_DATA_FOUND then p_id_adresa := null;
|
||||
end;
|
||||
|
||||
-- TIER 2: county + city (no street) but ONLY with valid id_loc
|
||||
if p_id_adresa is null then
|
||||
begin
|
||||
select id_adresa into p_id_adresa from (
|
||||
select id_adresa
|
||||
from vadrese_parteneri
|
||||
where id_part = p_id_part
|
||||
and judet = v_judet
|
||||
and localitate = v_localitate
|
||||
and id_loc IS NOT NULL
|
||||
order by principala desc, id_adresa desc
|
||||
) where rownum = 1;
|
||||
exception
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
p_id_adresa := null;
|
||||
when NO_DATA_FOUND then p_id_adresa := null;
|
||||
end;
|
||||
end if;
|
||||
|
||||
@@ -870,6 +891,12 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS
|
||||
end;
|
||||
end;
|
||||
|
||||
-- 01.04.2026 - strip_diacritics la stocare adrese
|
||||
v_strada := strip_diacritics(v_strada);
|
||||
v_localitate := strip_diacritics(v_localitate);
|
||||
v_numar := strip_diacritics(v_numar);
|
||||
v_bloc := strip_diacritics(v_bloc);
|
||||
|
||||
BEGIN
|
||||
pack_def.adauga_adresa_partener2(tnId_part => p_id_part,
|
||||
tcDenumire_adresa => NULL,
|
||||
|
||||
Reference in New Issue
Block a user