From a833cf639f7f64566ae045f959b9c676595b1b18 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Sun, 23 Aug 2026 20:31:07 +0300 Subject: [PATCH] sync SVN --- clase/ofirma.vc2 | 214 ++++++++++++++++++++-------- docs/README.md | 1 + docs/conexiuni-tunel-ssh-odbc.md | 174 +++++++++++++++++++++++ docs/inventar-comun.md | 9 ++ docs/testare-ui-vfp.md | 16 +++ programe/onomenclatoare.prg | 237 ++++++++++++++++++++++++++++++- programe/validare.prg | 28 +++- 7 files changed, 618 insertions(+), 61 deletions(-) create mode 100644 docs/conexiuni-tunel-ssh-odbc.md diff --git a/clase/ofirma.vc2 b/clase/ofirma.vc2 index 8683c8c..9e865a7 100644 --- a/clase/ofirma.vc2 +++ b/clase/ofirma.vc2 @@ -1428,6 +1428,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" *< OBJECTDATA: ObjPath="Clb_cont_banca9" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="Clb_banca10" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="Clb_cont_banca10" UniqueID="" Timestamp="" /> + *< OBJECTDATA: ObjPath="But_verifica1" UniqueID="" Timestamp="" /> * *m: alege_fj @@ -1437,6 +1438,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" *m: alege_nivel *m: alege_organizare *m: alege_proprietate + *m: anaf_completeaza_firma *m: sucursala *p: id_judet *p: jcategorie @@ -1472,10 +1474,10 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" LB_TITLU_ALB_B121.Caption = "FIRMA" LB_TITLU_ALB_B121.FontBold = .T. LB_TITLU_ALB_B121.Name = "LB_TITLU_ALB_B121" - LB_TITLU_ALB_B121.TabIndex = 60 + LB_TITLU_ALB_B121.TabIndex = 61 BUT_TERMIN1.Left = 803 BUT_TERMIN1.Name = "BUT_TERMIN1" - BUT_TERMIN1.TabIndex = 55 + BUT_TERMIN1.TabIndex = 56 BUT_TERMIN1.Top = 1 Gridsort1.Left = 20 Gridsort1.Name = "Gridsort1" @@ -1485,15 +1487,22 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'But_renunt1' AS but_renunt WITH ; Left = 769, ; Name = "But_renunt1", ; - TabIndex = 56, ; + TabIndex = 57, ; Top = 1 *< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" /> + ADD OBJECT 'But_verifica1' AS but_verifica WITH ; + Left = 329, ; + Name = "But_verifica1", ; + TabIndex = 3, ; + Top = 65 + *< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" /> + ADD OBJECT 'Cb_tx_caen_revizie' AS cb_tx_simplu WITH ; Height = 29, ; Left = 201, ; Name = "Cb_tx_caen_revizie", ; - TabIndex = 5, ; + TabIndex = 6, ; Top = 120, ; Width = 125, ; _cbbase1.BoundTo = .T., ; @@ -1515,7 +1524,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Cb_tx_categorie", ; - TabIndex = 8, ; + TabIndex = 9, ; Top = 204, ; Width = 314, ; _cbbase1.BoundColumn = 2, ; @@ -1537,7 +1546,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Cb_tx_mama", ; - TabIndex = 58, ; + TabIndex = 59, ; Top = 774, ; Width = 314, ; _CBBASE1.ColumnCount = 2, ; @@ -1562,7 +1571,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 356, ; Name = "Cb_tx_operatie", ; - TabIndex = 54, ; + TabIndex = 55, ; Top = 727, ; Width = 314, ; _cbbase1.BoundColumn = 2, ; @@ -1587,7 +1596,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ControlSource = "poRec.e_mama", ; Left = 251, ; Name = "chkMama", ; - TabIndex = 59, ; + TabIndex = 60, ; Top = 807 *< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" /> @@ -1595,7 +1604,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca1", ; - TabIndex = 23, ; + TabIndex = 24, ; Top = 36, ; Width = 217, ; TEXT_SIMPLU1.ControlSource = "porec.banca1", ; @@ -1613,7 +1622,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca10", ; - TabIndex = 41, ; + TabIndex = 42, ; Top = 288, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca10", ; @@ -1628,7 +1637,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca2", ; - TabIndex = 25, ; + TabIndex = 26, ; Top = 64, ; Width = 217, ; TEXT_SIMPLU1.ControlSource = "porec.banca2", ; @@ -1643,7 +1652,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca3", ; - TabIndex = 27, ; + TabIndex = 28, ; Top = 92, ; Width = 217, ; TEXT_SIMPLU1.ControlSource = "porec.banca3", ; @@ -1658,7 +1667,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca4", ; - TabIndex = 29, ; + TabIndex = 30, ; Top = 120, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca4", ; @@ -1675,7 +1684,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca5", ; - TabIndex = 31, ; + TabIndex = 32, ; Top = 148, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca5", ; @@ -1690,7 +1699,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca6", ; - TabIndex = 33, ; + TabIndex = 34, ; Top = 176, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca6", ; @@ -1705,7 +1714,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca7", ; - TabIndex = 35, ; + TabIndex = 36, ; Top = 204, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca7", ; @@ -1722,7 +1731,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca8", ; - TabIndex = 37, ; + TabIndex = 38, ; Top = 232, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca8", ; @@ -1737,7 +1746,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 625, ; Name = "Clb_banca9", ; - TabIndex = 39, ; + TabIndex = 40, ; Top = 260, ; Width = 217, ; Text_simplu1.ControlSource = "porec.banca9", ; @@ -1752,7 +1761,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Clb_caen", ; - TabIndex = 4, ; + TabIndex = 5, ; Top = 120, ; Width = 190, ; TEXT_SIMPLU1.ControlSource = "porec.caen", ; @@ -1770,7 +1779,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_capsocsub' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_capsocsub", ; - TabIndex = 7, ; + TabIndex = 8, ; Top = 176, ; Width = 314, ; TEXT_SIMPLU1.ControlSource = "porec.capital_soc_sub", ; @@ -1783,7 +1792,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_capsocvar' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_capsocvar", ; - TabIndex = 6, ; + TabIndex = 7, ; Top = 148, ; Width = 314, ; TEXT_SIMPLU1.ControlSource = "porec.capital_soc_var", ; @@ -1797,7 +1806,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_cod_firma", ; - TabIndex = 51, ; + TabIndex = 52, ; Top = 618, ; Width = 290, ; TEXT_SIMPLU1.ControlSource = "porec.cod_firma", ; @@ -1828,7 +1837,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_codang", ; - TabIndex = 48, ; + TabIndex = 49, ; Top = 534, ; Width = 290, ; TEXT_SIMPLU1.ControlSource = "porec.codang", ; @@ -1841,7 +1850,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca1", ; - TabIndex = 22, ; + TabIndex = 23, ; Top = 36, ; Width = 258, ; TEXT_SIMPLU1.ControlSource = "porec.cont_banca1", ; @@ -1859,7 +1868,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca10", ; - TabIndex = 40, ; + TabIndex = 41, ; Top = 288, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca10", ; @@ -1874,7 +1883,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca2", ; - TabIndex = 24, ; + TabIndex = 25, ; Top = 64, ; Width = 258, ; TEXT_SIMPLU1.ControlSource = "porec.cont_banca2", ; @@ -1889,7 +1898,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca3", ; - TabIndex = 26, ; + TabIndex = 27, ; Top = 92, ; Width = 258, ; TEXT_SIMPLU1.ControlSource = "porec.cont_banca3", ; @@ -1904,7 +1913,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca4", ; - TabIndex = 28, ; + TabIndex = 29, ; Top = 120, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca4", ; @@ -1920,7 +1929,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca5", ; - TabIndex = 30, ; + TabIndex = 31, ; Top = 148, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca5", ; @@ -1935,7 +1944,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca6", ; - TabIndex = 32, ; + TabIndex = 33, ; Top = 176, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca6", ; @@ -1950,7 +1959,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca7", ; - TabIndex = 34, ; + TabIndex = 35, ; Top = 204, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca7", ; @@ -1966,7 +1975,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca8", ; - TabIndex = 36, ; + TabIndex = 37, ; Top = 232, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca8", ; @@ -1981,7 +1990,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 368, ; Name = "Clb_cont_banca9", ; - TabIndex = 38, ; + TabIndex = 39, ; Top = 260, ; Width = 258, ; Text_simplu1.ControlSource = "porec.cont_banca9", ; @@ -1996,7 +2005,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_declarant", ; - TabIndex = 52, ; + TabIndex = 53, ; Top = 646, ; Width = 290, ; Text_simplu1.ControlSource = "porec.declarant", ; @@ -2009,7 +2018,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 545, ; Name = "Clb_email", ; - TabIndex = 45, ; + TabIndex = 46, ; Top = 324, ; Width = 284, ; TEXT_SIMPLU1.ControlSource = "porec.email", ; @@ -2028,7 +2037,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_functie", ; - TabIndex = 53, ; + TabIndex = 54, ; Top = 674, ; Width = 290, ; Text_simplu1.ControlSource = "porec.functie", ; @@ -2041,7 +2050,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_itm", ; - TabIndex = 50, ; + TabIndex = 51, ; Top = 590, ; Width = 290, ; Text_simplu1.ControlSource = "porec.indicativ", ; @@ -2056,7 +2065,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_nume", ; - TabIndex = 46, ; + TabIndex = 47, ; Top = 478, ; Width = 290, ; TEXT_SIMPLU1.ControlSource = "porec.nume", ; @@ -2069,7 +2078,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_oasp", ; - TabIndex = 49, ; + TabIndex = 50, ; Top = 562, ; Width = 290, ; TEXT_SIMPLU1.ControlSource = "porec.oasp", ; @@ -2083,7 +2092,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_prenume", ; - TabIndex = 47, ; + TabIndex = 48, ; Top = 506, ; Width = 290, ; TEXT_SIMPLU1.ControlSource = "porec.prenume", ; @@ -2095,7 +2104,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_reg_comert' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_reg_comert", ; - TabIndex = 3, ; + TabIndex = 4, ; Top = 92, ; Width = 314, ; TEXT_SIMPLU1.ControlSource = "porec.reg_comert", ; @@ -2111,7 +2120,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Clb_schema", ; - TabIndex = 57, ; + TabIndex = 58, ; Top = 746, ; Width = 314, ; Text_simplu1.ControlSource = "porec.schema", ; @@ -2128,7 +2137,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_telefon", ; - TabIndex = 42, ; + TabIndex = 43, ; Top = 324, ; Width = 181, ; TEXT_SIMPLU1.ControlSource = "porec.telefon", ; @@ -2144,7 +2153,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 365, ; Name = "Clb_telefon2", ; - TabIndex = 43, ; + TabIndex = 44, ; Top = 352, ; Width = 181, ; TEXT_SIMPLU1.ControlSource = "porec.telefon2", ; @@ -2159,7 +2168,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 545, ; Name = "Clb_telefon3", ; - TabIndex = 44, ; + TabIndex = 45, ; Top = 352, ; Width = 181, ; TEXT_SIMPLU1.ControlSource = "porec.telefon3", ; @@ -2191,7 +2200,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_tx_simplu10' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_tx_simplu10", ; - TabIndex = 20, ; + TabIndex = 21, ; Top = 674, ; Width = 314, ; Text_simplu1.ControlSource = "porec.apart", ; @@ -2206,7 +2215,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Clb_tx_simplu11", ; - TabIndex = 21, ; + TabIndex = 22, ; Top = 702, ; Width = 314, ; Text_simplu1.ControlSource = "porec.cod_postal", ; @@ -2220,7 +2229,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_tx_simplu6' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_tx_simplu6", ; - TabIndex = 16, ; + TabIndex = 17, ; Top = 562, ; Width = 314, ; Text_simplu1.ControlSource = "porec.strada", ; @@ -2234,7 +2243,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_tx_simplu7' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_tx_simplu7", ; - TabIndex = 17, ; + TabIndex = 18, ; Top = 590, ; Width = 314, ; Text_simplu1.ControlSource = "porec.numar", ; @@ -2249,7 +2258,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 29, ; Left = 12, ; Name = "Clb_tx_simplu8", ; - TabIndex = 18, ; + TabIndex = 19, ; Top = 618, ; Width = 314, ; Text_simplu1.ControlSource = "porec.bloc", ; @@ -2264,7 +2273,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ADD OBJECT 'Clb_tx_simplu9' AS clb_tx_simplu WITH ; Left = 12, ; Name = "Clb_tx_simplu9", ; - TabIndex = 19, ; + TabIndex = 20, ; Top = 646, ; Width = 314, ; Text_simplu1.ControlSource = "porec.scara", ; @@ -2281,7 +2290,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" cvar_afisata = porec.forma_juridica, ; Left = 11, ; Name = "Ct_clb_formaj", ; - TabIndex = 10, ; + TabIndex = 11, ; Top = 259, ; img_cautare.Name = "img_cautare", ; clb_tx_cautare.Lb_simplu1.Caption = "Formă juridică", ; @@ -2298,7 +2307,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" cvar_afisata = porec.tip_societate, ; Left = 11, ; Name = "Ct_clb_nivel", ; - TabIndex = 12, ; + TabIndex = 13, ; Top = 315, ; img_cautare.Name = "img_cautare", ; clb_tx_cautare.Lb_simplu1.Caption = "Nivel", ; @@ -2315,7 +2324,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" cvar_afisata = porec.forma_organizare, ; Left = 11, ; Name = "Ct_clb_organizare", ; - TabIndex = 11, ; + TabIndex = 12, ; Top = 287, ; img_cautare.Name = "img_cautare", ; clb_tx_cautare.Lb_simplu1.Caption = "Organizare", ; @@ -2334,7 +2343,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" cvar_afisata = porec.forma_proprietate, ; Left = 11, ; Name = "Ct_clb_proprietate", ; - TabIndex = 9, ; + TabIndex = 10, ; Top = 231, ; img_cautare.Name = "img_cautare", ; clb_tx_cautare.Lb_simplu1.Caption = "Proprietate", ; @@ -2349,7 +2358,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" cdate = porec, ; Left = 12, ; Name = "Ct_localitate1", ; - TabIndex = 15, ; + TabIndex = 16, ; Top = 478, ; Width = 314, ; CB_LOCALITATE_AF.img_atentie.Name = "img_atentie", ; @@ -2377,7 +2386,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 45, ; Left = 14, ; Name = "Ed_adresa", ; - TabIndex = 14, ; + TabIndex = 15, ; Top = 428, ; Width = 814, ; _edbase1.ControlSource = "porec.adresa", ; @@ -2395,7 +2404,7 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" Height = 40, ; Left = 14, ; Name = "Ed_tx_simplu1", ; - TabIndex = 13, ; + TabIndex = 14, ; Top = 389, ; Width = 814, ; _EDBASE1.ControlSource = "porec.antet", ; @@ -2584,6 +2593,91 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" ENDPROC + PROCEDURE anaf_completeaza_firma + Local loPartener As "empty" + Local loPartenerX As "empty" + Local lcCodFiscal, lcCodFiscalFRO, lcCrsJud, lcCrsLoc, lcDenumire, lcMesajIntrebare, lcNepotrivit, lcSelect, lcTipVerificare, ldData, llValid, lnRaspuns, loNom + + lcSelect = Select() + + *** 1. Preluare si validare cod fiscal + lcCodFiscal = Alltrim(Nvl(poRec.cod_fiscal, "")) + If Empty(m.lcCodFiscal) + AMESSAGEBOX("Completati codul fiscal", 0+48, _Screen.Caption) + Return .F. + Endif + + *** Acceptam doar CIF romanesc (ANAF nu intoarce date pentru alte tari) + lcCodFiscalFRO = Strtran(Strtran(Strtran(Upper(m.lcCodFiscal), "RO", ""), " ", ""), "R", "") + If !Isdigit(m.lcCodFiscalFRO) Or Len(m.lcCodFiscalFRO) > 10 Or Empty(m.lcCodFiscalFRO) + AMESSAGEBOX("Codul fiscal " + m.lcCodFiscal + " nu pare a fi un CIF romanesc valid.", 0+48, _Screen.Caption) + Return .F. + Endif + + lcDenumire = Alltrim(poRec.firma) + ldData = DATE() + lcTipVerificare = 'ANAF_SERVICIU_WEB' + + loPartenerX = Createobject("empty") + loPartener = Createobject("empty") + AddProperty(loPartenerX, "cod_fiscal", m.lcCodFiscal) + AddProperty(loPartenerX, "denumire", m.lcDenumire) + AddProperty(loPartenerX, "dataact", m.ldData) + llValid = verifica_partener(m.lcTipVerificare, loPartenerX, @loPartener) + + + If !m.llValid + amessagebox('Codul ' + m.lcCodFiscal + ' este invalid!', 0 + 48, _Screen.Caption) + ELSE + If Pemstatus(loPartener, "platitortvamfin", 5) + lcMesajIntrebare = 'Doriti sa se completeze datele in formular?' + + lnRaspuns = verifica_partener_show_info(loPartener, m.lcCodFiscal, m.lcDenumire, m.lcMesajIntrebare) + IF lnRaspuns = 6 + poRec.firma = Alltrim(Nvl(loPartener.firma, "")) + poRec.antet = Alltrim(Nvl(loPartener.firma, "")) + + poRec.reg_comert = Alltrim(Nvl(loPartener.regcom, "")) + poRec.adresa = Alltrim(Nvl(loPartener.adresa, "")) + *** Judetul si localitatea se potrivesc peste nomenclator: denumirea de la ANAF poate fi + *** scrisa altfel decat in syn_vnom_*, iar formularul are nevoie de id-uri, nu de text. + lcNepotrivit = "" + loNom = Createobject("AnafNomenclator") + lcCrsJud = Iif(!Empty(Thisform.Ct_localitate1.cCrsJudete), Thisform.Ct_localitate1.cCrsJudete, "crsJudete") + lcCrsLoc = Iif(!Empty(Thisform.Ct_localitate1.cCrsLocalitati), Thisform.Ct_localitate1.cCrsLocalitati, "crsLocalitati") + If Used(m.lcCrsJud) And loNom.pozitioneaza_judet(m.lcCrsJud, Nvl(loPartener.judet, "")) + poRec.judet = Alltrim(Evaluate(m.lcCrsJud + ".judet")) + *** ia id_judet din inregistrarea curenta si reface cursorul de localitati pe judetul ales + Thisform.Ct_localitate1.modifica_judet() + If Used(m.lcCrsLoc) And loNom.pozitioneaza_localitate(m.lcCrsLoc, Nvl(loPartener.localitate, "")) + poRec.localitate = Alltrim(Evaluate(m.lcCrsLoc + ".localitate")) + Thisform.Ct_localitate1.modifica_localitate(Evaluate(m.lcCrsLoc + ".id_loc")) + Else + lcNepotrivit = Alltrim(Nvl(loPartener.localitate, "")) + Endif + Else + lcNepotrivit = Alltrim(Nvl(loPartener.judet, "")) + ", " + Alltrim(Nvl(loPartener.localitate, "")) + Endif + + poRec.strada = Alltrim(Nvl(loPartener.strada, "")) + poRec.numar = Alltrim(Nvl(loPartener.nr, "")) + poRec.Bloc = Alltrim(Nvl(loPartener.Bloc, "")) + poRec.scara = Alltrim(Nvl(loPartener.scara, "")) + *** porec.apart e numeric in nom_firme; ANAF intoarce string + poRec.apart = Int(Val(Nvl(loPartener.apart, "0"))) + + Thisform.Refresh() + ENDIF + ENDIF + Endif + + If !Empty(m.lcNepotrivit) + AMESSAGEBOX("Nu am gasit in nomenclator: " + m.lcNepotrivit + Chr(13) + ; + "Alegeti manual judetul si localitatea.", 0+48, _Screen.Caption) + Endif + Select (m.lcSelect) + ENDPROC + PROCEDURE inainte_de_do_termin Local PLRETURN @@ -2787,6 +2881,10 @@ DEFINE CLASS frm_firme_nou AS _frmbase OF "_frm_base.vcx" PROCEDURE sucursala ENDPROC + PROCEDURE But_verifica1.Click + Thisform.anaf_completeaza_firma() + ENDPROC + PROCEDURE Cb_tx_categorie._cbbase1.InteractiveChange porec.persoana_juridica=this.value thisform.jcategorie=this.Value diff --git a/docs/README.md b/docs/README.md index 74e123e..396dda9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,6 +32,7 @@ atingi zona X, citeste fisierul Y"). Restul se deschid doar la declansator. | `testare-ui-vfp.md` | test cu formular real + screenshots (harness UI) | | **Oracle** | | | `conventie_mediu_oracle.md` | te conectezi la dev/test, alegi schema, rulezi un script de pachet | +| `conexiuni-tunel-ssh-odbc.md` | ajungi la un Oracle de PRODUCTIE prin tunel SSH (Bitvise) + alias TNS + DSN ODBC | | `scripturi-migrare-db.md` | modifici schema (tabele/view-uri/pachete); compatibilitate 10.2 | | `publicare-scripturi-db.md` | publici scripturile catre clienti | | `oracle_export.md` | reexporti sursa unui pachet PL/SQL | diff --git a/docs/conexiuni-tunel-ssh-odbc.md b/docs/conexiuni-tunel-ssh-odbc.md new file mode 100644 index 0000000..09641be --- /dev/null +++ b/docs/conexiuni-tunel-ssh-odbc.md @@ -0,0 +1,174 @@ +# Conexiuni la bazele de productie: tunel SSH (Bitvise) + ODBC/TNS + +Cum se ajunge, de pe statia de lucru, la un Oracle care nu e expus direct in internet. Valabil +pentru toate proiectele ROA. Scopul documentului: sa nu se mai piarda o sesiune intreaga +redescoperind lantul. + +> **Fara credentiale in git.** Acest fisier NU contine parole, si nici un fisier din repo nu +> trebuie sa contina. Parolele stau in profilul Bitvise (criptate cu DPAPI, legate de contul +> Windows) si in capul celui care lucreaza. Daca ai nevoie de o parola pe care nu o ai, cere-o - +> nu o cauta prin fisiere si **nu o ghici**: Oracle poate avea `FAILED_LOGIN_ATTEMPTS` in profil, +> iar cateva incercari gresite blocheaza contul de schema in PRODUCTIE. + +## Lantul, pe scurt + +``` +statie -> [tunel SSH Bitvise] -> 127.0.0.1:1521 -> Oracle de pe serverul de productie + ^ + aliasul TNS din instantclient\tnsnames.ora arata AICI + ^ + DSN-ul ODBC cu acelasi nume e ce primeste goConn.Connect() +``` + +Trei nume trebuie sa se potriveasca, si e usor de ratat: **profilul Bitvise** (ce port local +deschide), **aliasul TNS** (ce host:port foloseste) si **DSN-ul ODBC** (ce alias TNS foloseste). + +## 1. Tunelul SSH + +Profilele Bitvise (`.tlp`) stau in `D:\GoogleDrive\` (ex. `vending.tlp`). Un profil contine +gazda, portul, utilizatorul, parola criptata, cheile de gazda deja acceptate si **regulile de +port forwarding** - de obicei `127.0.0.1:1521 -> localhost:1521`. + +Ridicare din linie de comanda, fara interfata grafica: + +```powershell +$exe = 'C:\Program Files (x86)\Bitvise SSH Client\stnlc.exe' +Start-Process $exe -ArgumentList '-profile=D:\GoogleDrive\vending.tlp' -WindowStyle Hidden ` + -RedirectStandardOutput "$env:TEMP\stnlc_out.txt" -RedirectStandardError "$env:TEMP\stnlc_err.txt" +``` + +`stnlc` foloseste singur parola stocata in profil - **nu o trece pe linia de comanda**, ar ajunge +in istoricul shell-ului. Ruleaza sub acelasi cont Windows sub care a fost salvat profilul,altfel +DPAPI nu poate decripta parola. + +Verificare ca tunelul chiar e sus (nu te baza pe faptul ca procesul traieste): + +```powershell +(Test-NetConnection 127.0.0.1 -Port 1521 -WarningAction SilentlyContinue).TcpTestSucceeded +``` + +In `stnlc_out.txt` linia care conteaza e `Added client-to-server forwarding rule on +127.0.0.1:1521 to localhost:1521.` Inchidere: opreste procesul `stnlc`. + +**Capcana**: un singur port local 1521 pentru mai multe destinatii. Daca ai deja un tunel ridicat +catre alt client, al doilea nu mai poate lega portul si vei interoga **alta baza** fara sa-ti dai +seama. Verifica intotdeauna cu ce te-ai conectat (vezi pasul 4). + +## 2. Aliasul TNS + +`D:\ROA\instantclient_19_18\tnsnames.ora` (si `instantclient_11_2_0_2` pentru driverul ODBC pe +32 de biti). Aliasurile care merg prin tunel arata spre `127.0.0.1`: + +``` +VENDING = + (DESCRIPTION = + (ADDRESS_LIST = (ADDRESS = (PROTOCOL = tcp)(HOST = 127.0.0.1)(PORT = 1521))) + (CONNECT_DATA = (SERVICE_NAME = XEPDB1)) + ) +``` + +Pentru `sqlplus` trebuie `TNS_ADMIN` setat pe folderul care contine `tnsnames.ora`: + +```powershell +$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' +``` + +## 3. DSN-ul ODBC + +Aplicatia nu foloseste TNS direct: `oConn.Connect(tcHost, tcUser, tcPassword)` +(`oproceduri_comune.prg`) construieste `dsn=;Uid=...;Pwd=...` - deci **`tcHost` e un nume +de DSN ODBC**, nu un host si nu un alias TNS. DSN-urile sunt pe 32 de biti (VFP e pe 32 de biti), +deci in `HKLM\SOFTWARE\WOW6432Node\ODBC\ODBC.INI`, cu driverul din `instantclient_11_2_0_2`. + +Listare rapida: + +```powershell +Get-ChildItem 'HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI' | + Select-Object -ExpandProperty PSChildName +``` + +De obicei DSN-ul are acelasi nume cu aliasul TNS (`VENDING`, `CENTRAL`, `ROA_CENTRAL`...). +Administrare vizuala: `C:\Windows\SysWOW64\odbcad32.exe` (**nu** cel din `System32`, acela e pe +64 de biti si nu vede DSN-urile VFP). + +## 4. Interogare si verificare + +```powershell +$env:TNS_ADMIN = 'D:\ROA\instantclient_19_18' +& 'D:\ROA\instantclient_19_18\sqlplus.exe' -S -L '/@VENDING' '@script.sql' +``` + +`-L` = o singura incercare de login (nu reincearca la parola gresita). **Foloseste-l intotdeauna +pe productie.** + +Prima interogare, mereu, ca sa stii unde ai nimerit: + +```sql +select user || ' @ ' || sys_context('USERENV','DB_NAME') from dual; +``` + +Pentru extragere in fisier, `spool` scrie **local**, nu pe server: + +```sql +set pagesize 0 feedback off heading off linesize 100 trimspool on termout off +spool D:\cale\locala\iesire.txt +select ...; +spool off +``` + +**Capcana PowerShell**: intr-un here-string cu ghilimele duble (`@"..."@`) PowerShell expandeaza +`$`. Un regex Oracle care se termina cu `$` (ancora de sfarsit) ajunge stricat in fisierul `.sql` +si interogarea intoarce 0 randuri **fara nicio eroare**. Foloseste here-string cu apostrof +(`@'...'@`) si inlocuieste caile printr-un token. + +**Capcana `termout off`**: ascunde si mesajele de eroare. Daca fisierul spool iese gol, ruleaza +din nou fara `termout off` inainte sa banuiesti datele. + +## Schemele cunoscute (fara parole) + +| Tunel / profil | Alias TNS + DSN | Schema Oracle | +|---|---|---| +| `vending.tlp` | `VENDING` | `vending` | +| conpress | `ROA_CONPRESS` | `xenoti` | + +Restul aliasurilor din `tnsnames.ora` (`ROA_CENTRAL`, `CENTRAL105`, `ROA_TEST`, ...) sunt retea +interna si nu au nevoie de tunel. + +## Reguli pe productie + +1. **Doar `SELECT`.** Fara `INSERT`/`UPDATE`/`DELETE`/DDL, fara `ALTER SESSION` care schimba + comportament persistent. Daca ai nevoie de date de lucru, extrage-le si lucreaza local. +2. **Fara ghicit parole** - vezi avertismentul de la inceput. +3. **Interogari marginite**: `fetch first N rows only`, si evita scanarile complete pe tabele + mari in orele de lucru. +4. **Inchide tunelul** cand ai terminat; nu-l lasa deschis peste noapte. +5. **Datele extrase**: codurile fiscale sunt publice si pot sta in repo (vezi + `utile\Teste\cache_anaf\codes_*_reale.txt`). Denumirile de parteneri, adresele, soldurile + **nu** - nu le comite. + +## De unde vin loturile de coduri fiscale pentru teste + +`COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt` a fost extras din productia `vending`, tabela +`nom_parteneri` (23932 randuri, 6382 coduri romanesti distincte): + +```sql +select cif from ( + select distinct regexp_replace(upper(trim(cod_fiscal)), '[^0-9]', '') as cif + from nom_parteneri + where cod_fiscal is not null + and regexp_like(upper(trim(cod_fiscal)), '^(RO)?[[:space:]]*[0-9]{2,10}$') +) where length(cif) between 2 and 10 +order by ora_hash(cif) +fetch first 1000 rows only; +``` + +`order by ora_hash(cif)` da o dispersie **deterministica** (aceeasi de fiecare data), spre +deosebire de `dbms_random`; ordonarea crescuta dupa cod ar fi inclinat lotul spre firme vechi, +deci spre Bucuresti. Suprapunere cu lotul mai vechi de 200: 8 coduri. + +Folosire in proba end-to-end ANAF: + +```powershell +$env:E2E_CODURI = 'D:\ROA\ROADEF\COMUN\utile\Teste\cache_anaf\codes_1000_reale.txt' +$env:E2E_LIMITA = '1000' +``` diff --git a/docs/inventar-comun.md b/docs/inventar-comun.md index d833637..6193586 100644 --- a/docs/inventar-comun.md +++ b/docs/inventar-comun.md @@ -169,10 +169,19 @@ diferit de metoda `goExport.export_xls`, doar nume identic. |---|---|---| | VerificareCod (clasa) | validare completa cu webservice: metode VERIFICARE_CIF/VERIFICARE_CNP/ANAF/MFIN/VIES/validare/GetError | 169 | | VerificareANAF (clasa) | sincronizare lista CIF-uri cu ANAF (VerificaListaCIF, ANAF_SincronWebService_PlatitorTva) | 26 | +| ParseAdresaAnaf / FaraPrefixLoc (VerificareANAF) | sparge adresa ANAF in judet/localitate/strada/nr/bloc/scara/etaj/apart; FaraPrefixLoc taie prefixul administrativ (JUD./MUN./ORS./COM./SAT, plus formele intregi MUNICIPIUL/JUDETUL - pe Bucuresti ANAF trimite "MUNICIPIUL BUCURESTI") pastrand denumirea intreaga. ORASUL/COMUNA/SATUL NU se taie: exista localitati care incep asa (ORASUL NOU). | - | | test_cif / VALIDARE_CIF / test_cnp / VALIDARE_CNP | validari format + cifra control, offline | 27/19/9/15 | | VERIFICARE_PLATITORTVA / VIES_VAT / ONRC | platitor TVA / verificare VIES / interogare ONRC | 5/5/9 | | IntroducereCod (clasa Form) | formular introducere + validare cod | 25 | +### onomenclatoare.prg - nomenclatoare judete/localitati +| Functie/clasa | Ce face | Uz | +|---|---|---| +| AnafNomenclator (clasa) | potriveste denumirea de judet/localitate de la ANAF peste cursoarele nomenclatorului (crsJudete/crsLocalitati ale clasei `ct_localitate`) si le pozitioneaza pe randul gasit, de unde se ia id-ul. Trepte: exact -> fara sufix administrativ -> departajare dupa comuna -> cheie fuzzy cu A si I unificate (nomenclatorul tine si TIRGU MURES, si TARGU MURES). Treptele tolerante accepta doar candidat unic; altfel se completeaza doar judetul si utilizatorul alege manual. | - | +| AnafNomenclator.nume_curat / poz_marcaj | reduc o denumire la numele propriu, taind sufixul administrativ in ambele forme in care apare: cu paranteze, cum il tine nomenclatorul (`AGIGEA (COM. AGIGEA)`), si fara, cum il trimite ANAF (`AGIGEA COM. AGIGEA`). Marcajele au punct (` COM.`/` ORS.`/` MUN.`/` SAT.`/` JUD.`), deci nu pot manca din numele propriu-zis. | - | +| AnafNomenclator.cheie_sufix / fara_marcaj | scot comuna/orasul de care apartine localitatea (`GRECI (COM. SCHITU)` -> `SCHITU`), din oricare din cele doua forme, si fara cuvantul administrativ - sursele il scriu diferit (nomenclator `(ORAS X)`, ANAF `ORS. X`). Folosite la departajarea omonimelor din acelasi judet. | - | +| AnafNomenclator.cheie_fuzzy / cheie_bruta | cheie de comparare: fara separatoare, cu A si I unificate. `cheie_fuzzy` taie intai sufixul, `cheie_bruta` nu. | - | + ### ocautare.prg - dialoguri standard de cautare/alegere (de refolosit in loc de SELECT+grid manual) | Functie | Ce alege | Uz (prg/forme) | |---|---|---| diff --git a/docs/testare-ui-vfp.md b/docs/testare-ui-vfp.md index b25a789..fdec6c4 100644 --- a/docs/testare-ui-vfp.md +++ b/docs/testare-ui-vfp.md @@ -10,6 +10,14 @@ Fisiere in `COMUN\utile\Teste\`: `vfp_ui_harness.ps1` (orchestrator generic, par `mock_amessagebox.prg` (mock dialog) — infrastructura sta in radacina `Teste\`; suitele stau in subfoldere pe subiect. Exemplu complet: `achizitie_import\test_import_nota_ui.prg` + `.ps1`. +**Initializarea de mediu se alege dupa PROIECT, nu dupa clasa testata.** `test_init_env_auto.prg` +are `gcAppPath` hardcodat pe `D:\ROA\ROACONT\`; exista variante `_roagest`, `_roafacturare`, +`_acnpro`, `_roadef`. `D:\ROA\ROACONT\COMUN` si `D:\ROA\ROADEF\COMUN` sunt **working copy-uri +SVN separate, nu junctions**: un test pornit cu init-ul gresit incarca alt COMUN si nu vede +modificarile necomise — trece sau pica pe cod vechi, fara niciun semn. Pune in test o verificare +explicita ca noul cod chiar e incarcat (ex. `CREATEOBJECT` pe clasa noua, intr-un `TRY`) inainte +de orice asertiune. + **REGULA (Marius): testele pe aplicatii frontend exerseaza fluxul REAL al utilizatorului** — formularul/butonul/metoda pe care o apeleaza aplicatia, NU introducerea directa a randurilor in cursoare/tabele. Popularea directa sare peste validari/filtre/efecte @@ -117,6 +125,14 @@ g. **Mock de messagebox**: `FUNCTION amessagebox` care returneaza direct valoare (6=Da), incarcat cu `SET PROCEDURE ... ADDITIVE` **PRIMUL**, inaintea fisierelor aplicatiei: la nume duplicat de procedura VFP foloseste fisierul cautat PRIMUL (verificat empiric). Astfel umbreste `amessagebox` si in apelurile din metodele de clasa. + **Nu acopera apelurile INTRA-FISIER**: cand functia care deschide dialogul sta in ACELASI + `.prg` cu `amessagebox`, mock-ul nu o prinde si dialogul ramane modal. Caz real: + `verifica_partener_show_info` si `amessagebox` sunt amandoua in `oproceduri_comune.prg` — + rularea headless s-a blocat pe primul CIF pana s-a facut un mock pentru wrapper-ul insusi + (`partener_anaf\mock_verifica_partener_show_info.prg`). Regula practica: mock-ul se pune pe + functia pe care o apeleaza codul TESTAT, nu pe cea de la capatul lantului. Si pune in test o + proba care confirma ca mock-ul a castigat, INAINTE de orice actiune care poate deschide un + dialog — altfel esecul se manifesta ca test agatat, nu ca eroare. h. **Cursorii ceruti de Init**: pre-populeaza-i INAINTE de instantiere (Init-ul recreeaza din Oracle cursoarele goale, iar recrearea lasa grid-ul fara coloane, eroare 1925). Pune 1 rand placeholder inainte, apoi **`ZAP`** dupa `Show()` — NU `DELETE ALL`, care lasa un rand fizic diff --git a/programe/onomenclatoare.prg b/programe/onomenclatoare.prg index 1d602c9..53477d5 100644 --- a/programe/onomenclatoare.prg +++ b/programe/onomenclatoare.prg @@ -2577,4 +2577,239 @@ Procedure NOM_cursuri_NOU Do Adauga_Modifica_Inregistrare With "curscal", loRec, , "INSERT", , "addnomcurs" Endproc -************************************************************************************************************************** \ No newline at end of file +************************************************************************************************************************** + +*!* 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 diff --git a/programe/validare.prg b/programe/validare.prg index 07fbccf..f535f51 100644 --- a/programe/validare.prg +++ b/programe/validare.prg @@ -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