This commit is contained in:
2026-08-23 20:31:07 +03:00
parent a580dfd6e1
commit a833cf639f
7 changed files with 618 additions and 61 deletions

View File

@@ -2577,4 +2577,239 @@ Procedure NOM_cursuri_NOU
Do Adauga_Modifica_Inregistrare With "curscal", loRec, , "INSERT", , "addnomcurs"
Endproc
**************************************************************************************************************************
**************************************************************************************************************************
*!* 23.08.2026
*!* marius.mutu
*!* AnafNomenclator - potriveste denumirile de judet/localitate primite de la ANAF peste
*!* nomenclator, pentru completarea automata a datelor firmei si a partenerilor.
Define Class AnafNomenclator As Custom
*** Rezultatul ultimei departajari (vezi metoda departajeaza): cate randuri au ramas si
*** id-ul ultimului. Proprietati, nu parametri prin referinta, ca sa se poata apela din
*** doua locuri din pozitioneaza fara sa se duplice bucla.
nDeparte = 0
uIdDeparte = 0
*** Lasa cursorul pe judetul cerut si intoarce .T.; la esec cursorul ramane nemiscat.
Procedure pozitioneaza_judet
Lparameters tcCursor, tcJudet
Return This.pozitioneaza(m.tcCursor, [judet], [id_judet], m.tcJudet)
Endproc
Procedure pozitioneaza_localitate
Lparameters tcCursor, tcLocalitate
Return This.pozitioneaza(m.tcCursor, [localitate], [id_loc], m.tcLocalitate)
Endproc
*** tcCamp: campul cu denumirea; tcCampId: cheia de rand, folosita la repozitionare
*** (nu se face GO pe un Recno capturat in SCAN).
Procedure pozitioneaza
Lparameters tcCursor, tcCamp, tcCampId, tcValoare
Local lcCautat, lcCheie, lcSufix, lnGasite, lnSelect, luId, llOk
If Type('tcValoare') # 'C' Or !Used(m.tcCursor)
Return .F.
Endif
lcCautat = This.nume_curat(m.tcValoare)
If Empty(m.lcCautat)
Return .F.
Endif
llOk = .F.
lnSelect = Select()
Select (m.tcCursor)
*** Treapta 1: denumirea din nomenclator, exact asa cum e scrisa.
Locate For Upper(Alltrim(Nvl(Evaluate(m.tcCamp), []))) == m.lcCautat
If Found()
Return .T.
Endif
*** Treapta 2: fara sufixul dintre paranteze - nomenclatorul tine
*** "AGHIRESU-FABRICI (COM. AGHIRESU)", ANAF trimite doar numele satului.
lnGasite = 0
Scan
If This.nume_curat(Evaluate(m.tcCamp)) == m.lcCautat
lnGasite = m.lnGasite + 1
luId = Evaluate(m.tcCampId)
Endif
Endscan
*** Treapta 2b: mai multe localitati omonime in acelasi judet - se departajeaza dupa
*** comuna/orasul de care apartin, pe care ANAF il trimite si el:
*** ANAF: "GRECI COM. SCHITU"
*** nomenclator: "GRECI (COM. SCHITU)" si "GRECI (COM. OSICA DE SUS)"
*** Cand ANAF NU trimite comuna (ex. "STEFANESTI" in Arges, unde nomenclatorul are si
*** "(COM. SUSENI)", si "(ORAS STEFANESTI)"), cazul ramane ambiguu si se refuza - corect:
*** nomenclatorul insusi marcheaza situatia prin nr_loc > 1.
lcSufix = This.cheie_sufix(m.tcValoare)
If m.lnGasite > 1 And !Empty(m.lcSufix)
This.departajeaza(m.tcCamp, m.tcCampId, m.lcCautat, m.lcSufix, .F.)
If This.nDeparte = 1
lnGasite = 1
luId = This.uIdDeparte
Endif
Endif
*** Treapta 3: cheie cu A si I unificate - aceeasi localitate apare in nomenclator
*** si ca TIRGU MURES, si ca TARGU MURES.
If m.lnGasite = 0
lcCheie = This.cheie_fuzzy(m.tcValoare)
Scan
If This.cheie_fuzzy(Evaluate(m.tcCamp)) == m.lcCheie
lnGasite = m.lnGasite + 1
luId = Evaluate(m.tcCampId)
Endif
Endscan
*** Treapta 3b: departajarea dupa comuna se aplica SI aici, nu doar dupa treapta 2 -
*** altfel omonimele care difera de ANAF si prin A/I raman refuzate degeaba.
*** Caz real: ANAF "SARBI COM. FARCASA", nomenclatorul "SIRBI (COM. BUDESTI)" si
*** "SIRBI (COM. FARCASA)" - treapta 2 nu gaseste nimic, treapta 3 gaseste doi.
If m.lnGasite > 1 And !Empty(m.lcSufix)
This.departajeaza(m.tcCamp, m.tcCampId, m.lcCheie, m.lcSufix, .T.)
If This.nDeparte = 1
lnGasite = 1
luId = This.uIdDeparte
Endif
Endif
Endif
If m.lnGasite = 1
Locate For Nvl(Evaluate(m.tcCampId), -1) = Nvl(m.luId, -1)
llOk = Found()
Endif
If !m.llOk
Select (m.lnSelect)
Endif
Return m.llOk
Endproc
*** Numara randurile care au ACEEASI denumire (dupa regula treptei curente) SI aceeasi
*** comuna/oras ca valoarea cautata. Rezultatul in This.nDeparte / This.uIdDeparte.
*** tlFuzzy: .T. daca denumirile se compara pe cheia cu A si I unificate (treapta 3).
*** Cursorul trebuie sa fie deja selectat de apelant.
Procedure departajeaza
Lparameters tcCamp, tcCampId, tcCautat, tcSufix, tlFuzzy
Local lcNume
This.nDeparte = 0
This.uIdDeparte = 0
Scan
lcNume = Iif(m.tlFuzzy, This.cheie_fuzzy(Evaluate(m.tcCamp)), This.nume_curat(Evaluate(m.tcCamp)))
If m.lcNume == m.tcCautat And This.cheie_sufix(Evaluate(m.tcCamp)) == m.tcSufix
This.nDeparte = This.nDeparte + 1
This.uIdDeparte = Evaluate(m.tcCampId)
Endif
Endscan
Endproc
*** "AGHIRESU-FABRICI (COM. AGHIRESU)" -> "AGHIRESU-FABRICI"
*** Acelasi sufix apare in doua forme si trebuie taiat in amandoua, ca sa se poata compara
*** cele doua surse intre ele:
*** nomenclator: "AGIGEA (COM. AGIGEA)" - cu paranteze
*** ANAF: "AGIGEA COM. AGIGEA" - fara paranteze (adresa vine intr-un singur element
*** de virgula: "JUD. CONSTANTA, SAT AGIGEA COM. AGIGEA, STR. ECLUZEI, NR.1")
*** 23.08.2026: pana aici se taia doar forma cu paranteze, deci satele nu se potriveau deloc.
*** Masurat pe 200 de coduri fiscale reale: 26 din cele 100 de esecuri veneau de aici.
Procedure nume_curat
Lparameters tcNume
Local lcNume, lnPoz
lcNume = Upper(Alltrim(Nvl(m.tcNume, [])))
lnPoz = At([(], m.lcNume)
If m.lnPoz > 1
lcNume = Alltrim(Left(m.lcNume, m.lnPoz - 1))
Endif
lnPoz = This.poz_marcaj(m.lcNume)
If m.lnPoz > 1
lcNume = Alltrim(Left(m.lcNume, m.lnPoz - 1))
Endif
Return m.lcNume
Endproc
*** Pozitia primului marcaj administrativ INTERIOR (0 daca nu exista). Marcajele au punct,
*** deci o denumire reala de localitate nu le poate contine si taierea nu mananca din nume.
*** Pozitia 1 nu se ia in seama: nu vrem sa ramanem cu sirul gol.
Procedure poz_marcaj
Lparameters tcNume
Local lnPoz
lnPoz = 0
lnPoz = This.prima_poz(m.lnPoz, At([ COM.], m.tcNume))
lnPoz = This.prima_poz(m.lnPoz, At([ ORS.], m.tcNume))
lnPoz = This.prima_poz(m.lnPoz, At([ MUN.], m.tcNume))
lnPoz = This.prima_poz(m.lnPoz, At([ SAT.], m.tcNume))
lnPoz = This.prima_poz(m.lnPoz, At([ JUD.], m.tcNume))
Return m.lnPoz
Endproc
*** Cea mai din stanga pozitie valida (> 1) dintre cele doua; 0 daca niciuna.
Procedure prima_poz
Lparameters tnPoz, tnCandidat
If m.tnCandidat > 1 And (m.tnPoz = 0 Or m.tnCandidat < m.tnPoz)
Return m.tnCandidat
Endif
Return m.tnPoz
Endproc
*** Cheie de comparare toleranta: fara sufix administrativ, fara separatoare, cu A si I unificate.
Procedure cheie_fuzzy
Lparameters tcNume
Return This.cheie_bruta(This.nume_curat(m.tcNume))
Endproc
*** Normalizare fara taierea sufixului - se aplica pe orice bucata de text.
Procedure cheie_bruta
Lparameters tcText
Local lcCheie
lcCheie = Upper(Alltrim(Nvl(m.tcText, [])))
lcCheie = Chrtran(m.lcCheie, [ -.], [])
lcCheie = Chrtran(m.lcCheie, [AI], [@@])
Return m.lcCheie
Endproc
*** Cheia comunei/orasului de care apartine localitatea, din oricare din cele doua forme:
*** "GRECI (COM. SCHITU)" (nomenclator) -> SCHITU
*** "GRECI COM. SCHITU" (ANAF) -> SCHITU
*** Cuvantul administrativ se scoate pentru ca sursele il scriu diferit: nomenclatorul are
*** si "(ORAS X)", ANAF trimite "ORS. X". Sir gol daca denumirea nu are sufix.
Procedure cheie_sufix
Lparameters tcNume
Local lcNume, lcSufix, lnPoz
lcNume = Upper(Alltrim(Nvl(m.tcNume, [])))
lcSufix = []
lnPoz = At([(], m.lcNume)
If m.lnPoz > 1
lcSufix = Alltrim(Strtran(Substr(m.lcNume, m.lnPoz + 1), [)], []))
Else
lnPoz = This.poz_marcaj(m.lcNume)
If m.lnPoz > 1
lcSufix = Alltrim(Substr(m.lcNume, m.lnPoz))
Endif
Endif
Return This.cheie_bruta(This.fara_marcaj(m.lcSufix))
Endproc
*** Scoate cuvantul administrativ de la inceputul unui SUFIX: "COM. SCHITU" -> "SCHITU".
*** Aici formele intregi (COMUNA/ORASUL/SATUL) sunt sigure, spre deosebire de
*** VerificareANAF.FaraPrefixLoc: acolo textul poate fi chiar o denumire de localitate
*** (ORASUL NOU), aici e intotdeauna un sufix administrativ.
Procedure fara_marcaj
Lparameters tcSufix
Local lcT, lcPrim, lnPoz
lcT = Upper(Alltrim(Nvl(m.tcSufix, [])))
If Empty(m.lcT)
Return m.lcT
Endif
lcPrim = Getwordnum(m.lcT, 1, [ ])
lnPoz = At([.], m.lcPrim)
Do Case
Case m.lnPoz > 0
lcT = Alltrim(Substr(m.lcT, At([.], m.lcT) + 1))
Case Inlist(m.lcPrim, [SAT], [COM], [ORS], [MUN], [JUD], [ORAS], ;
[COMUNA], [SATUL], [ORASUL], [MUNICIPIUL], [JUDETUL])
lcT = Alltrim(Substr(m.lcT, Len(m.lcPrim) + 1))
Endcase
Return m.lcT
Endproc
Enddefine

View File

@@ -2710,13 +2710,13 @@ Define Class VerificareANAF As Custom
Do Case
Case m.lnItem = 1 && 'JUD.'$UPPER(lcItem)
*!* lcJudet = ALLTRIM(STRTRAN(m.lcItem, 'JUD.', '',1,1,1))
loAdresa.judet = Getwordnum(m.lcItem, 2, ' ') && CONSTANTA
loAdresa.judet = This.FaraPrefixLoc(m.lcItem) && SATU MARE
Case m.lnItem = 2 && 'MUN.'$UPPER(lcItem)
*!* lcLocalitate = ALLTRIM(STRTRAN(m.lcItem, 'MUN.', '',1,1,1))
IF LEFT(m.lcItem, 7) = "SECTOR "
loAdresa.localitate = STRTRAN(m.lcItem, "SECTOR ", "BUCURESTI SECTORUL ")
ELSE
loAdresa.localitate = Getwordnum(m.lcItem, 2, ' ') && CONSTANTA
loAdresa.localitate = This.FaraPrefixLoc(m.lcItem) && TIRGU NEAMT
ENDIF
Case m.lnItem = 3
lcPrefix = Getwordnum(m.lcItem, 1, ' ') && STR. / BD.
@@ -2748,6 +2748,30 @@ Define Class VerificareANAF As Custom
Return loAdresa
Endproc
*** Taie prefixul administrativ dintr-un element de adresa ANAF: "JUD. SATU MARE" -> "SATU MARE".
*** Fara el ramanea doar primul cuvant, deci denumirile din doua cuvinte ieseau trunchiate.
*** 23.08.2026: adaugat 'MUNICIPIUL' / 'JUDETUL', formele NEprescurtate. Pe Bucuresti ANAF nu
*** trimite "JUD. BUCURESTI", ci "MUNICIPIUL BUCURESTI" - fara punct si negasit in lista de mai
*** jos, prefixul ramanea lipit, iar judetul nu se potrivea cu "BUCURESTI" din syn_vnom_judete.
*** Masurat pe 200 de coduri fiscale reale: 74 din cele 100 de esecuri veneau exact de aici, si
*** cadea si localitatea, desi ea se potrivea exact (formularul nu mai incearca localitatea daca
*** judetul a picat). 'ORASUL' / 'COMUNA' / 'SATUL' sunt lasate INTENTIONAT afara: exista
*** localitati care incep chiar asa (ex. ORASUL NOU, jud. Satu Mare) si le-am trunchia numele.
Procedure FaraPrefixLoc
Lparameters tcItem
Local lcItem, lcPrefix, lnPoz
lcItem = Alltrim(Nvl(m.tcItem, ''))
lcPrefix = Getwordnum(m.lcItem, 1, ' ')
lnPoz = At('.', m.lcPrefix)
Do Case
Case m.lnPoz > 0
lcItem = Alltrim(Substr(m.lcItem, At('.', m.lcItem) + 1))
Case Inlist(Upper(m.lcPrefix), 'SAT', 'JUD', 'MUN', 'ORS', 'COM', 'MUNICIPIUL', 'JUDETUL')
lcItem = Alltrim(Substr(m.lcItem, Len(m.lcPrefix) + 1))
Endcase
Return m.lcItem
Endproc
*************************************
*** Parcurge un cursor in forma crsANAF si salveaza fiecare rand in ISTORIC_CODURI_FISCALE
*** prin pack_parteneri.save_istoric_cod_fiscal (26 parametri); commit din 100 in 100 si la final