From 889840357ad168894f2593eb03655cd2b0f4a3a5 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Mon, 27 Jul 2026 01:29:41 +0300 Subject: [PATCH] Verificare ANAF la alegerea partenerului ocautare.prg - miezul functionalitatii: - anaf_verif_cautare: verdictul ANAF pe randul curent din formularul de cautare (label sub grid), la data documentului; discordantele si codurile fiscale invalide cu rosu; F4 sau click deschide detaliile. - ANAF_StarePartener, cu cache pe sesiune, excludere parteneri externi si persoane fizice; ANAF_ValidareCod pentru CIF/CNP. - ANAF_NivelVerificare: cascada RC_ANAF_VERIF_SELECTIE (kill-switch settings.ini > optiuni utilizator > optiuni firma > implicit 1), cu cache invalidat la schimbarea firmei sau utilizatorului; ANAF_ComutaVerificare pentru punctul de meniu. - Detalii: alegerea variantei corecte de partener din perechea RO / fara RO, cu discriminator "are documente in perioada"; dupa Da sau Nu se inchide cautarea si se revine in formular cu partenerul ales (AplicaInlocuirePartenerANAF). - ANAF_CaData: data documentului poate veni si ca DateTime (tact.dataact). - Banda proprie sub grid pentru label: formularul creste cu 54, gridul isi pierde ancorarea de jos si primeste inaltimea din AjusteazaBanda, legata de Resize si Activate - formularul isi reaseaza gridul dupa Show, deci Activate e momentul util. validare.prg: ANAF_VerificaCuiSingle, wrapper single-CUI peste serviciul ANAF, cu data verificarii si o singura eroare logata pe sesiune. cauta_alfa.prg: hook generic - ataseaza poVerifAlegere pe formularul de cautare inainte de Show si il detaseaza dupa. Apelanti opt-in (lVerificaANAF): baza.vc2 (lookup-ul generic de partener din formularele actbaza/actbaza2007 lansate din meniuri), onote_contabile.vc2 (partener debit/credit), omodificari.vc2 (do_cauta din cele trei clase de modificare, cu data notei), ofacturare.vc2 (client, furnizor). Casa/banca ramane in afara: acolo partenerul se alege pentru imperecherea facturilor. cauta_alfa_forms.vc2: F4 deschide detaliile, iar terminarea cautarii trece prin VerificaAlegere. Teste: suita headless pentru fluxul de verificare (utile/Teste/partener_anaf/), cu mock pentru apelul ANAF si pentru dialoguri. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019H3r66sVojGhgaKq5niu1u --- clase/baza.vc2 | 3 +- clase/cauta_alfa_forms.vc2 | 13 + clase/ofacturare.vc2 | 12 +- clase/omodificari.vc2 | 27 +- clase/onote_contabile.vc2 | 1 + docs/conventie_ux_formulare.md | 22 +- docs/flux-editare-vfp-text.md | 2 +- docs/git_svn_parallel_init_prompt.md | 86 - docs/reguli_lucru.md | 16 +- docs/scripturi-migrare-db.md | 11 + programe/cauta_alfa.prg | 10 + programe/ocautare.prg | 800 +++++++- programe/validare.prg | 122 +- utile/Teste/mock_ainputbox.prg | 33 + utile/Teste/mock_amessagebox.prg | 6 + .../partener_anaf/mock_anaf_verificare.prg | 34 + .../Teste/partener_anaf/shot_dialog_anaf.prg | 146 ++ .../Teste/partener_anaf/shot_dialog_anaf.ps1 | 177 ++ .../test_verif_partener_anaf_v2_ui.prg | 1660 +++++++++++++++++ .../test_verif_partener_anaf_v2_ui.ps1 | 12 + 20 files changed, 3083 insertions(+), 110 deletions(-) delete mode 100644 docs/git_svn_parallel_init_prompt.md create mode 100644 utile/Teste/mock_ainputbox.prg create mode 100644 utile/Teste/partener_anaf/mock_anaf_verificare.prg create mode 100644 utile/Teste/partener_anaf/shot_dialog_anaf.prg create mode 100644 utile/Teste/partener_anaf/shot_dialog_anaf.ps1 create mode 100644 utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg create mode 100644 utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1 diff --git a/clase/baza.vc2 b/clase/baza.vc2 index 5d6339c..ffe3161 100644 --- a/clase/baza.vc2 +++ b/clase/baza.vc2 @@ -10397,7 +10397,8 @@ DEFINE CLASS item AS container *!* 03.10.2006 *!* MARIUS.MUTU - locauta = CautPartenerContabilitate(GetHash([cTitlu=>] + T + [??lAdaugCorespondente=>1??cTipuriParteneri=>] + lcTip)) + *!* 26.07.2026 claude - verificare ANAF la alegerea partenerului pe formularele de documente + locauta = CautPartenerContabilitate(GetHash([cTitlu=>] + T + [??lAdaugCorespondente=>1??cTipuriParteneri=>] + lcTip + [??lVerificaANAF=>1])) *!* modificare migrare v 1.0 > v 2.0 If poAct.id_set = 229 poAct.vid_part_rez = locauta.id_part diff --git a/clase/cauta_alfa_forms.vc2 b/clase/cauta_alfa_forms.vc2 index 27df05d..f9288a0 100644 --- a/clase/cauta_alfa_forms.vc2 +++ b/clase/cauta_alfa_forms.vc2 @@ -564,6 +564,13 @@ DEFINE CLASS cauta_alfa_form AS _frmbase OF "_frm_base.vcx" ENDPROC + PROCEDURE inainte_de_do_termin + If Type('This.oVerifAlegere') = 'O' And !Isnull(This.oVerifAlegere) + Return This.oVerifAlegere.VerificaAlegere(Thisform) + Endif + Return DODEFAULT() + ENDPROC + PROCEDURE Init Lparameters tcCursor, tcNume_Proc, tcTitluColoana, tccoloana, tl_AllInList, ; tcPrimaColoana, tnPornire, tcGridDynamicBackColor, tcGridToolTip, ; @@ -705,6 +712,12 @@ DEFINE CLASS cauta_alfa_form AS _frmbase OF "_frm_base.vcx" THIS.cb_tx_cautare1.SETFOCUS KEYBOARD '{END}' + CASE nKeyCode = -3 && F4 + NODEFAULT + IF TYPE('THIS.oVerifAlegere') = 'O' AND !ISNULL(THIS.oVerifAlegere) + THIS.oVerifAlegere.Detalii() + ENDIF + OTHERWISE DODEFAULT(nKeyCode, nShiftAltCtrl) ENDCASE diff --git a/clase/ofacturare.vc2 b/clase/ofacturare.vc2 index 06ae45f..30786ab 100644 --- a/clase/ofacturare.vc2 +++ b/clase/ofacturare.vc2 @@ -6949,7 +6949,9 @@ DEFINE CLASS frm_date_aviz AS _frmbase OF "_frm_base.vcx" Endif Otherwise && modificare v 2.0.93 : am adaugat 47 - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Clienti??cCont=>]+Iif(INLIST(poDate.tip,42,47),[357],Iif(Inlist(poDate.tip,28,29),[461],Alltrim(gcCont411)))+[??lAdaugCorespondente=>1])) + loHash = GetHash([cTitlu=>Clienti??cCont=>]+Iif(INLIST(poDate.tip,42,47),[357],Iif(Inlist(poDate.tip,28,29),[461],Alltrim(gcCont411)))+[??lAdaugCorespondente=>1??lVerificaANAF=>1]) + loHash.SetValue('dDataDoc', Iif(Type('poDate.dataact') = 'D', poDate.dataact, {})) + loCauta = CautPartenerContabilitate(loHash) If !Empty(Nvl(loCauta.id_part,0)) And !Empty(loCauta.denumire) poDate.id_client = loCauta.id_part poDate.nume_client = loCauta.denumire @@ -7906,7 +7908,9 @@ DEFINE CLASS frm_date_aviz_lucrare AS _frmbase OF "_frm_base.vcx" PROCEDURE do_cauta_furnizor Local loCauta *!* loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti furnizorul??cCont=>401??lAdaugCorespondente=>1])) - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti furnizorul??cCont=>401])) + loHash = GetHash([cTitlu=>Alegeti furnizorul??cCont=>401??lVerificaANAF=>1]) + loHash.SetValue('dDataDoc', Iif(Type('poDate.dataact') = 'D', poDate.dataact, {})) + loCauta = CautPartenerContabilitate(loHash) If !Empty(loCauta.id_part) And !Empty(loCauta.denumire) AND !ISNULL(loCauta.id_part) poDate.id_furnizor = loCauta.id_part poDate.furnizor = Alltrim(loCauta.denumire) @@ -8970,7 +8974,9 @@ DEFINE CLASS frm_date_factura AS _frmbase OF "_frm_base.vcx" PROCEDURE do_cauta_client Local loCauta - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Clienti??cCont=>4111??lAdaugCorespondente=>1])) + loHash = GetHash([cTitlu=>Clienti??cCont=>4111??lAdaugCorespondente=>1??lVerificaANAF=>1]) + loHash.SetValue('dDataDoc', Iif(Type('poDate.dataact') = 'D', poDate.dataact, {})) + loCauta = CautPartenerContabilitate(loHash) If !Empty(Nvl(loCauta.id_part,0)) And !Empty(loCauta.denumire) If loCauta.id_part <> poDate.id_client poDate.listaid = [] diff --git a/clase/omodificari.vc2 b/clase/omodificari.vc2 index a9be3e5..bcd3e73 100644 --- a/clase/omodificari.vc2 +++ b/clase/omodificari.vc2 @@ -1607,12 +1607,17 @@ DEFINE CLASS frm_modific AS _frmbase OF "_frm_base.vcx" PROCEDURE do_cauta PARAMETERS tcCont - LOCAL loCauta + LOCAL loCauta, loHash IF EMPTY(tcCont) RETURN ENDIF - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont))) + *!* 27.07.2026 claude - verificarea ANAF la data documentului din nota, nu la data curenta + loHash = GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont) + [??lVerificaANAF=>1]) + IF USED('tact') AND INLIST(TYPE('tact.dataact'), 'D', 'T') + loHash.SetValue('dDataDoc', tact.dataact) + ENDIF + loCauta = CautPartenerContabilitate(loHash) RETURN loCauta @@ -4601,12 +4606,17 @@ DEFINE CLASS frm_modific2007 AS _frmbase OF "_frm_base.vcx" PROCEDURE do_cauta PARAMETERS tcCont - LOCAL loCauta + LOCAL loCauta, loHash IF EMPTY(NVL(tcCont,'')) RETURN ENDIF - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont))) + *!* 27.07.2026 claude - verificarea ANAF la data documentului din nota, nu la data curenta + loHash = GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont) + [??lVerificaANAF=>1]) + IF USED('tact') AND INLIST(TYPE('tact.dataact'), 'D', 'T') + loHash.SetValue('dDataDoc', tact.dataact) + ENDIF + loCauta = CautPartenerContabilitate(loHash) RETURN loCauta @@ -12613,12 +12623,17 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx" PROCEDURE do_cauta PARAMETERS tcCont - LOCAL loCauta + LOCAL loCauta, loHash IF EMPTY(NVL(tcCont,'')) RETURN ENDIF - loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont))) + *!* 27.07.2026 claude - verificarea ANAF la data documentului din nota, nu la data curenta + loHash = GetHash([cTitlu=>Alegeti partenerul??lAdaugCorespondente=>1??cCont=>] + ALLTRIM(tcCont) + [??lVerificaANAF=>1]) + IF USED('tact') AND INLIST(TYPE('tact.dataact'), 'D', 'T') + loHash.SetValue('dDataDoc', tact.dataact) + ENDIF + loCauta = CautPartenerContabilitate(loHash) RETURN loCauta diff --git a/clase/onote_contabile.vc2 b/clase/onote_contabile.vc2 index bb3ee67..5942f94 100644 --- a/clase/onote_contabile.vc2 +++ b/clase/onote_contabile.vc2 @@ -6965,6 +6965,7 @@ DEFINE CLASS frm_note_contabile2007_nou AS _frmbase OF "_frm_base.vcx" WITH loHash .SetValue("cTitlu", "Alegeþi partenerul") .SetValue("cCont", lcCont) + .SetValue("lVerificaANAF", .T.) && 26.07.2026 claude - verificare ANAF la alegerea partenerului ENDWITH loPartener = CautPartenerContabilitate(loHash) diff --git a/docs/conventie_ux_formulare.md b/docs/conventie_ux_formulare.md index e9e1c92..55a1678 100644 --- a/docs/conventie_ux_formulare.md +++ b/docs/conventie_ux_formulare.md @@ -33,6 +33,22 @@ butoane grupate la margini, fără elemente lipite unele de altele. semnificaÈ›ie clară (verde = acÈ›iune pozitivă/transmite, roÈ™u = oprire/pericol, albastru = navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`. +## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT) + +- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label, + textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din + `COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au + fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara + Arial Narrow). +- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx` — + modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce + deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei. +- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica, + Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*` + respectiva — nu se improvizeaza un buton generic pentru o actiune care are deja clasa ei. +- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din + `cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ. + ## Vocabular FuncÈ›ional, compact, aerisit, minimalist, grupat, uÈ™or de înÈ›eles de utilizatori, aer aerisit, @@ -43,6 +59,6 @@ regulile mecanice de mai sus, pe orice aplicaÈ›ie ROA*. - `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache (relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back). -- Capcana de encoding cp1252 la editarea `.sc2`/`.vc2` (corupere diacritice) — documentată în - proiectul unde a fost descoperită (ROAAUTO `docs/conventie_encoding_cp1252.md`); relevantă ori - de câte ori editezi text-cache-ul unui formular/librărie pentru a aplica aceste reguli de UX. +- `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la + editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie + pentru a aplica aceste reguli de UX. diff --git a/docs/flux-editare-vfp-text.md b/docs/flux-editare-vfp-text.md index 3794cf3..5817aea 100644 --- a/docs/flux-editare-vfp-text.md +++ b/docs/flux-editare-vfp-text.md @@ -28,7 +28,7 @@ rularea `git_sync.ps1`; restul pasilor raman la fel. Fluxul cu cache extern (`vc 3. Patch review: `git diff --no-index > docs/diff_runda_.patch` (exit 1 = normal). Utilizatorul revizuieste FISIERUL de patch si aproba; write-back-ul (pasul 5) se face DOAR dupa aprobare. Commit doar dupa confirmare pe patch + test in IDE. - Comentariile in cod: maxim o linie (`*!* DD.MM.YYYY autor - motiv scurt`), fara explicatii lungi. + Comentariile in cod: conventia din `reguli_lucru.md` (punctul 2). Obligatoriu inainte de a preda patch-ul la review: skill-ul de code-review rulat pe bucatile de cod din diff (nu doar citire manuala) - prinde defecte gen IIF cu numar gresit de argumente, deduplicari care nu se declanseaza niciodata, interogari mai largi decat e nevoie. diff --git a/docs/git_svn_parallel_init_prompt.md b/docs/git_svn_parallel_init_prompt.md deleted file mode 100644 index e0fb5cd..0000000 --- a/docs/git_svn_parallel_init_prompt.md +++ /dev/null @@ -1,86 +0,0 @@ -# Prompt: init git in paralel cu SVN pentru un proiect ROA - -Foloseste acest prompt intr-o sesiune Claude Code noua, deschisa in radacina proiectului -tinta (ex. `D:\ROA\ROAIMOB`). Functioneaza generic pentru orice proiect VFP din `D:\ROA\` -care are structura ROAACNPRO (proiect + subfolder COMUN\ partajat, ambele in SVN). - ---- - -``` -Vreau sa initializezi git pentru proiectul VFP din directorul curent, in paralel cu SVN-ul -existent (nu atinge SVN, nu rula comenzi svn, doar adauga .svn/ in .gitignore). - -Structura e identica cu D:\ROA\ROAACNPRO: acest folder e propriul proiect VFP (are un .PJX -al lui), si contine un subfolder COMUN\ care e framework-ul PARTAJAT intre toate aplicatiile -ROA, versionat separat prin SVN (are propriul .svn\). - -Fa exact ce s-a facut deja pentru ROAACNPRO (poti citi acolo ca referinta/sablon): -- D:\ROA\ROAACNPRO\.gitignore (sablon pentru .gitignore-ul proiectului principal) -- D:\ROA\ROAACNPRO\COMUN\.gitignore (sablon pentru .gitignore-ul din COMUN) -- D:\ROA\ROAACNPRO\CLAUDE.md (conventii proiect) si docs\cautare_vcx_vct.md (cum se cauta - cod in interiorul .vcx/.scx binare, via D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1) - -Pasi: - -1. Verifica intai ce exista deja: `git status`/`.git` in radacina si in COMUN\, si - `git remote -v` daca exista deja vreun remote configurat gresit (asa cum a fost cazul la - ROAACNPRO, unde originul proiectului principal pointa gresit catre repo-ul comun.git). - -2. REPO PRINCIPAL (radacina acestui folder): - - Daca nu exista .git, `git init -b main`. - - Creeaza/adapteaza .gitignore dupa modelul ROAACNPRO/.gitignore (artefacte VFP compilate: - *.fxp, *.mpx, *.bak, *.mpr, *.err, log.txt, *.tmp, *.dct, *.exe, cruft Windows), plus - obligatoriu `COMUN/` (COMUN e gestionat de git-ul lui separat, nu de-al acestui repo) - si `.svn/`. - - Deduce numele repo-ului gitea dupa conventia romfast/.git - (ex. romfast/roaimob.git). INAINTE sa creezi/pushezi orice, verifica cu - `git ls-remote git@gitea.romfast.ro:romfast/.git` daca exista deja si ce contine - (clone --depth 1 intr-un folder temporar din scratchpad daca ai dubii). Daca exista deja - cu istoric care nu se potriveste cu ce ai local, OPRESTE-TE si intreaba-ma inainte sa - faci push sau orice suprascriere. - - Daca remote-ul e gol/nou: add -A, commit "Initial commit — sursa ", adauga - origin, push normal (fara --force). - -3. COMUN\ (subfolder-ul partajat): - - Initializeaza un git SEPARAT, propriu, in interiorul COMUN\ (COMUN are propriul .git, - nu e tracked de repo-ul principal — de-asta l-am exclus mai sus). - - .gitignore propriu in COMUN\ dupa modelul ROAACNPRO/COMUN/.gitignore (artefacte VFP + - `.svn/` + `bash.exe.stackdump`). - - Origin-ul din COMUN\ trebuie sa fie EXACT acelasi repo pentru toate proiectele ROA: - git@gitea.romfast.ro:romfast/comun.git — repo-ul asta e deja populat (din COMUN-ul lui - ROAACNPRO). NU face commit+push orbeste peste el. - - Fa intai `git fetch origin`, compara continutul de pe origin/main cu fisierele locale - din acest COMUN\ (diff pe folder, nu doar pe nume). Daca sunt identice sau diferentele - sunt neglijabile, seteaza pur si simplu branch-ul local sa urmareasca origin/main (fara - sa strici fisierele din working copy SVN). Daca sunt diferente reale intre COMUN-ul - acestui proiect si cel deja impins pe gitea, arata-mi un rezumat al diferentelor si - intreaba-ma explicit cum procedez (nu face force-push fara aprobarea mea explicita — - ar sterge ireversibil istoricul comun tuturor proiectelor ROA). - -4. Cautare in cod VFP binar (.vcx/.scx) pentru acest proiect: - - Foloseste acelasi vcx2txt.ps1, dar parametrizat pentru proiectul curent (nu ROAACNPRO): - powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` - -Project D:\ROA\\.PJX -ProjectRoot D:\ROA\ ` - -CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_ - - Cache separat per proiect (nu-l amesteca cu _textcache al ROAACNPRO). Grep in cache-ul - respectiv, la fel ca in docs\cautare_vcx_vct.md. - -5. La final, adauga/actualizeaza CLAUDE.md al acestui proiect cu o sectiune scurta: git ruleaza - in paralel cu SVN legacy (SVN ramane sursa "vie" pentru COMUN, sincronizat manual catre git); - COMUN e partajat intre toate aplicatiile ROA prin acelasi git@gitea.romfast.ro:romfast/comun.git; - cautarile in .vcx/.scx se fac cu vcx2txt.ps1 parametrizat pentru acest proiect (vezi mai sus). - -Inainte de orice `push --force` sau orice operatie care ar suprascrie istoric remote deja -existent (mai ales pe romfast/comun.git, care e comun mai multor proiecte), opreste-te si -intreaba-ma explicit — nu decide singur. -``` - ---- - -## Note - -- Cel mai sensibil pas e COMUN\: daca versiunea de COMUN a noului proiect difera de cea deja - impinsa pe `comun.git` (din ROAACNPRO), Claude trebuie sa se opreasca si sa intrebe cum se - reconciliaza, nu sa faca force-push automat. -- Daca `romfast/.git` nu exista inca pe gitea, trebuie creat gol acolo inainte de push - (manual sau prin API) — altfel push-ul esueaza cu "repository not found". diff --git a/docs/reguli_lucru.md b/docs/reguli_lucru.md index b4f91da..d857f39 100644 --- a/docs/reguli_lucru.md +++ b/docs/reguli_lucru.md @@ -5,11 +5,19 @@ Write-back in binar (txt2vcx) si commit DOAR dupa aprobarea patch-ului de catre utilizator. Patch-urile sunt intermediare de review: NU se comit NICIODATA in git (sunt in .gitignore ca `docs/diff_runda*.patch`); raman doar local, pe disc. -2. Comentarii in cod: max o linie `*!* DD.MM.YYYY autor - motiv scurt`, DOAR la - functionalitati noi/schimbate. La rezolvari de erori NU se adauga comentarii. +2. Comentarii in cod: NU se pun comentarii in corpul codului (nici la functionalitati noi). + In ANTETUL fisierului se tine o singura intrare CUMULATIVA per functionalitate, in stilul + existent (`*!* DD.MM.YYYY` / `*!* autor` / `*!* ce face, 1-2 fraze`): la revenirea pe aceeasi + lucrare se rescrie intrarea, nu se adauga alta. Autorul e persoana care semneaza livrarea + (ex. `marius.mutu`) - niciodata "claude" sau alt nume de agent. + Se descrie doar comportamentul final, fara referinte la revizii, runde, patch-uri sau la + corectii facute pe parcurs. La rezolvari de erori NU se adauga comentarii deloc. Explicatiile merg in docs/ sau in mesajul de commit, nu in cod. - Changelog (`changelog_.txt`): text minimal, pe limba utilizatorului, - nu tehnic - o fraza scurta per intrare `:nou:`/`:modificare:`/`:eroare:`. + Changelog (`changelog_.txt`): text minimal, pe limba utilizatorului, nu tehnic, + o fraza scurta per intrare. Cat timp lucrarea nu a ajuns la utilizatori (fara deploy), + erorile introduse si corectate in interiorul ei NU se pomenesc - intrarea descrie + functionalitatea asa cum ajunge la utilizator, `:nou:`/`:modificare:`; `:eroare:` ramane + doar pentru erori care au fost in productie. 3. Modificari minime: doar ce s-a cerut; fara refactorizari sau curatenie din oficiu. 4. Testare headless (fara IDE): `vfp9.exe -A -T "" ` din PowerShell. Mediu, sabloane, capcane si metoda de depanare: `depanare_testare_vfp.md`. diff --git a/docs/scripturi-migrare-db.md b/docs/scripturi-migrare-db.md index c93332f..6e201ff 100644 --- a/docs/scripturi-migrare-db.md +++ b/docs/scripturi-migrare-db.md @@ -5,3 +5,14 @@ Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in `gcDirMare`/`dirgen` — ex. `D:\ROA\DATABASE\SCRIPTURI_CLAR`). Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`. Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo. + +Reguli confirmate de Marius (24.07.2026): + +- **Line-endings CRLF obligatoriu** in scripturile `.sql` — tool-urile agentului scriu + implicit LF; dupa orice scriere, verifica si converteste byte-safe LF -> CRLF (fara + decodare/reincodare). Parsarea pe fluxul ROA (ex. `ALINES` pe `CHR(13)+CHR(10)`) + esueaza silentios pe LF: tot fisierul devine un singur rand. +- `versiune_db.txt` (marker-ul `YYYY_MM_DD_NN` din radacina aplicatiei) se scrie fara + newline la final (conventia existenta). +- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu + functioneaza — foloseste `begin pachet.procedura(...); end;`. diff --git a/programe/cauta_alfa.prg b/programe/cauta_alfa.prg index 7a97c85..d6b5395 100644 --- a/programe/cauta_alfa.prg +++ b/programe/cauta_alfa.prg @@ -207,8 +207,18 @@ ENDIF Endif .cIdColumn = lcIdColumn Endwith + + If Type('poVerifAlegere') = 'O' And !Isnull(poVerifAlegere) + AddProperty(oForm_cautare, 'oVerifAlegere', poVerifAlegere) + poVerifAlegere.Activeaza(oForm_cautare) + Endif + oForm_cautare.Show() + If Type('poVerifAlegere') = 'O' And !Isnull(poVerifAlegere) + poVerifAlegere.Dezactiveaza() + Endif + *!* modificare 30.11.2006 If Type("lorec") = "O" poRec = lorec diff --git a/programe/ocautare.prg b/programe/ocautare.prg index a5c9ffe..36ffebd 100644 --- a/programe/ocautare.prg +++ b/programe/ocautare.prg @@ -39,9 +39,762 @@ *!* marius.mutu *!* caut_client_contract_activ - nu se iau contracte active de pe clienti inactivi +*!* 26.07.2026 +*!* marius.mutu +*!* verificare ANAF la alegerea partenerului: starea la data documentului si codul fiscal invalid pe randul curent +*!* din formularul de cautare, detalii si alegerea variantei corecte cu F4, optiunea RC_ANAF_VERIF_SELECTIE + *!* #DEFINE CRLF CHR(13) + CHR(10) #INCLUDE COMUN\ROA.H +Procedure ANAF_StarePartener + Lparameters tcCodFiscal, tdData + + Local lcCodFiscal, lcCodTara, lcCui, loVerificareCod, loRezANAF, lcCheieCache, lnI, llValid, loOut, ldData + + *** guard mediu partajat - ocautare.prg e inclus si de alte produse ROA fara validare.prg/goLog incarcate + If !('VALIDARE' $ Upper(Set('Procedure'))) Or Type('goLog') <> 'O' + Return .Null. + Endif + lcCodFiscal = Alltrim(Nvl(m.tcCodFiscal, '')) + If Empty(m.lcCodFiscal) + Return .Null. + Endif + *** excludere parteneri externi (COD_TARA <> RO) + loVerificareCod = Createobject("VerificareCod") + lcCodTara = loVerificareCod.GetCodTara(m.lcCodFiscal) + If m.lcCodTara <> 'RO' + Return .Null. + Endif + *** normalizare + excludere persoane fizice (CNP 13 cifre) / coduri nenumerice dupa eliminarea RO + lcCui = NormalizeazaCUI(m.lcCodFiscal) + llValid = !Empty(m.lcCui) + If m.llValid + For lnI = 1 To Len(m.lcCui) + If !Isdigit(Substr(m.lcCui, lnI, 1)) + llValid = .F. + Exit + Endif + Endfor + Endif + If !m.llValid Or Len(m.lcCui) = 13 + Return .Null. + Endif + ldData = ANAF_CaData(m.tdData) + If Empty(m.ldData) And Type('poAct.dataact') $ 'DT' + ldData = ANAF_CaData(poAct.dataact) + Endif + If Empty(m.ldData) + ldData = Date() + Endif + *** cache pe sesiune (cheie = CUI normalizat + data verificarii) + apel ANAF (wrapper single-CUI, validare.prg), fara Wait Window + If Type('goCacheANAF_Sesiune') <> 'O' + Public goCacheANAF_Sesiune + goCacheANAF_Sesiune = Createobject('Collection') + Endif + lcCheieCache = 'C' + m.lcCui + '_' + Dtos(m.ldData) + If goCacheANAF_Sesiune.GetKey(m.lcCheieCache) = 0 + loRezANAF = ANAF_VerificaCuiSingle(m.lcCui, m.ldData) + goCacheANAF_Sesiune.Add(Iif(Vartype(m.loRezANAF) = 'O', m.loRezANAF, .F.), m.lcCheieCache) + Else + loRezANAF = goCacheANAF_Sesiune.Item(m.lcCheieCache) + Endif + If Vartype(m.loRezANAF) <> 'O' + Return .Null. && fara raspuns/CUI negasit -> degradare tacuta + Endif + *** verdict + loOut = Createobject("Empty") + Addproperty(loOut, "cCui", m.lcCui) + Addproperty(loOut, "lAreRO", Left(Upper(Alltrim(m.lcCodFiscal)), 2) = 'RO') + Addproperty(loOut, "lPlatitorANAF", loRezANAF.scpTVA) + Addproperty(loOut, "lInactivANAF", loRezANAF.statusInactivi) + Addproperty(loOut, "cDenumireANAF", Alltrim(Nvl(loRezANAF.denumire, ''))) + Addproperty(loOut, "lDiscordanta", (loRezANAF.scpTVA <> loOut.lAreRO) Or loRezANAF.statusInactivi) + Addproperty(loOut, "dData", m.ldData) + Return loOut +Endproc && ANAF_StarePartener + +Procedure ANAF_ValidareCod + Lparameters tcCodFiscal, tnTipPersoana + + Local lcCodFiscal, lcCui, loVerificareCod, lnTipPersoana, llCnp + If !('VALIDARE' $ Upper(Set('Procedure'))) + Return '' + Endif + lcCodFiscal = Alltrim(Nvl(m.tcCodFiscal, '')) + If Empty(m.lcCodFiscal) + Return '' + Endif + loVerificareCod = Createobject("VerificareCod") + If loVerificareCod.GetCodTara(m.lcCodFiscal) <> 'RO' + Return '' + Endif + lcCui = NormalizeazaCUI(m.lcCodFiscal) + lnTipPersoana = Nvl(m.tnTipPersoana, 0) + llCnp = Iif(m.lnTipPersoana = 2, .T., Iif(m.lnTipPersoana = 1, .F., Len(m.lcCui) = 13)) + If m.llCnp + Return Iif(loVerificareCod.VALIDARE_CNP(m.lcCui), '', 'CNP invalid (' + m.lcCui + ')') + Endif + Return Iif(loVerificareCod.VALIDARE_CIF(m.lcCui), '', 'CIF invalid (' + m.lcCui + ')') +Endproc && ANAF_ValidareCod + +Procedure ANAF_CaData + *** data documentului poate veni si ca DateTime (ex. tact.dataact din note contabile) + Lparameters tuValoare + Do Case + Case Vartype(m.tuValoare) = 'D' + Return m.tuValoare + Case Vartype(m.tuValoare) = 'T' + Return Ttod(m.tuValoare) + Otherwise + Return {} + Endcase +Endproc && ANAF_CaData + +Procedure ANAF_NivelVerificare + *** cascada RC_ANAF_VERIF_SELECTIE: 0=oprit, 1=verdict pe rand (implicit), 2=rezervat (tratat ca 1), 3=verdict+confirmare + Local lcSel, lcCheie, lnNivel, lcVal + + *** kill-switch - doar valoarea explicita '0' opreste; absenta NU seteaza nivelul + If Alltrim(Nvl(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) == '0' + Return 0 + Endif + + *** cache pe sesiune - cheia (schema + utilizator) invalideaza automat la schimbarea firmei/utilizatorului + lcCheie = 'N' + Iif(Type('gcS') = 'C', gcS, '') + '_' + Iif(Type('gnIdUtil') = 'N', Transform(gnIdUtil), '') + If Type('goCacheANAF_Nivel') <> 'O' + Public goCacheANAF_Nivel + goCacheANAF_Nivel = Createobject('Collection') + Endif + If goCacheANAF_Nivel.GetKey(m.lcCheie) <> 0 + Return goCacheANAF_Nivel.Item(m.lcCheie) + Endif + + lnNivel = 1 + lcSel = Select() + If 'OINIT_OPTIUNI' $ Upper(Set('Procedure')) + lcVal = Iif(Used('crsOptiuniUtilizator'), Alltrim(Nvl(citeste_optiune_utilizator('RC_ANAF_VERIF_SELECTIE'), '')), '') + If Empty(m.lcVal) And Used('crsOptiuni') + lcVal = Alltrim(Nvl(citeste_optiune('RC_ANAF_VERIF_SELECTIE'), '')) + Endif + If !Empty(m.lcVal) + lnNivel = Int(Val(m.lcVal)) + Endif + Endif + Select (m.lcSel) + + goCacheANAF_Nivel.Add(m.lnNivel, m.lcCheie) + Return m.lnNivel +Endproc && ANAF_NivelVerificare + +Procedure ANAF_CautaPereche + Lparameters tcCui, tcCursor + + Local lcSelect, lnSucces + lcSelect = [SELECT ID_PART, DENUMIRE, COD_FISCAL, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE STERS = 0 AND (UPPER(REPLACE(COD_FISCAL,' ','')) = '] + m.tcCui + [' ] + ; + [OR UPPER(REPLACE(COD_FISCAL,' ','')) = 'RO] + m.tcCui + [') ORDER BY UPPER(DENUMIRE), ID_PART] + If Used(m.tcCursor) + Use In (m.tcCursor) + Endif + lnSucces = goExecutor.oExecute(m.lcSelect, m.tcCursor) + If m.lnSucces < 0 + goLog.Log('ANAF_CautaPereche: ' + goExecutor.cEroare, 'ANAF_CautaPereche') + If Used(m.tcCursor) + Use In (m.tcCursor) + Endif + Return .F. && degradare tacuta + Endif + Return .T. +Endproc && ANAF_CautaPereche + +Procedure AplicaInlocuirePartenerANAF + Lparameters toPartener, toInlocuire, tcTipuriParteneri + + Local lnRecCnt + If Vartype(m.toInlocuire) <> 'O' Or Isnull(m.toPartener) Or Type('toPartener.id_part') <> 'N' + Return + Endif + toPartener.id_part = toInlocuire.nIdPart + If Type('toPartener.denumire') = 'C' + toPartener.denumire = toInlocuire.cDenumire + Endif + If Type('toPartener.nume') = 'C' + toPartener.nume = toInlocuire.cDenumire + Endif + toPartener.cod_fiscal = toInlocuire.cCodFiscal + *** recalculeaza tip pentru id-ul perechii, acelasi criteriu ca SELECT-ul gridului (coresp_tip_part) + If Type('toPartener.tip') = 'N' And !Empty(Nvl(m.tcTipuriParteneri, '')) + lnRecCnt = 0 + goExecutor.oSelect2Value([SELECT COUNT(*) AS NR FROM CORESP_TIP_PART WHERE ID_PART = ] + Transform(toInlocuire.nIdPart) + ; + [ AND ID_TIP_PART IN (] + m.tcTipuriParteneri + [)], @lnRecCnt) + toPartener.tip = Iif(Nvl(m.lnRecCnt, 0) > 0, 0, 1) + Endif + goLog.Log('ANAF: inlocuire partener -> id_part=' + Transform(toInlocuire.nIdPart), 'AplicaInlocuirePartenerANAF') +Endproc && AplicaInlocuirePartenerANAF + +Procedure ANAF_ComutaVerificare + *** valori: 0 = oprit, 1 = starea pe randul curent, 3 = starea si confirmarea la partener discordant, 9 = oprit pe acest calculator + Local lcSel, lcOptiune, lcEticheta, lcValIni, lcValUtil, lcValFirma, lcSursa, lnNivel, lnNou, lcMesaj + + lcEticheta = 'Verificare ANAF la alegerea partenerului' + lcOptiune = 'RC_ANAF_VERIF_SELECTIE' + lcSel = Select() + lcValIni = Alltrim(Nvl(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) + lcValUtil = '' + lcValFirma = '' + If 'OINIT_OPTIUNI' $ Upper(Set('Procedure')) + lcValUtil = Iif(Used('crsOptiuniUtilizator'), Alltrim(Nvl(citeste_optiune_utilizator(m.lcOptiune), '')), '') + lcValFirma = Iif(Used('crsOptiuni'), Alltrim(Nvl(citeste_optiune(m.lcOptiune), '')), '') + Endif + Select (m.lcSel) + + lnNivel = ANAF_NivelVerificare() + Do Case + Case m.lcValIni == '0' + lcSursa = 'oprita pe acest calculator (settings.ini)' + Case !Empty(m.lcValUtil) + lcSursa = 'setata pentru utilizatorul curent' + Case !Empty(m.lcValFirma) + lcSursa = 'setata pentru firma' + Otherwise + lcSursa = 'implicita' + Endcase + + lcMesaj = 'Acum: ' + Transform(m.lnNivel) + ' - ' + ANAF_TextNivel(m.lnNivel) + Chr(13) + ; + '(' + m.lcSursa + ')' + Chr(13) + Chr(13) + ; + ' 0 = ' + ANAF_TextNivel(0) + Chr(13) + ; + ' 1 = ' + ANAF_TextNivel(1) + Chr(13) + ; + ' 3 = ' + ANAF_TextNivel(3) + Chr(13) + ; + ' 9 = ' + ANAF_TextNivel(9) + Chr(13) + Chr(13) + ; + 'Valorile 0, 1 si 3 va urmaresc pe orice calculator.' + Amessagebox(m.lcMesaj, 0 + 64, lcEticheta) + lnNou = aInputBox('Valoarea noua (0, 1, 3 sau 9):', m.lcEticheta, m.lnNivel) + If Vartype(m.lnNou) <> 'N' Or !Inlist(m.lnNou, 0, 1, 3, 9) + Return + Endif + + If m.lnNou = 9 + setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '0') + Else + If m.lcValIni == '0' + setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '1') + Endif + If !('OINIT_OPTIUNI' $ Upper(Set('Procedure'))) Or !Used('crsOptiuniUtilizator') + Amessagebox('Optiunea nu poate fi salvata: lipseste lista de optiuni ale utilizatorului.', 0 + 48, lcEticheta) + Return + Endif + lcSel = Select() + scrie_optiune_utilizator(m.lcOptiune, Alltrim(Str(m.lnNou)), 'VERIFICARE ANAF LA ALEGEREA PARTENERULUI') + Select (m.lcSel) + Endif + If Type('goCacheANAF_Nivel') = 'O' + Release goCacheANAF_Nivel + Endif +Endproc && ANAF_ComutaVerificare + +Procedure ANAF_TextNivel + Lparameters tnNivel + Do Case + Case m.tnNivel = 0 + Return 'fara verificare' + Case m.tnNivel = 9 + Return 'oprita pe acest calculator, pentru toti utilizatorii lui' + Case m.tnNivel >= 3 + Return 'arata starea si intreaba la alegerea unui partener discordant' + Otherwise + Return 'arata starea partenerului la ANAF pe randul curent' + Endcase +Endproc && ANAF_TextNivel + +DEFINE CLASS anaf_timer AS Timer + oOwner = .Null. + Interval = 400 + Enabled = .F. + + PROCEDURE Timer + This.Enabled = .F. + If Vartype(This.oOwner) = 'O' + This.oOwner.VerificaRand(.F.) + Endif + ENDPROC +ENDDEFINE + +DEFINE CLASS anaf_label AS Label + FontName = 'Arial' + FontSize = 10 + BackStyle = 0 +ENDDEFINE + +DEFINE CLASS anaf_verif_cautare AS Custom + oForm = .Null. + oTimer = .Null. + nIdPart = 0 + oStare = .Null. + cCui = '' + dDataDoc = {} + oCandidati = .Null. + nNivel = 1 + lDecis = .F. && 27.07.2026 claude - decizia a fost deja luata in Detalii + + PROCEDURE Activeaza + Lparameters toForm + Local lcCursor, llCreat + If Vartype(m.toForm) <> 'O' Or toForm.lAles + Return + Endif + lcCursor = toForm.crs_cursor + If !Used(m.lcCursor) Or Type(m.lcCursor + '.cod_fiscal') <> 'C' Or Type(m.lcCursor + '.id_part') <> 'N' + Return + Endif + llCreat = .F. + Try + toForm.NewObject('lb_anaf', '_label', '_baza.vcx') + llCreat = .T. + Catch + llCreat = .F. + Endtry + If !m.llCreat + Try + toForm.AddObject('lb_anaf', 'anaf_label') + llCreat = .T. + Catch + llCreat = .F. + Endtry + Endif + If !m.llCreat + Return + Endif + This.oForm = toForm + This.oTimer = Createobject('anaf_timer') + This.oTimer.oOwner = This + *!* 27.07.2026 claude - banda proprie sub grid, inalta cat doua linii de label + If Type('toForm._GRID1') = 'O' And Bitand(toForm._GRID1.Anchor, 8) = 8 + toForm._GRID1.Anchor = toForm._GRID1.Anchor - 8 && inaltimea gridului o dau eu, in AjusteazaBanda + Endif + toForm.Height = toForm.Height + 54 + With toForm.lb_anaf + .AutoSize = .F. + .BackStyle = 0 + .WordWrap = .T. + .MousePointer = 15 + .Left = 8 + .Width = toForm.Width - 20 + .Height = 46 + .Top = toForm.Height - 50 + .Caption = '' + .Visible = .T. + .Anchor = 14 + Endwith + Bindevent(toForm.lb_anaf, 'Click', This, 'Detalii') + Bindevent(toForm, 'Resize', This, 'AjusteazaBanda') + Bindevent(toForm, 'Activate', This, 'AjusteazaBanda') + This.AjusteazaBanda() + Bindevent(toForm._GRID1, 'AfterRowColChange', This, 'DupaRand') + ENDPROC + + PROCEDURE AjusteazaBanda + *** gridul ramane ancorat jos; il opresc doar sa intre peste banda labelului + Local lnMax + If Vartype(This.oForm) <> 'O' Or Type('This.oForm._GRID1') <> 'O' + Return + Endif + If Bitand(This.oForm._GRID1.Anchor, 8) = 8 + This.oForm._GRID1.Anchor = This.oForm._GRID1.Anchor - 8 + Endif + lnMax = This.oForm.Height - 58 - This.oForm._GRID1.Top + If m.lnMax > 60 + This.oForm._GRID1.Height = m.lnMax + Endif + ENDPROC + + PROCEDURE Dezactiveaza + If Vartype(This.oTimer) = 'O' + This.oTimer.Enabled = .F. + This.oTimer.oOwner = .Null. + This.oTimer = .Null. + Endif + If Vartype(This.oForm) = 'O' + Try + Unbindevents(This.oForm, 'Resize', This, 'AjusteazaBanda') + Unbindevents(This.oForm, 'Activate', This, 'AjusteazaBanda') + Catch + Endtry + If Type('This.oForm.lb_anaf') = 'O' + Try + Unbindevents(This.oForm.lb_anaf) + Catch + Endtry + Endif + If Type('This.oForm._GRID1') = 'O' + Try + Unbindevents(This.oForm._GRID1) + Catch + Endtry + Endif + Endif + This.oForm = .Null. + ENDPROC + + PROCEDURE DupaRand + Lparameters nColIndex + If Vartype(This.oTimer) = 'O' + This.oTimer.Enabled = .F. + This.oTimer.Enabled = .T. + Endif + ENDPROC + + PROCEDURE VerificaRand + Lparameters tlSincron + Local lcCursor, lnId, lcCodFiscal, loStare, lnTipPersoana, lcCodInvalid + If Vartype(This.oForm) <> 'O' + Return .F. + Endif + If Vartype(This.oTimer) = 'O' + This.oTimer.Enabled = .F. + Endif + lcCursor = This.oForm.crs_cursor + If !Used(m.lcCursor) Or Reccount(m.lcCursor) = 0 + This.SeteazaLabel('', .F.) + This.nIdPart = 0 + This.oStare = .Null. + This.cCui = '' + Return .F. + Endif + lnId = Nvl(Evaluate(m.lcCursor + '.id_part'), 0) + lcCodFiscal = Alltrim(Nvl(Evaluate(m.lcCursor + '.cod_fiscal'), '')) + If m.lnId = 0 + This.SeteazaLabel('', .F.) + Return .F. + Endif + If m.lnId = This.nIdPart + Return !Isnull(This.oStare) + Endif + lnTipPersoana = Iif(Type(m.lcCursor + '.tip_persoana') = 'N', Nvl(Evaluate(m.lcCursor + '.tip_persoana'), 0), 0) + lcCodInvalid = ANAF_ValidareCod(m.lcCodFiscal, m.lnTipPersoana) + If !Empty(m.lcCodInvalid) + This.nIdPart = m.lnId + This.oStare = .Null. + This.cCui = '' + This.SeteazaLabel(m.lcCodInvalid + ' (F4 = detalii)', .T.) + goLog.Log('Cod fiscal invalid: ' + m.lcCodInvalid + ' id_part=' + Transform(m.lnId), 'anaf_verif_cautare') + Return .F. + Endif + This.SeteazaLabel('Verificare ANAF...', .F.) + loStare = ANAF_StarePartener(m.lcCodFiscal, This.dDataDoc) + This.nIdPart = m.lnId + This.oStare = m.loStare + This.cCui = Iif(Isnull(m.loStare), '', loStare.cCui) + Do Case + Case Isnull(m.loStare) + This.SeteazaLabel('', .F.) + Return .F. + Case !loStare.lDiscordanta + This.SeteazaLabel(This.TextAnaf(m.loStare, .F., 24) + ' (F4 = detalii)', .F.) + Otherwise + This.SeteazaLabel(This.TextAnaf(m.loStare, .F., 24) + ' (F4 = detalii)', .T.) + goLog.Log('Discordanta ANAF: CUI=' + loStare.cCui + ' id_part=' + Transform(m.lnId) + ; + ' scpTVA=' + Transform(loStare.lPlatitorANAF) + ' inactivANAF=' + Transform(loStare.lInactivANAF), 'anaf_verif_cautare') + Endcase + Return .T. + ENDPROC + + PROCEDURE SeteazaLabel + Lparameters tcText, tlAvertisment + If Vartype(This.oForm) <> 'O' + Return + Endif + With This.oForm.lb_anaf + .Caption = m.tcText + .ForeColor = Iif(m.tlAvertisment, Rgb(192, 0, 0), Rgb(0, 128, 0)) + .FontBold = m.tlAvertisment + Endwith + This.oForm.lb_anaf.Refresh() + ENDPROC + + PROCEDURE TextStare + Lparameters toStare + Return Iif(toStare.lPlatitorANAF, 'Platitor TVA', 'Neplatitor TVA') + Iif(toStare.lInactivANAF, ' (inactiv la ANAF)', '') + ENDPROC + + PROCEDURE TextAnaf + Lparameters toStare, tlCuVirgula, tnMaxLen + Local lcCodOk, lcDenANAF, lcDenFull + lcCodOk = Iif(toStare.lPlatitorANAF, 'RO', '') + toStare.cCui + lcDenFull = Alltrim(Nvl(toStare.cDenumireANAF, '')) + lcDenANAF = lcDenFull + If Vartype(m.tnMaxLen) = 'N' And m.tnMaxLen > 0 And Len(m.lcDenFull) > m.tnMaxLen + lcDenANAF = Left(m.lcDenFull, m.tnMaxLen) + '...' + Endif + Return 'ANAF: ' + This.TextStare(toStare) + ' (' + ; + Iif(Empty(m.lcDenANAF), '', m.lcDenANAF + Iif(m.tlCuVirgula, ', ', ' ')) + m.lcCodOk + ')' + ; + ' la ' + Dtoc(toStare.dData) + ENDPROC + + PROCEDURE AntetDialog + Lparameters tcDenAles, tcCodAles + Local lcAntet + lcAntet = Alltrim(m.tcDenAles) + ' (CUI: ' + Alltrim(m.tcCodAles) + ', ID: ' + Transform(This.nIdPart) + ')' + Chr(13) + Chr(13) + If !Isnull(This.oStare) + lcAntet = m.lcAntet + This.TextAnaf(This.oStare, .T.) + Chr(13) + Chr(13) + Endif + Return m.lcAntet + ENDPROC + + PROCEDURE ListaCorecti + Lparameters tnCandidati, tnCandidat, tcDenPereche, tlEroare + Local lcCursorP, lcLista, lcCodOk, loCandidat + lcCodOk = Iif(This.oStare.lPlatitorANAF, 'RO', '') + This.cCui + lcLista = '' + tnCandidati = 0 + tnCandidat = 0 + tcDenPereche = '' + tlEroare = .F. + This.oCandidati = Createobject('Collection') + lcCursorP = Sys(2015) + If ANAF_CautaPereche(This.cCui, m.lcCursorP) + Select (m.lcCursorP) + Scan For Chrtran(Upper(Alltrim(Nvl(cod_fiscal, ''))), ' ', '') == Upper(m.lcCodOk) And id_part <> This.nIdPart + tnCandidati = m.tnCandidati + 1 + lcLista = m.lcLista + ' ' + Transform(m.tnCandidati) + '. ' + Alltrim(Nvl(denumire, '')) + ; + ' (ID: ' + Transform(id_part) + ')' + Iif(Nvl(inactiv, 0) = 1, ' inactiv', '') + Chr(13) + loCandidat = Createobject('Empty') + Addproperty(loCandidat, 'nIdPart', id_part) + Addproperty(loCandidat, 'cDenumire', Alltrim(Nvl(denumire, ''))) + Addproperty(loCandidat, 'lInactiv', Nvl(inactiv, 0) = 1) + Addproperty(loCandidat, 'lAreDocumente', .F.) + This.oCandidati.Add(loCandidat) + If m.tnCandidati = 1 + tnCandidat = id_part + tcDenPereche = Alltrim(Nvl(denumire, '')) + Endif + Endscan + Use In (m.lcCursorP) + Else + tlEroare = .T. + Endif + Return m.lcLista + ENDPROC + + PROCEDURE MarcheazaDocumente + *** discriminator "are documente in perioada" - un singur SELECT, apelat doar din Detalii + Local lcSirId, lcCursorD, lnI, loCand + If Vartype(This.oCandidati) <> 'O' Or This.oCandidati.Count = 0 Or Type('gnAn') <> 'N' Or Type('gnLuna') <> 'N' + Return + Endif + lcSirId = '' + For lnI = 1 To This.oCandidati.Count + lcSirId = m.lcSirId + Iif(Empty(m.lcSirId), '', ',') + Transform(This.oCandidati.Item(m.lnI).nIdPart) + Endfor + lcCursorD = Sys(2015) + If goExecutor.oExecute([SELECT DISTINCT ID_PART FROM IREG_PARTENERI WHERE AN = ] + Transform(gnAn) + ; + [ AND LUNA = ] + Transform(gnLuna) + [ AND ID_PART IN (] + m.lcSirId + [)], m.lcCursorD) < 0 + goLog.Log('MarcheazaDocumente: ' + goExecutor.cEroare, 'anaf_verif_cautare') + If Used(m.lcCursorD) + Use In (m.lcCursorD) + Endif + Return + Endif + Select (m.lcCursorD) + Scan + For lnI = 1 To This.oCandidati.Count + loCand = This.oCandidati.Item(m.lnI) + If loCand.nIdPart = id_part + loCand.lAreDocumente = .T. + Endif + Endfor + Endscan + Use In (m.lcCursorD) + ENDPROC + + PROCEDURE TextListaCandidati + Local lcLista, lnI, loCand + lcLista = '' + If Vartype(This.oCandidati) = 'O' + For lnI = 1 To This.oCandidati.Count + loCand = This.oCandidati.Item(m.lnI) + lcLista = m.lcLista + ' ' + Transform(m.lnI) + '. ' + Alltrim(loCand.cDenumire) + ; + ' (ID: ' + Transform(loCand.nIdPart) + ')' + Iif(loCand.lInactiv, ' inactiv', '') + ; + Iif(loCand.lAreDocumente, ' are documente in perioada', '') + Chr(13) + Endfor + Endif + Return m.lcLista + ENDPROC + + PROCEDURE Detalii + Local lcCursor, lcDenAles, lcCodAles, lcCodOk, lcLista, lcMesaj, lnCandidati, lnCandidat, lcDenPereche + Local lnRasp, lnAles, loAles, llEroare + If Vartype(This.oForm) <> 'O' + Return + Endif + poANAFInlocuire = .Null. + + lcCursor = This.oForm.crs_cursor + lcDenAles = Alltrim(Nvl(Evaluate(m.lcCursor + '.denumire'), Nvl(Evaluate(m.lcCursor + '.nume'), ''))) + lcCodAles = Alltrim(Nvl(Evaluate(m.lcCursor + '.cod_fiscal'), '')) + + If Isnull(This.oStare) + Amessagebox(This.AntetDialog(m.lcDenAles, m.lcCodAles) + 'ANAF nu a raspuns - verificarea a fost sarita.', ; + 0 + 64, 'Verificare partener ANAF') + Return + Endif + + lcCodOk = Iif(This.oStare.lPlatitorANAF, 'RO', '') + This.cCui + lnCandidati = 0 + lnCandidat = 0 + lcDenPereche = '' + llEroare = .F. + This.ListaCorecti(@lnCandidati, @lnCandidat, @lcDenPereche, @llEroare) + + If m.llEroare + Amessagebox(This.AntetDialog(m.lcDenAles, m.lcCodAles) + 'Nu s-a putut citi lista de parteneri.', ; + 0 + 64, 'Verificare partener ANAF') + Return + Endif + + If m.lnCandidati = 0 + Amessagebox(This.AntetDialog(m.lcDenAles, m.lcCodAles) + ; + 'Nu exista partener cu CUI ' + m.lcCodOk + ' (il puteti crea cu butonul Nou).', 0 + 64, 'Verificare partener ANAF') + Return + Endif + + This.MarcheazaDocumente() + lcLista = This.TextListaCandidati() + lcMesaj = This.AntetDialog(m.lcDenAles, m.lcCodAles) + 'Parteneri ROA cu CUI ' + m.lcCodOk + ':' + Chr(13) + m.lcLista + Chr(13) + ; + 'Da = Pastreaza selectia' + Chr(13) + ; + Iif(m.lnCandidati = 1, 'Nu = Alege 1 ' + m.lcDenPereche + ' (ID: ' + Transform(m.lnCandidat) + ')', ; + 'Nu = Alege din lista (1-' + Transform(m.lnCandidati) + ')') + Chr(13) + ; + 'Abandon = Renunta' + Do While .T. + lnRasp = Amessagebox(m.lcMesaj, 3 + 48, 'Verificare partener ANAF') + Do Case + Case m.lnRasp = 7 && Nu - alege alt partener din lista + lnAles = 1 + If m.lnCandidati > 1 + lnAles = aInputBox('Numarul variantei (1-' + Transform(m.lnCandidati) + ')', 'Verificare ANAF', 1) + If Vartype(m.lnAles) <> 'N' Or m.lnAles < 1 Or m.lnAles > m.lnCandidati + Loop + Endif + Endif + loAles = This.oCandidati.Item(m.lnAles) + poANAFInlocuire = Createobject('Empty') + Addproperty(poANAFInlocuire, 'nIdPart', loAles.nIdPart) + Addproperty(poANAFInlocuire, 'cDenumire', loAles.cDenumire) + Addproperty(poANAFInlocuire, 'cCodFiscal', m.lcCodOk) + goLog.Log('Decizie ANAF (Detalii): ALEGE PERECHEA id_part=' + Transform(loAles.nIdPart), 'anaf_verif_cautare') + This.lDecis = .T. + Exit + Case m.lnRasp = 6 && Da - pastreaza selectia curenta + goLog.Log('Decizie ANAF (Detalii): CONTINUA CU ALEGEREA', 'anaf_verif_cautare') + This.lDecis = .T. + Exit + Otherwise && Abandon - renunta la alegerea unei variante + poANAFInlocuire = .Null. + goLog.Log('Decizie ANAF (Detalii): RENUNTA', 'anaf_verif_cautare') + Exit + Endcase + Enddo + *!* 27.07.2026 claude - dupa Da/Nu se inchide cautarea, ca sa revina in formular cu partenerul ales + If (m.lnRasp = 6 Or m.lnRasp = 7) And Pemstatus(This.oForm, 'do_termin', 5) + This.oForm.do_termin() + Endif + ENDPROC + + PROCEDURE VerificaAlegere + Lparameters toForm + Local lcCursor, lcDenAles, lcCodAles, lcCodOk, lnCandidati, lnCandidat, lcDenPereche + Local lcLista, lcMesaj, lnRasp, lnAles, loAles, llEroare, lnIdCurent + + If Vartype(This.oForm) <> 'O' + Return .T. + Endif + If This.lDecis + Return .T. + Endif + + If This.nNivel < 3 + *** nivel 1/2: fara apel ANAF nou - se logheaza doar starea deja cunoscuta din navigarea prin grid + lcCursor = This.oForm.crs_cursor + If Used(m.lcCursor) And Reccount(m.lcCursor) > 0 + lnIdCurent = Nvl(Evaluate(m.lcCursor + '.id_part'), 0) + If m.lnIdCurent = This.nIdPart And !Isnull(This.oStare) And This.oStare.lDiscordanta + goLog.Log('Alegere partener discordant ANAF (fara confirmare): CUI=' + This.cCui + ' id_part=' + Transform(This.nIdPart) + ; + ' scpTVA=' + Transform(This.oStare.lPlatitorANAF) + ' inactivANAF=' + Transform(This.oStare.lInactivANAF), 'anaf_verif_cautare') + Endif + Endif + Return .T. + Endif + + *** nivel 3: comportamentul de azi, neschimbat (verificare sincrona + confirmare) + If !This.VerificaRand(.T.) + Return .T. + Endif + If Isnull(This.oStare) Or !This.oStare.lDiscordanta + Return .T. + Endif + + lcCursor = This.oForm.crs_cursor + lcDenAles = Alltrim(Nvl(Evaluate(m.lcCursor + '.denumire'), Nvl(Evaluate(m.lcCursor + '.nume'), ''))) + lcCodAles = Alltrim(Nvl(Evaluate(m.lcCursor + '.cod_fiscal'), '')) + lcCodOk = Iif(This.oStare.lPlatitorANAF, 'RO', '') + This.cCui + + lnCandidati = 0 + lnCandidat = 0 + lcDenPereche = '' + llEroare = .F. + lcLista = This.ListaCorecti(@lnCandidati, @lnCandidat, @lcDenPereche, @llEroare) + + lcMesaj = This.AntetDialog(m.lcDenAles, m.lcCodAles) + If m.llEroare + lcMesaj = m.lcMesaj + 'Nu s-a putut citi lista de parteneri.' + Chr(13) + Chr(13) + ; + 'De acord = Pastreaza selectia' + Chr(13) + ; + 'Abandon = Inapoi la cautare' + lnRasp = Amessagebox(m.lcMesaj, 1 + 48, 'Verificare ANAF') + goLog.Log('Decizie ANAF (lista indisponibila): rasp=' + Transform(m.lnRasp), 'anaf_verif_cautare') + Return (m.lnRasp = 1) + Endif + If m.lnCandidati = 0 + lcMesaj = m.lcMesaj + 'Nu exista partener cu CUI ' + m.lcCodOk + ' (il puteti crea cu butonul Nou).' + Chr(13) + Chr(13) + ; + 'De acord = Pastreaza selectia' + Chr(13) + ; + 'Abandon = Inapoi la cautare' + lnRasp = Amessagebox(m.lcMesaj, 1 + 48, 'Verificare ANAF') + goLog.Log('Decizie ANAF (fara pereche): rasp=' + Transform(m.lnRasp), 'anaf_verif_cautare') + Return (m.lnRasp = 1) + Endif + lcMesaj = m.lcMesaj + 'Parteneri ROA cu CUI ' + m.lcCodOk + ':' + Chr(13) + m.lcLista + Chr(13) + ; + 'Da = Pastreaza selectia' + Chr(13) + ; + Iif(m.lnCandidati = 1, 'Nu = Alege 1 ' + m.lcDenPereche + ' (ID: ' + Transform(m.lnCandidat) + ')', ; + 'Nu = Alege din lista (1-' + Transform(m.lnCandidati) + ')') + Chr(13) + ; + 'Abandon = Inapoi la cautare' + Do While .T. + lnRasp = Amessagebox(m.lcMesaj, 3 + 48, 'Verificare ANAF') + Do Case + Case m.lnRasp = 7 && Nu - alternativa cu cod fiscal corect (numarul cerut daca sunt mai multe) + lnAles = 1 + If m.lnCandidati > 1 + lnAles = aInputBox('Numarul variantei (1-' + Transform(m.lnCandidati) + ')', 'Verificare ANAF', 1) + If Vartype(m.lnAles) <> 'N' Or m.lnAles < 1 Or m.lnAles > m.lnCandidati + Loop + Endif + Endif + loAles = This.oCandidati.Item(m.lnAles) + poANAFInlocuire = Createobject('Empty') + Addproperty(poANAFInlocuire, 'nIdPart', loAles.nIdPart) + Addproperty(poANAFInlocuire, 'cDenumire', loAles.cDenumire) + Addproperty(poANAFInlocuire, 'cCodFiscal', m.lcCodOk) + goLog.Log('Decizie ANAF: ALEGE PERECHEA id_part=' + Transform(loAles.nIdPart), 'anaf_verif_cautare') + Return .T. + Case m.lnRasp = 6 && Da - continua cu selectia curenta + goLog.Log('Decizie ANAF: CONTINUA CU ALEGEREA', 'anaf_verif_cautare') + Return .T. + Otherwise && Abandon - inapoi la cautare + goLog.Log('Decizie ANAF: RAMAI IN CAUTARE', 'anaf_verif_cautare') + Return .F. + Endcase + Enddo + ENDPROC +ENDDEFINE + ************************************************************************************************************************ * CautPartenerContabilitate(cTitlu, cTipuriParteneri) * Date : 04/10/2006 @@ -63,6 +816,7 @@ Procedure CautPartenerContabilitate Local loHash As MyHash, lcSelect, lcTitlu, lcTipuriParteneri, lnSucces, llAllInList, lnPornire, lcFiltruOrig, lcNumeProcedura, llAdaugCorespondente + Local lVerificaANAF, ldDataDoc, lnNivelANAF *!* parametrii lcTitlu = toHash.GetValue("cTitlu") @@ -73,6 +827,8 @@ Procedure CautPartenerContabilitate lcFiltruOrig = toHash.GetValue("cFiltruOrig") llAllInList = toHash.GetValue("lAllInList") lnPornire = toHash.GetValue("nPornire") + lVerificaANAF = toHash.GetValue("lVerificaANAF") + ldDataDoc = toHash.GetValue("dDataDoc") *!* parametrii @@ -93,12 +849,12 @@ Procedure CautPartenerContabilitate If !Empty(lcTipuriParteneri) *!* selectia se face din corespondente tipuri partener lcSelect = [SELECT MIN(CASE WHEN A.ID_TIP_PART in (] + lcTipuriParteneri + [) THEN 0 ELSE 1 END) AS TIP,] + ; - [B.ID_PART, B.DENUMIRE AS NUME, B.COD_FISCAL, B.DENUMIRE ] + ; + [B.ID_PART, B.DENUMIRE AS NUME, B.COD_FISCAL, B.DENUMIRE, B.TIP_PERSOANA ] + ; [ FROM CORESP_TIP_PART A ] + ; [ LEFT JOIN NOM_PARTENERI B ON A.ID_PART = B.ID_PART ] Else *!* selectia se face din parteneri - lcSelect = [SELECT 0 as TIP, B.ID_PART, B.DENUMIRE AS NUME, B.COD_FISCAL, B.DENUMIRE ] + ; + lcSelect = [SELECT 0 as TIP, B.ID_PART, B.DENUMIRE AS NUME, B.COD_FISCAL, B.DENUMIRE, B.TIP_PERSOANA ] + ; [ FROM NOM_PARTENERI B ] Endif @@ -108,7 +864,7 @@ Procedure CautPartenerContabilitate .SetValue("cFiltru", "1=2") .SetValue("cOrder", "1,NUME") If !Empty(Nvl(lcTipuriParteneri, '')) - .SetValue("cGroup", "B.ID_PART, B.DENUMIRE, B.COD_FISCAL") + .SetValue("cGroup", "B.ID_PART, B.DENUMIRE, B.COD_FISCAL, B.TIP_PERSOANA") Endif .SetValue("cColoana", "denumire,cod_fiscal,id_part") .SetValue("cTitlu", lcTitlu) @@ -142,8 +898,24 @@ Procedure CautPartenerContabilitate Endwith + Private poVerifAlegere, poANAFInlocuire + poVerifAlegere = .Null. + poANAFInlocuire = .Null. + If m.lVerificaANAF + lnNivelANAF = ANAF_NivelVerificare() + If m.lnNivelANAF > 0 + poVerifAlegere = Createobject('anaf_verif_cautare') + poVerifAlegere.dDataDoc = ANAF_CaData(m.ldDataDoc) + poVerifAlegere.nNivel = m.lnNivelANAF + Endif + Endif + loCauta = cauta_alfa_hash(loHash) && 11.07.2007 + If Type('gnbuton') = 'N' And gnbuton = 1 + AplicaInlocuirePartenerANAF(loCauta, poANAFInlocuire, lcTipuriParteneri) + Endif + *!* ADAUG TIPURI DE PARTENER - PARTENER DACA NU EXISTA If llAdaugCorespondente And !Isnull(loCauta) And Type('loCauta.id_part') = 'N' And loCauta.id_part <> 0 And !Empty(lcTipuriParteneri) And loCauta.tip = 1 Do ADAUGA_CORESP_TIP_PART With loCauta.id_part, lcTipuriParteneri In oproceduri_parteneri.prg @@ -158,14 +930,14 @@ Endproc && CautPartenerContabilitate * Date : 04/11/2004, 14:01:21 * author : lavinia.viziru ******************************************* INCEPUT:caut_parteneri ******************************************* -Procedure caut_parteneri( tcCont, tcTitlu, tlToateIreg, tlNou, tlInactiv) +Procedure caut_parteneri( tcCont, tcTitlu, tlToateIreg, tlNou, tlInactiv, tlVerificaANAF, tdDataDoc) Local lcCont, loCauta, lcFiltruOriginal Local lcTitlu, lcFiltru, lcSchema, lcOrder, lcNumeProc, lcTitluColoane Store "" To loCauta lcCont = tcCont llInactiv = m.tlInactiv && daca arat si partenerii inactivi (ex: la fisa de cont, cand un partener s-a unificat, partenerul vechi este inactiv) - lcSelect = [select distinct p.denumire, p.nume, p.cod_fiscal, p.id_part, p.inactiv FROM Vcoresp_tip_part p ] + ; + lcSelect = [select distinct p.denumire, p.nume, p.cod_fiscal, p.id_part, p.inactiv, p.tip_persoana FROM Vcoresp_tip_part p ] + ; [ join vcoresp_tip_cont c on p.id_tip_part=c.id_tip_part ] lcFiltru = [1=2] lcSchema = [] @@ -188,8 +960,26 @@ Procedure caut_parteneri( tcCont, tcTitlu, tlToateIreg, tlNou, tlInactiv) ENDIF lcTitluColoane = [Denumire, Nume,Cod fiscal, Id, Inactiv] + + Local lnNivelANAF + Private poVerifAlegere, poANAFInlocuire + poVerifAlegere = .Null. + poANAFInlocuire = .Null. + If m.tlVerificaANAF + lnNivelANAF = ANAF_NivelVerificare() + If m.lnNivelANAF > 0 + poVerifAlegere = Createobject('anaf_verif_cautare') + poVerifAlegere.dDataDoc = ANAF_CaData(m.tdDataDoc) + poVerifAlegere.nNivel = m.lnNivelANAF + Endif + Endif + loCauta = cauta_alfa(lcSelect, lcFiltru, lcSchema, lcOrder, lccoloane, lcTitlu, lcTitluColoane, lcNumeProc, tlToateIreg, lcFiltruOriginal) && 11.07.2007 + If Type('gnbuton') = 'N' And gnbuton = 1 + AplicaInlocuirePartenerANAF(loCauta, poANAFInlocuire) + Endif + Return loCauta Endproc diff --git a/programe/validare.prg b/programe/validare.prg index 4a0820a..4629832 100644 --- a/programe/validare.prg +++ b/programe/validare.prg @@ -55,6 +55,10 @@ *!* marius.mutu *!* ANAF_SincronWebService_PlatitorTva api v9 +*!* 25.07.2026 +*!* marius.mutu +*!* NormalizeazaCUI + ANAF_VerificaCuiSingle (verificare la alegerea partenerului, la data documentului) + *!* http://ec.europa.eu/taxation_customs/vies/viesquer.do *!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CIF/1879855/MFIN *!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CNP/1810228134187 @@ -1546,6 +1550,123 @@ Define Class VerificareCod As Custom Endfunc && GetEmptyMfinObj Enddefine +************************************* +*** Normalizeaza un cod fiscal: UPPER, fara spatii, fara prefixul RO daca restul e numeric +************************************* +Function NormalizeazaCUI + Lparameters tcCui + + Local lcCui, lcRest, lnI, llNumeric + lcCui = Upper(Strtran(Alltrim(Nvl(m.tcCui, '')), ' ', '')) + If Left(m.lcCui, 2) = 'RO' + lcRest = Substr(m.lcCui, 3) + llNumeric = !Empty(m.lcRest) + For lnI = 1 To Len(m.lcRest) + If !Isdigit(Substr(m.lcRest, lnI, 1)) + llNumeric = .F. + Exit + Endif + Endfor + If m.llNumeric + lcCui = m.lcRest + Endif + Endif + + Return m.lcCui +Endfunc && NormalizeazaCUI + +************************************* +*** Wrapper single-CUI peste VerificareANAF: tdData = data documentului (lipsa -> data curenta), degradare tacuta (.NULL.) +************************************* +Function ANAF_VerificaCuiSingle + Lparameters tcCui, tdData + + Local lcCuiNormalizat, loHTTP, loEx As Exception, loResult, lcServer, lcSend, lcJsonString, lcDataFormatted, ldData + Local loVerificareANAF As "VerificareANAF", loCol As "empty", laCoduri[1], lcAliasTemp, lnReccountTemp, lnI, llValid + + If Type('gvANAF_EroareLogataSesiune') = 'U' + Public gvANAF_EroareLogataSesiune + gvANAF_EroareLogataSesiune = .F. + Endif + + lcCuiNormalizat = NormalizeazaCUI(m.tcCui) + llValid = !Empty(m.lcCuiNormalizat) + If m.llValid + For lnI = 1 To Len(m.lcCuiNormalizat) + If !Isdigit(Substr(m.lcCuiNormalizat, lnI, 1)) + llValid = .F. + Exit + Endif + Endfor + Endif + If !m.llValid + Return .Null. + Endif + + loResult = .Null. + lcAliasTemp = "crsANAFSingleTemp" + + Try + loVerificareANAF = Createobject("VerificareANAF") && incarca nfjsonread/nfjsoncreate (Init) + + Try + loHTTP = Createobject('winHTTP.winHTTPrequest.5.1') + If Pemstatus(m.loHTTP, 'SetTimeouts', 5) + loHTTP.SetTimeouts(3000, 3000, 5000, 5000) && rezolvare/conectare 3s, trimitere/primire 5s - de revizuit dupa masuratori (Tema) + Endif + Catch To loEx + loHTTP = Createobject('Microsoft.XMLHTTP') + Endtry + + ldData = Iif(Vartype(m.tdData) = 'D' And !Empty(m.tdData), m.tdData, Date()) + lcDataFormatted = Left(Dtos(m.ldData), 4) + "-" + Substr(Dtos(m.ldData), 5, 2) + "-" + Substr(Dtos(m.ldData), 7, 2) + + loCol = Createobject("empty") + Addproperty(loCol, "cui", Int(Val(m.lcCuiNormalizat))) + Addproperty(loCol, "data", m.lcDataFormatted) + laCoduri[1] = loCol + lcSend = nfjsoncreate(@laCoduri) + + lcServer = 'https://webservicesp.anaf.ro/api/PlatitorTvaRest/v9/tva' + + lcJsonString = '' + loHTTP.Open('POST', lcServer, .F.) + loHTTP.setRequestHeader("Content-Type", "application/json;") + loHTTP.Send(lcSend) + If loHTTP.Status = 200 + lcJsonString = Alltrim(loHTTP.responseText) + Endif + + If !Empty(m.lcJsonString) And Left(m.lcJsonString, 1) = '{' + Use In (Select(m.lcAliasTemp)) + loVerificareANAF.ParseJsonANAFv8(nfjsonread(m.lcJsonString), m.lcAliasTemp) + If Used(m.lcAliasTemp) + Select (m.lcAliasTemp) + lnReccountTemp = Reccount() + If m.lnReccountTemp = 1 And !Empty(denumire) + loResult = Createobject("empty") + Addproperty(loResult, "cui", cui) + Addproperty(loResult, "scpTVA", Nvl(scpTVA, .F.)) + Addproperty(loResult, "statusInactivi", Nvl(statusInactivi, .F.)) + Addproperty(loResult, "denumire", Nvl(denumire, "")) + Addproperty(loResult, "mesaj", Nvl(mesaj, "")) + Endif + Use In (Select(m.lcAliasTemp)) + Endif + Endif + Catch To loEx + If !gvANAF_EroareLogataSesiune + If Type('goLog') = 'O' + goLog.Log('ANAF_VerificaCuiSingle: ' + loEx.Message, 'ANAF_VerificaCuiSingle') + Endif + gvANAF_EroareLogataSesiune = .T. + Endif + loResult = .Null. + Endtry + + Return m.loResult +Endfunc && ANAF_VerificaCuiSingle + ********************************************* *** Verificare coduri fiscale folosind serviciul web ANAF, cate 500 de coduri per interogare ********************************************* @@ -1717,7 +1838,6 @@ Define Class VerificareANAF As Custom goLog.Log('lcJsonString: ' + m.lcJsonString, 'ANAF_SincronWebService_PlatitorTva') * - SET STEP ON If Not Empty(m.lcJsonString) TRY loJsonObject = nfjsonread(m.lcJsonString) && nfJson from http://vfpx.codeplex.com/ diff --git a/utile/Teste/mock_ainputbox.prg b/utile/Teste/mock_ainputbox.prg new file mode 100644 index 0000000..fbbf9bc --- /dev/null +++ b/utile/Teste/mock_ainputbox.prg @@ -0,0 +1,33 @@ +* mock_ainputbox.prg - inlocuieste FUNCTION aInputBox (din oproceduri_comune.prg) in teste, ca +* fereastra modala de introducere sa NU blocheze testul headless. Se incarca cu SET PROCEDURE ... +* ADDITIVE langa mock_amessagebox.prg (aceeasi rezolutie de nume: castiga fisierul de proceduri +* deschis cel mai recent). +* gnMockInputBox (PUBLIC, optional): valoarea returnata la fiecare apel (implicit 1). +* gcMockInputSecventa (PUBLIC, optional): lista de valori separate prin virgula, returnate pe rand +* (apelul N ia valoarea N, ultimul apel se repeta) - pentru fluxuri care reiau intrebarea, ex. +* numar de varianta invalid urmat de unul valid. Are prioritate fata de gnMockInputBox. +* gnMockInputCount (PUBLIC, optional): contor de apeluri - pentru aserti de tipul "nu s-a cerut +* numarul variantei cand exista o singura varianta". +* gcMockUltimPrompt (PUBLIC, optional): textul ultimului prompt primit. +FUNCTION aInputBox + LPARAMETERS tcPrompt, tcTitle, txDefaultValue, tnLeft, tnTop, tcFormat, tcInputMask, tcPasswordChar + LOCAL luRaspuns, lnApel, lcValoare + IF TYPE('gnMockInputCount') = 'N' + gnMockInputCount = gnMockInputCount + 1 + lnApel = gnMockInputCount + ELSE + lnApel = 1 + ENDIF + luRaspuns = IIF(TYPE('gnMockInputBox') = 'N', gnMockInputBox, 1) + IF TYPE('gcMockInputSecventa') = 'C' AND !EMPTY(gcMockInputSecventa) + lcValoare = GETWORDNUM(gcMockInputSecventa, MIN(m.lnApel, GETWORDCOUNT(gcMockInputSecventa, ',')), ',') + luRaspuns = VAL(m.lcValoare) + ENDIF + IF TYPE('gcMockUltimPrompt') = 'C' + gcMockUltimPrompt = TRANSFORM(tcPrompt) + ENDIF + IF TYPE('gcUILog') = 'C' + DO HarnessLog WITH 'MOCK aInputBox apelat: [' + ALLTRIM(TRANSFORM(tcPrompt)) + '] -> returnez ' + TRANSFORM(luRaspuns) + ENDIF + RETURN luRaspuns +ENDFUNC diff --git a/utile/Teste/mock_amessagebox.prg b/utile/Teste/mock_amessagebox.prg index d49116c..ec82a1a 100644 --- a/utile/Teste/mock_amessagebox.prg +++ b/utile/Teste/mock_amessagebox.prg @@ -10,6 +10,8 @@ * mock-ul raspunde cu ACEASTA valoare in loc de gnMockRaspuns - necesar cand doua dialoguri * diferite (recalculare suma in lei / actualizare total factura) apar in ACELASI apel de metoda * si trebuie sa primeasca raspunsuri diferite (ex. Da la primul, Nu la al doilea). +* gcMockUltimMesaj / gnMockUltimTip (PUBLIC, optional): daca testul declara gcMockUltimMesaj ca +* sir, mock-ul memoreaza in ele mesajul si tipul ultimului apel - pentru aserti pe TEXTUL dialogului. FUNCTION amessagebox LPARAMETERS tcMessage, tnDialogBoxType, tcTitle, tcFont, tnTimeOut, tnTimeoutValue LOCAL lnRaspuns @@ -18,6 +20,10 @@ FUNCTION amessagebox ELSE lnRaspuns = IIF(TYPE('gnMockRaspuns') = 'N', gnMockRaspuns, 6) ENDIF + IF TYPE('gcMockUltimMesaj') = 'C' + gcMockUltimMesaj = TRANSFORM(tcMessage) + gnMockUltimTip = IIF(TYPE('tnDialogBoxType') = 'N', tnDialogBoxType, 0) + ENDIF IF TYPE('gcUILog') = 'C' DO HarnessLog WITH 'MOCK amessagebox apelat: [' + ALLTRIM(TRANSFORM(tcMessage)) + '] -> returnez ' + TRANSFORM(lnRaspuns) ENDIF diff --git a/utile/Teste/partener_anaf/mock_anaf_verificare.prg b/utile/Teste/partener_anaf/mock_anaf_verificare.prg new file mode 100644 index 0000000..30e8f0e --- /dev/null +++ b/utile/Teste/partener_anaf/mock_anaf_verificare.prg @@ -0,0 +1,34 @@ +* mock_anaf_verificare.prg - inlocuieste FUNCTION ANAF_VerificaCuiSingle (validare.prg) cu raspunsuri +* preconfigurate, ca testul UI sa NU faca apeluri reale la serviciul ANAF (lent/nedeterminist). +* Se incarca cu SET PROCEDURE ... ADDITIVE INAINTEA lui test_init_env_auto (care incarca validare.prg +* real) - la nume duplicat de FUNCTION, VFP foloseste fisierul cautat PRIMUL (verificat empiric, +* vezi COMUN\docs\testare-ui-vfp.md capcana g). NormalizeazaCUI (validare.prg) NU e suprascrisa - +* se foloseste cea reala. +* IMPORTANT: goANAFMockData (Collection cu raspunsuri, cheie 'C'+cui normalizat) si gnANAFCallCount +* (contor apeluri reale, nu din cache) se construiesc INLINE in programul principal al testului, +* NU aici si NU intr-o PROCEDURE - vezi capcana l din depanare_testare_vfp.md (CREATEOBJECT/ +* ADDPROPERTY apelate dintr-o PROCEDURA se comporta gresit in acest runtime headless; SET PROCEDURE +* nici nu executa codul de top-level al acestui fisier, doar inregistreaza FUNCTION-ul de mai jos). +* Contor apeluri: gnANAFCallCount creste doar cand mock-ul e efectiv apelat (ANAF_StarePartener +* verifica intai goCacheANAF_Sesiune - cache-hit NU ajunge aici). +* runda 12: tdData (data documentului, trimisa de ANAF_StarePartener) e retinuta in gdANAFUltimaData, +* ca testul sa poata verifica ca data ajunge efectiv la wrapper. +FUNCTION ANAF_VerificaCuiSingle + LPARAMETERS tcCui, tdData + LOCAL lcCui, lcKey + IF TYPE('goANAFMockData') <> 'O' + RETURN .NULL. + ENDIF + IF TYPE('gnANAFCallCount') = 'N' + gnANAFCallCount = gnANAFCallCount + 1 + ENDIF + IF VARTYPE(m.tdData) = 'D' + gdANAFUltimaData = m.tdData + ENDIF + lcCui = NormalizeazaCUI(m.tcCui) + lcKey = 'C' + m.lcCui + IF goANAFMockData.GetKey(m.lcKey) = 0 + RETURN .NULL. && CUI neconfigurat - simuleaza "fara raspuns" (degradare tacuta) + ENDIF + RETURN goANAFMockData.Item(m.lcKey) +ENDFUNC diff --git a/utile/Teste/partener_anaf/shot_dialog_anaf.prg b/utile/Teste/partener_anaf/shot_dialog_anaf.prg new file mode 100644 index 0000000..7e0d798 --- /dev/null +++ b/utile/Teste/partener_anaf/shot_dialog_anaf.prg @@ -0,0 +1,146 @@ +* shot_dialog_anaf.prg - captureaza dialogul REAL (AMESSAGEBOX neinlocuit) generat de +* anaf_verif_cautare.VerificaAlegere() (ocautare.prg), pt. o captura de ecran cu mesajul de +* PRODUCTIE real (AntetDialog/ListaCorecti/TextAnaf) - nu text scris de mana in script. +* Mock ANAF (raspunsuri preconfigurate, fara apel real la anaf.ro) ca in suita principala, dar +* FARA mock_amessagebox.prg: AMESSAGEBOX ramane cea reala din oproceduri_comune.prg. Acea functie +* suporta DOUA ramuri: formularul MessageBox.vcx (daca acea clasa e incarcata) sau MESSAGEBOX() +* nativ altfel (fereastra Windows separata, clasa #32770) - formularul VCX nu se randeaza in acest +* mediu minimal headless (confirmat: se blocheaza fara eroare, indiferent de suita testata), asa ca +* acest script elibereaza clasa (RELEASE CLASSLIB, doar in sesiunea proprie, niciun fisier atins) +* ca AMESSAGEBOX sa aleaga singura ramura nativa. Fereastra nativa BLOCHEAZA scriptul pana e inchisa +* din exterior (shot_dialog_anaf.ps1 o gaseste dupa semnalul ready_0, o captureaza cu PrintWindow +* si o inchide cu WM_CLOSE). +SET SAFETY OFF +SET TALK OFF +SET DELETED ON +SET EXACT ON +SET CENTURY ON +SET DATE DMY +SET NULLDISPLAY TO '' +CLOSE DATABASES + +PUBLIC gcUILog, gcSyncDir +gcUILog = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\shot_dialog_anaf_log.txt" +gcSyncDir = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\uisync_dialog\" +STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog) + +ON ERROR DO VpaErrD WITH ERROR(), MESSAGE(), PROGRAM(), LINENO() +ON SHUTDOWN QUIT + +*-- doar mock-ul ANAF (raspunsuri) - FARA mock_amessagebox: AMESSAGEBOX ramane cea reala din productie +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\ui_harness.prg" ADDITIVE +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\mock_anaf_verificare.prg" ADDITIVE +DO VpaLogD WITH 'mock ANAF incarcat (fara mock amessagebox - dialog REAL)' + +DO D:\ROA\ROACONT\COMUN\utile\Teste\test_init_env_auto.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT' +IF gnHandle <= 0 + DO VpaLogD WITH 'EROARE: conectare Oracle esuata - GATA' + DO HarnessDone WITH 'done-error' + QUIT +ENDIF +DO VpaLogD WITH 'mediu OK, schema=' + gcS + +*-- test_init_env_auto incarca "Set Classlib To Messagebox Additive" (ca in roacont.prg) - cu ea +*-- incarcata, AMESSAGEBOX (productie) afiseaza formularul MessageBox.vcx (nu s-a randat in acest +*-- mediu minimal headless, fara legatura cu suita testata). RELEASE CLASSLIB doar in acest script +*-- de captura (nu atinge niciun fisier) - AMESSAGEBOX ramane codul REAL, foloseste doar cealalta +*-- ramura pe care el insusi o suporta: MESSAGEBOX() nativ, fereastra Windows separata (#32770). +RELEASE CLASSLIB Messagebox +DO VpaLogD WITH 'Set(Classlib) dupa RELEASE: [' + SET('Classlib') + ']' + +PUBLIC goANAFMockData, gnANAFCallCount, gdANAFUltimaData +goANAFMockData = CREATEOBJECT('Collection') +gnANAFCallCount = 0 +gdANAFUltimaData = {} +LOCAL loRespDiscord +loRespDiscord = CREATEOBJECT('Empty') +ADDPROPERTY(loRespDiscord, 'cui', '7654321') +ADDPROPERTY(loRespDiscord, 'scpTVA', .T.) +ADDPROPERTY(loRespDiscord, 'statusInactivi', .F.) +ADDPROPERTY(loRespDiscord, 'denumire', 'DISCORD SRL ANAF') +ADDPROPERTY(loRespDiscord, 'mesaj', '') +goANAFMockData.Add(loRespDiscord, 'C7654321') +DO VpaLogD WITH 'mock ANAF: CUI 7654321 configurat' + +PUBLIC gnIdDiscord, gnIdPereche + +TRY + DO CurataDateTestD + DO CreeazaDateTestD + + LOCAL lnOk + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART IN (] + TRANSFORM(gnIdDiscord) + [,] + TRANSFORM(gnIdPereche) + [) AND INACTIV = 0 ORDER BY ID_PART], 'ctestdialog') + + PUBLIC goFormD, poVerifD + goFormD = CREATEOBJECT('cauta_alfa_form', 'ctestdialog', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + goFormD.crs_cursor = 'ctestdialog' + goFormD.lAles = .F. + poVerifD = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(goFormD, 'oVerifAlegere', poVerifD) + poVerifD.Activeaza(goFormD) + goFormD.WindowType = 0 + goFormD.Show() + SELECT ctestdialog + LOCATE FOR id_part = gnIdDiscord + goFormD._GRID1.AfterRowColChange(1) + poVerifD.VerificaRand(.T.) + DO VpaLogD WITH 'stare pregatita, label=[' + ALLTRIM(goFormD.lb_anaf.Caption) + ']' + + DO HarnessReady WITH 0, 'gata sa afisez dialogul REAL' + *-- BLOCHEAZA aici (MESSAGEBOX() nativ) pana harnessul extern inchide fereastra (WM_CLOSE) + LOCAL llRez + llRez = poVerifD.VerificaAlegere(goFormD) + DO VpaLogD WITH 'dialog inchis, VerificaAlegere a intors ' + TRANSFORM(llRez) + + DO HarnessDone WITH 'done' +CATCH TO loExcD + DO VpaLogD WITH 'CATCH ErrorNo=' + TRANSFORM(loExcD.ErrorNo) + ' Message=' + loExcD.Message + ' Line=' + TRANSFORM(loExcD.LineNo) + DO HarnessDone WITH 'done-error' +FINALLY + DO CurataDateTestD +ENDTRY + +QUIT + +PROCEDURE CurataDateTestD + LOCAL lnOk + lnOk = goExecutor.oExecuta([DELETE FROM NOM_PARTENERI WHERE COD_FISCAL IN ('7654321','RO7654321')]) + =goExecutor.oExecuta('COMMIT') + DO VpaLogD WITH 'CurataDateTestD: sters=' + TRANSFORM(m.lnOk) +ENDPROC + +PROCEDURE CreeazaDateTestD + LOCAL lcIns + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','7654321',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','RO7654321',0,0,1,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + =goExecutor.oExecuta('COMMIT') + gnIdDiscord = 0 + gnIdPereche = 0 + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '7654321'], @gnIdDiscord) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = 'RO7654321'], @gnIdPereche) + DO VpaLogD WITH 'CreeazaDateTestD: discord=' + TRANSFORM(gnIdDiscord) + ' pereche=' + TRANSFORM(gnIdPereche) +ENDPROC + +PROCEDURE VpaErrD + LPARAMETERS tnErr, tcMsg, tcProg, tnLine + DO VpaLogD WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg + TRY + DO CurataDateTestD + CATCH + ENDTRY + QUIT +ENDPROC + +PROCEDURE VpaLogD + LPARAMETERS tcMsg + SET SAFETY OFF + LOCAL lcL + lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '') + STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog) +ENDPROC diff --git a/utile/Teste/partener_anaf/shot_dialog_anaf.ps1 b/utile/Teste/partener_anaf/shot_dialog_anaf.ps1 new file mode 100644 index 0000000..2699dca --- /dev/null +++ b/utile/Teste/partener_anaf/shot_dialog_anaf.ps1 @@ -0,0 +1,177 @@ +# shot_dialog_anaf.ps1 - lanseaza shot_dialog_anaf.prg (dialog ANAF REAL, neinlocuit) si +# captureaza fereastra nativa MESSAGEBOX() (clasa #32770) aparuta in acelasi proces vfp9, +# apoi o inchide cu WM_CLOSE (fara SendKeys, fara sa fure focus - fereastra e mutata off-screen +# inainte de captura, ca in vfp_ui_harness.ps1). +param( + [string]$Prg = (Join-Path $PSScriptRoot 'shot_dialog_anaf.prg'), + [string]$OutPng = (Join-Path $PSScriptRoot 'screenshots\dialog_anaf_real.png'), + [int]$ReadyTimeoutSec = 150, + [int]$DialogTimeoutSec = 20, + [string]$Vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' +) +$ErrorActionPreference = 'Stop' + +$TestDir = [System.IO.Path]::GetDirectoryName($Prg) +$TestFxp = [System.IO.Path]::ChangeExtension($Prg, 'fxp') +$TestLog = Join-Path $TestDir 'shot_dialog_anaf_log.txt' +$SyncDir = Join-Path $TestDir 'uisync_dialog' +$Precompile = Join-Path (Split-Path $TestDir -Parent) '_precompile.ps1' + +Add-Type -AssemblyName System.Drawing + +Add-Type @" +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +public class Win32Dlg { + public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); + [StructLayout(LayoutKind.Sequential)] + public struct RECT { public int Left, Top, Right, Bottom; } + [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); + [DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + [DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd); + [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr hWnd); + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdc, uint nFlags); + [DllImport("user32.dll")] public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + public static readonly IntPtr HWND_BOTTOM = new IntPtr(1); + public const uint SWP_NOSIZE = 0x0001; + public const uint SWP_NOACTIVATE = 0x0010; + public const uint WM_CLOSE = 0x0010; + + public static List FindByPidAndClass(int pid, string className) { + var result = new List(); + EnumWindows((hWnd, lParam) => { + int wpid; + GetWindowThreadProcessId(hWnd, out wpid); + if (wpid == pid && IsWindowVisible(hWnd)) { + var sb = new StringBuilder(256); + GetClassName(hWnd, sb, sb.Capacity); + if (sb.ToString() == className) { result.Add(hWnd); } + } + return true; + }, IntPtr.Zero); + return result; + } + public static string GetTitle(IntPtr hWnd) { + var sb = new StringBuilder(512); + GetWindowText(hWnd, sb, sb.Capacity); + return sb.ToString(); + } +} +"@ + +function Push-Offscreen([IntPtr]$Hwnd) { + if ($Hwnd -eq [IntPtr]::Zero -or -not [Win32Dlg]::IsWindow($Hwnd)) { return } + [Win32Dlg]::SetWindowPos($Hwnd, [Win32Dlg]::HWND_BOTTOM, -4000, 0, 0, 0, ([Win32Dlg]::SWP_NOSIZE -bor [Win32Dlg]::SWP_NOACTIVATE)) | Out-Null +} + +function Wait-MainWindowHandle([System.Diagnostics.Process]$Proc, [int]$TimeoutSec) { + $deadline = (Get-Date).AddSeconds($TimeoutSec) + while ((Get-Date) -lt $deadline) { + try { + $Proc.Refresh() + if ($Proc.HasExited) { return [IntPtr]::Zero } + if ($Proc.MainWindowHandle -ne [IntPtr]::Zero) { return $Proc.MainWindowHandle } + } catch {} + Start-Sleep -Milliseconds 200 + } + return [IntPtr]::Zero +} + +function Wait-File([string]$Path, [int]$TimeoutSec, [IntPtr]$Hwnd = [IntPtr]::Zero) { + $deadline = (Get-Date).AddSeconds($TimeoutSec) + while (-not (Test-Path $Path)) { + if ((Get-Date) -gt $deadline) { return $false } + if ($Hwnd -ne [IntPtr]::Zero) { Push-Offscreen $Hwnd } + Start-Sleep -Milliseconds 300 + } + return $true +} + +function Take-Screenshot([IntPtr]$Hwnd, [string]$Path) { + $rect = New-Object Win32Dlg+RECT + [Win32Dlg]::GetWindowRect($Hwnd, [ref]$rect) | Out-Null + $w = $rect.Right - $rect.Left + $h = $rect.Bottom - $rect.Top + if ($w -le 0 -or $h -le 0) { $w = 600; $h = 300 } + $bmp = New-Object System.Drawing.Bitmap $w, $h + $g = [System.Drawing.Graphics]::FromImage($bmp) + $hdc = $g.GetHdc() + $ok = [Win32Dlg]::PrintWindow($Hwnd, $hdc, 2) + $g.ReleaseHdc($hdc) + $g.Dispose() + if (-not $ok) { + $g2 = [System.Drawing.Graphics]::FromImage($bmp) + $hdc2 = $g2.GetHdc() + [Win32Dlg]::PrintWindow($Hwnd, $hdc2, 0) | Out-Null + $g2.ReleaseHdc($hdc2) + $g2.Dispose() + } + $bmp.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png) + $bmp.Dispose() +} + +New-Item -ItemType Directory -Force -Path (Split-Path $OutPng -Parent) | Out-Null +if (Test-Path $SyncDir) { Get-ChildItem $SyncDir -File | Remove-Item -Force -ErrorAction SilentlyContinue } else { New-Item -ItemType Directory -Path $SyncDir | Out-Null } + +Write-Host "Precompilez .fxp (izolat): $Precompile -Prg $Prg" +Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue +Start-Sleep -Milliseconds 500 +Start-Process powershell -WindowStyle Hidden -ArgumentList @('-ExecutionPolicy','Bypass','-File',"`"$Precompile`"",'-Prg',"`"$Prg`"") -Wait | Out-Null +Start-Sleep -Seconds 2 +Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue +Start-Sleep -Seconds 2 +if (-not (Test-Path $TestFxp)) { Write-Warning "Nu s-a generat $TestFxp - compilare esuata."; exit 1 } + +$ready0 = Join-Path $SyncDir 'ready_0.txt' +if (Test-Path $ready0) { Remove-Item $ready0 -Force } +if (Test-Path $TestLog) { Remove-Item $TestLog -Force } +$t0 = Get-Date +Write-Host "Lansez VFP: $Vfp -A $TestFxp" +$proc = Start-Process -FilePath $Vfp -ArgumentList @('-A', "`"$TestFxp`"") -PassThru +$hwnd = Wait-MainWindowHandle $proc 15 +Push-Offscreen $hwnd + +if (-not (Wait-File $ready0 $ReadyTimeoutSec $hwnd)) { + Write-Warning "Nu am primit ready_0 in ${ReadyTimeoutSec}s. Ultima linie log: '$(Get-Content $TestLog -Tail 1 -ErrorAction SilentlyContinue)'" + if (-not $proc.HasExited) { try { $proc.Kill() } catch {} } + Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue + exit 1 +} +Write-Host "ready_0 primit - astept fereastra MESSAGEBOX() nativa (clasa #32770, acelasi PID)" + +$dlgHwnd = [IntPtr]::Zero +$deadline = (Get-Date).AddSeconds($DialogTimeoutSec) +while ((Get-Date) -lt $deadline -and $dlgHwnd -eq [IntPtr]::Zero) { + $cands = [Win32Dlg]::FindByPidAndClass($proc.Id, '#32770') + foreach ($h in $cands) { $dlgHwnd = $h; break } + if ($dlgHwnd -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 300 } +} + +if ($dlgHwnd -eq [IntPtr]::Zero) { + Write-Warning "Fereastra dialogului nu a aparut in ${DialogTimeoutSec}s." + if (-not $proc.HasExited) { try { $proc.Kill() } catch {} } + Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue + exit 1 +} +Write-Host ("dialog gasit: hwnd={0} titlu=[{1}]" -f $dlgHwnd, [Win32Dlg]::GetTitle($dlgHwnd)) +Push-Offscreen $dlgHwnd +Start-Sleep -Milliseconds 600 +Push-Offscreen $dlgHwnd +Take-Screenshot $dlgHwnd $OutPng +Write-Host "screenshot: $OutPng" + +# inchide dialogul (echivalent Escape/Cancel) - nu SendKeys, ca sa nu ceara focus +[Win32Dlg]::PostMessage($dlgHwnd, [Win32Dlg]::WM_CLOSE, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null + +$done = Join-Path $SyncDir 'done.txt' +if (Wait-File $done 30 $hwnd) { Write-Host "done: $((Get-Content $done -Raw).Trim())" } else { Write-Warning "Nu am primit done.txt dupa inchiderea dialogului." } +Start-Sleep -Milliseconds 500 +if (-not $proc.HasExited) { try { $proc.Kill() } catch {} } +Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue +Write-Host "GATA. Screenshot in $OutPng" diff --git a/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg b/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg new file mode 100644 index 0000000..b6f8cc1 --- /dev/null +++ b/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg @@ -0,0 +1,1660 @@ +* test_verif_partener_anaf_v2_ui.prg +* Teste UI pentru verificarea ANAF la selectia partenerului - REVIZIA 2 (V2', 25.07.2026): +* verdict in formularul de cautare (label pe cauta_alfa_form), fara frm_verif_partener_anaf +* (eliminata). Vezi docs\design-alegere-partener-anaf.md sectiunea "REVIZIA 2". +* Testeaza clasele reale din COMUN\programe\ocautare.prg (anaf_verif_cautare/anaf_timer) +* atasate prin hook-ul generic din cauta_alfa.prg, instantiind DIRECT cauta_alfa_form (ca sa evit +* Show() modal al formularului de cautare - vezi capcana "Forme modale" din depanare_testare_vfp.md) +* si navigand grid-ul ca utilizatorul real (AfterRowColChange), nu populare directa de cursor - +* singura populare directa e sursa de date (cursorul RecordSource al gridului), ca in fluxul real +* caut_parteneri()/CautPartenerContabilitate() (SELECT din NOM_PARTENERI). +* +* Mock-uri (INFRASTRUCTURA, permise conform testare-ui-vfp.md): ANAF_VerificaCuiSingle (raspunsuri +* preconfigurate, fara apel real la anaf.ro) si amessagebox (dialogurile de detalii nu blocheaza). +* ANAF_CautaPereche NU se poate mock-ui (e definita SI apelata in ACELASI fisier ocautare.prg - +* rezolutia VFP foloseste versiunea locala indiferent de SET PROCEDURE) - perechile de test sunt +* randuri disposable REALE in NOM_PARTENERI (schema MARIUSM_AUTO), inserate/sterse de acest test. +* +* Date de test (disposable, identificate dupa COD_FISCAL - vezi nota ID_PART mai jos): +* RO1112223 TEST ANAF CONCORD SRL - concordant (ANAF platitor, are RO) +* 7654320 TEST ANAF DISCORD SRL - discordant, ARE pereche (RO7654320, inactiva) +* RO7654320 TEST ANAF DISCORD SRL - perechea (INACTIVA), concordanta cu ANAF +* 9000004 TEST ANAF NOPERECHE SRL - discordant, FARA pereche +* RO 7654320 TEST ANAF SPATIU SRL - a doua varianta cu cod corect (cod scris cu spatiu) +* 1234567890128 TEST ANAF PERSFIZ - CNP valid, persoana fizica - fara verificare ANAF +* 1234567890123 TEST ANAF CNP INVALID - persoana fizica cu CNP invalid +* 1234567 TEST ANAF CIF INVALID - persoana juridica cu CIF invalid +* +* NOTA ID_PART: NOM_PARTENERI are trigger BEFORE INSERT (trg_NOM_PARTENERI_befoins) care +* SUPRASCRIE ID_PART cu seq_NOM_PARTENERI.nextval, indiferent de valoarea din INSERT - ID-urile +* nu pot fi alese explicit. Testul insereaza FARA ID_PART si citeste ID-ul real alocat dupa +* insert (dupa COD_FISCAL, care e sub controlul testului) - gnIdConcord/gnIdDiscord/gnIdPereche/ +* gnIdNopereche/gnIdPersfiz (PUBLIC). +* +* Scenarii de decizie (RUNDA 11): dialogul propriu (anaf_dialog) a fost inlocuit cu AMESSAGEBOX +* tip 3+48 (Da/Nu/Abandon) si 1+48 (OK/Abandon) cand nu exista pereche. Raspunsul se impune prin +* mock_amessagebox.prg cu gnMockRaspuns (6 = Da, 7 = Nu, 2 = Abandon, 1 = OK), iar textul afisat +* se citeste din gcMockUltimMesaj/gnMockUltimTip - totul sincron, fara Show(1) modal si fara clicker. +* +* RUNDA 12: verificarea ANAF se face la DATA DOCUMENTULUI (proprietatea dDataDoc pe +* anaf_verif_cautare), cheia de cache pe sesiune e 'C'+CUI+'_'+Dtos(data), iar textele (label + +* dialoguri, metodele TextAnaf/AntetDialog/ListaCorecti) includ acum denumirea si codul de la +* ANAF plus data verificarii. Scenariile 11-13 (VerificaDataDocument/VerificaCacheData/ +* VerificaDataFallback) acopera data documentului; mock_anaf_verificare.prg retine data primita +* in gdANAFUltimaData (PUBLIC, declarata mai jos). + +SET SAFETY OFF +SET TALK OFF +SET DELETED ON +SET EXACT ON +SET CENTURY ON +SET DATE DMY +SET NULLDISPLAY TO '' +CLOSE DATABASES + +PUBLIC gcUILog, gcSyncDir +gcUILog = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\test_verif_partener_anaf_v2_ui_log.txt" +gcSyncDir = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\uisync\" +STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog) + +ON ERROR DO VpaErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO() +ON SHUTDOWN QUIT + +*----- mock-uri INAINTE de test_init_env_auto (rezolutie "primul fisier cautat", capcana g) ----- +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\ui_harness.prg" ADDITIVE +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\mock_amessagebox.prg" ADDITIVE +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\mock_ainputbox.prg" ADDITIVE +SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\mock_anaf_verificare.prg" ADDITIVE +DO VpaLog WITH 'mock-uri incarcate' + +DO D:\ROA\ROACONT\COMUN\utile\Teste\test_init_env_auto.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT' +IF gnHandle <= 0 + DO VpaLog WITH 'EROARE: conectare Oracle esuata - GATA' + DO HarnessDone WITH 'done-error' + QUIT +ENDIF +DO VpaLog WITH 'mediu OK, schema=' + gcS + +*-- RE-TEST RUNDA 10: fix aplicat in ocautare.prg (guard '_BAZA' eliminat, NewObject pe _label +*-- din _baza.vcx rezolvat pe SET PATH, cu fallback anaf_label) - FARA workaround de test, cale +*-- reala (Activeaza se apeleaza natural, fara SET CLASSLIB manual). + +PUBLIC gnMockRaspuns, gcMockUltimMesaj, gnMockUltimTip +gnMockRaspuns = 6 +gcMockUltimMesaj = '' +gnMockUltimTip = 0 + +*-- goANAFMockData/gnANAFCallCount + obiectele de raspuns ANAF: construite INLINE in programul +*-- principal (nu intr-o PROCEDURE) - vezi capcana l, depanare_testare_vfp.md, si antetul +*-- mock_anaf_verificare.prg. Cheia e 'C' + CUI normalizat (fara RO). +PUBLIC goANAFMockData, gnANAFCallCount, gdANAFUltimaData +goANAFMockData = CREATEOBJECT('Collection') +gnANAFCallCount = 0 +gdANAFUltimaData = {} +LOCAL loRespConcord, loRespDiscord, loRespNoPereche +loRespConcord = CREATEOBJECT('Empty') +ADDPROPERTY(loRespConcord, 'cui', '1112223') +ADDPROPERTY(loRespConcord, 'scpTVA', .T.) +ADDPROPERTY(loRespConcord, 'statusInactivi', .F.) +ADDPROPERTY(loRespConcord, 'denumire', 'CONCORD SRL ANAF') +ADDPROPERTY(loRespConcord, 'mesaj', '') +goANAFMockData.Add(loRespConcord, 'C1112223') +loRespDiscord = CREATEOBJECT('Empty') +ADDPROPERTY(loRespDiscord, 'cui', '7654320') +ADDPROPERTY(loRespDiscord, 'scpTVA', .T.) +ADDPROPERTY(loRespDiscord, 'statusInactivi', .F.) +ADDPROPERTY(loRespDiscord, 'denumire', 'DISCORD SRL ANAF') +ADDPROPERTY(loRespDiscord, 'mesaj', '') +goANAFMockData.Add(loRespDiscord, 'C7654320') +loRespNoPereche = CREATEOBJECT('Empty') +ADDPROPERTY(loRespNoPereche, 'cui', '9000004') +ADDPROPERTY(loRespNoPereche, 'scpTVA', .T.) +ADDPROPERTY(loRespNoPereche, 'statusInactivi', .F.) +ADDPROPERTY(loRespNoPereche, 'denumire', 'NOPERECHE SRL ANAF') +ADDPROPERTY(loRespNoPereche, 'mesaj', '') +goANAFMockData.Add(loRespNoPereche, 'C9000004') +DO VpaLog WITH 'mock ANAF: 3 CUI-uri configurate (1112223, 7654320, 9000004)' + +PUBLIC gnIdConcord, gnIdDiscord, gnIdPereche, gnIdNopereche, gnIdPersfiz, gnIdSpatiu +PUBLIC gnIdCnpInv, gnIdCifInv, gnMockInputBox, gnMockInputCount, gcMockUltimPrompt, gcMockInputSecventa +gnMockInputBox = 1 +gnMockInputCount = 0 +gcMockUltimPrompt = '' +gcMockInputSecventa = '' + +TRY + DO CurataDateTest + DO CreeazaDateTest + + *========================================================================= + * Scenariul 1: label CONCORDANT (verde, fara bold) pe randul concordant + *========================================================================= + DO PornesteCautare + SELECT ctestparteneri + LOCATE FOR id_part = gnIdConcord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + DO VerificaLabelConcordant + + DO HarnessStep WITH 0, 'Scenariul 1 concordant: [' + ALLTRIM(goFormT.lb_anaf.Caption) + ']' + + *========================================================================= + * Scenariul 2: label DISCORDANT (rosu, fara bold) pe randul discordant cu pereche + *========================================================================= + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + DO VerificaLabelDiscordant + + DO HarnessStep WITH 1, 'Scenariul 2 discordant: [' + ALLTRIM(goFormT.lb_anaf.Caption) + ']' + + *========================================================================= + * Scenariul 2b (runda 15): cod fiscal invalid - persoana juridica cu CIF invalid, + * persoana fizica cu CNP invalid (rosu, fara apel ANAF); CNP valid = fara label + *========================================================================= + DO VerificaCodInvalid + + *========================================================================= + * Scenariul 3: debounce - navigare rapida prin 3 randuri, ZERO apeluri ANAF + * pana nu se opreste pe unul (timer 400ms nu apuca sa se declanseze intre randuri) + *========================================================================= + DO VerificaDebounce + + *========================================================================= + * Scenariul 4: cache - a doua selectie pe ACELASI CUI (alt formular nou), + * in aceeasi sesiune VFP, ZERO apel ANAF nou (goCacheANAF_Sesiune e global pe sesiune) + *========================================================================= + DO VerificaCache + + *========================================================================= + * Scenariul 5: click pe label -> AMESSAGEBOX cu detalii (format numerotat) + *========================================================================= + DO VerificaDetalii + + *========================================================================= + * Scenariul 6: alegere rapida (D2) - inainte sa expire timerul, verificarea + * se face SINCRON la VerificaAlegere (nu asteapta timerul) + *========================================================================= + DO VerificaAlegereRapidaD2 + + *========================================================================= + * Scenariul 7: kill-switch [anaf] verificare_selectie=0 -> fara label, fara apel ANAF + *========================================================================= + DO VerificaKillSwitch + + *========================================================================= + * Scenariul 8: regresie - cautare NON-partener (fara oVerifAlegere atasat): + * fara label, inaltime formular NESCHIMBATA, zero impact + *========================================================================= + DO VerificaRegresieNonPartener + + IF USED('ctestparteneri') + USE IN ctestparteneri + ENDIF + IF VARTYPE(goFormT) = 'O' + TRY + goFormT.oVerifAlegere.Dezactiveaza() + DO VpaLog WITH 'PASS Dezactiveaza (goFormT): fara eroare (Unbindevents 1-argument, fix runda 10)' + CATCH TO loExcDez1 + DO VpaLog WITH 'FAIL Dezactiveaza (goFormT): ' + loExcDez1.Message + ENDTRY + goFormT.Release() + ENDIF + + *========================================================================= + * Scenariul 9 (runda 11): TEXTUL mesajului de decizie - 3 linii scurte + * (denumire+CUI+ID / verdict ANAF / lista candidatilor) si tipul 3+48 (Da/Nu/Abandon). + *========================================================================= + DO VerificaMesajDecizie + DO HarnessStep WITH 2, 'Mesaj decizie ANAF verificat' + + *========================================================================= + * Scenariul 10: VerificaAlegere END-TO-END prin AMESSAGEBOX (mock, gnMockRaspuns): + * 6 = Da (pastreaza selectia), 7 = Nu (prima alternativa), 2 = Abandon (inapoi la cautare). + *========================================================================= + DO VerificaAlegereD1aButonPereche + DO VerificaAlegereD1aButonAles + DO VerificaAlegereD1aRenunta + DO VerificaAlegereFaraPereche + DO HarnessStep WITH 3, 'Scenariile de decizie 6/7/2 executate' + + *========================================================================= + * Scenariul 10b (runda 15): cu MAI MULTE variante, "Da" cere numarul variantei + * (numar invalid -> revine la mesaj); cu O SINGURA varianta nu se mai cere nimic + *========================================================================= + DO VerificaAlegereVarianta + + *========================================================================= + * Scenariul 11 (runda 12): data documentului (dDataDoc) ajunge la wrapper ANAF + * si apare in textul labelului ("... la ") + *========================================================================= + DO VerificaDataDocument + + *========================================================================= + * Scenariul 12 (runda 12): cheia de cache pe sesiune include data - acelasi CUI + * la 2 date diferite => 2 apeluri, acelasi CUI la ACEEASI data => 1 apel (cache-hit) + *========================================================================= + DO VerificaCacheData + + *========================================================================= + * Scenariul 13 (runda 12): fara data documentului (dDataDoc gol) => se foloseste Date() + *========================================================================= + DO VerificaDataFallback + + *========================================================================= + * Scenariul 14 (runda 14): fara dDataDoc, dar cu poAct in stiva (formular de + * introduceri) => se foloseste poAct.dataact, nu Date() + *========================================================================= + DO VerificaDataPoAct + + *========================================================================= + * Scenariile REVIZIA 4 (runda 17): cascada RC_ANAF_VERIF_SELECTIE, gating pe nivel, + * C2 (Renunta), H2 (eroare lista), Detalii cu oStare Null, discriminator documente, + * B1 (label golit), comutare optiune (meniu) + *========================================================================= + DO RuleazaIzolat WITH 'VerificaCascadaOptiuni' + DO RuleazaIzolat WITH 'VerificaGatingNivel' + DO RuleazaIzolat WITH 'VerificaC2Renunta' + DO RuleazaIzolat WITH 'VerificaH2EroareListaCorecti' + DO RuleazaIzolat WITH 'VerificaDetaliiStareNula' + DO RuleazaIzolat WITH 'VerificaDiscriminatorDocumente' + DO RuleazaIzolat WITH 'VerificaB1LabelGolit' + DO RuleazaIzolat WITH 'VerificaComutareOptiune' + + DO VpaLog WITH 'GATA - toate scenariile executate' + DO HarnessStep WITH 4, 'toate scenariile executate' + DO HarnessDone WITH 'done' + +CATCH TO loExc + DO VpaLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']' + DO HarnessDone WITH 'done-error' +FINALLY + DO CurataDateTest +ENDTRY + +QUIT + +*================================================================================== +PROCEDURE CurataDateTest + LOCAL lnOk + lnOk = goExecutor.oExecuta([DELETE FROM NOM_PARTENERI WHERE COD_FISCAL IN ('RO1112223','7654320','RO7654320','RO 7654320','9000004','1234567890128','1234567890123','1234567')]) + =goExecutor.oExecuta('COMMIT') + DO VpaLog WITH 'CurataDateTest: sters=' + TRANSFORM(m.lnOk) +ENDPROC + +PROCEDURE CreeazaDateTest + *-- FARA ID_PART in INSERT: trigger BEFORE INSERT (trg_NOM_PARTENERI_befoins) suprascrie + *-- oricum cu seq_NOM_PARTENERI.nextval - ID-urile reale se citesc dupa, pe COD_FISCAL. + LOCAL lcIns + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF CONCORD SRL','TEST ANAF CONCORD SRL','RO1112223',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','7654320',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','RO7654320',0,0,1,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF SPATIU SRL','TEST ANAF SPATIU SRL','RO 7654320',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF NOPERECHE SRL','TEST ANAF NOPERECHE SRL','9000004',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF PERSFIZ','TEST ANAF PERSFIZ','1234567890128',0,0,0,2,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF CNP INVALID','TEST ANAF CNP INVALID','1234567890123',0,0,0,2,0,0)] + =goExecutor.oExecuta(m.lcIns) + lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ; + [('TEST ANAF CIF INVALID SRL','TEST ANAF CIF INVALID SRL','1234567',0,0,0,1,0,0)] + =goExecutor.oExecuta(m.lcIns) + =goExecutor.oExecuta('COMMIT') + + gnIdConcord = 0 + gnIdDiscord = 0 + gnIdPereche = 0 + gnIdNopereche = 0 + gnIdPersfiz = 0 + gnIdSpatiu = 0 + gnIdCnpInv = 0 + gnIdCifInv = 0 + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = 'RO 7654320'], @gnIdSpatiu) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = 'RO1112223'], @gnIdConcord) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '7654320'], @gnIdDiscord) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = 'RO7654320'], @gnIdPereche) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '9000004'], @gnIdNopereche) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '1234567890128'], @gnIdPersfiz) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '1234567890123'], @gnIdCnpInv) + =goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '1234567'], @gnIdCifInv) + DO VpaLog WITH 'CreeazaDateTest: id-uri alocate concord=' + TRANSFORM(gnIdConcord) + ' discord=' + TRANSFORM(gnIdDiscord) + ; + ' pereche=' + TRANSFORM(gnIdPereche) + ' spatiu=' + TRANSFORM(gnIdSpatiu) + ; + ' nopereche=' + TRANSFORM(gnIdNopereche) + ' persfiz=' + TRANSFORM(gnIdPersfiz) +ENDPROC + +PROCEDURE PornesteCautare + *-- replica exact structura cursorului produs de caut_parteneri() (denumire, nume, + *-- cod_fiscal, id_part, inactiv), populat REAL din NOM_PARTENERI (nu valori inventate). + LOCAL lnOk + IF USED('ctestparteneri') + USE IN ctestparteneri + ENDIF + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV, TIP_PERSOANA FROM NOM_PARTENERI ] + ; + [WHERE ID_PART IN (] + TRANSFORM(gnIdConcord) + [,] + TRANSFORM(gnIdDiscord) + [,] + TRANSFORM(gnIdPereche) + [,] + ; + TRANSFORM(gnIdNopereche) + [,] + TRANSFORM(gnIdPersfiz) + [,] + TRANSFORM(gnIdCnpInv) + [,] + TRANSFORM(gnIdCifInv) + ; + [) AND INACTIV = 0 ORDER BY ID_PART], 'ctestparteneri') + IF m.lnOk < 0 + DO VpaLog WITH 'FAIL PornesteCautare: query esuat - ' + goExecutor.cEroare + RETURN + ENDIF + + PUBLIC goFormT, poVerifAlegere + goFormT = CREATEOBJECT('cauta_alfa_form', 'ctestparteneri', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + goFormT.crs_cursor = 'ctestparteneri' + goFormT.Lb_titlu_alb_b121.Caption = 'Test ANAF' + goFormT.lAles = .F. + goFormT.cIdColumn = 'id_part' + + PRIVATE lnInaltimeInitiala + lnInaltimeInitiala = goFormT.Height + + poVerifAlegere = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(goFormT, 'oVerifAlegere', poVerifAlegere) + poVerifAlegere.Activeaza(goFormT) + + goFormT.WindowType = 0 + goFormT.Show() + DOEVENTS FORCE + + *-- RUNDA 17 (B3): cu cmd_select prezent labelul ii ia coordonatele, iar inaltimea formei NU mai creste + IF TYPE('goFormT.cmd_select') = 'O' + IF VARTYPE(goFormT.lb_anaf) = 'O' AND goFormT.Height = m.lnInaltimeInitiala ; + AND goFormT.lb_anaf.Top = goFormT.cmd_select.Top ; + AND goFormT.lb_anaf.Left = goFormT.cmd_select.Left ; + AND goFormT.lb_anaf.Height = goFormT.cmd_select.Height ; + AND goFormT.lb_anaf.Anchor = 14 + DO VpaLog WITH 'PASS activare: lb_anaf pe coordonatele cmd_select, inaltimea formei neschimbata (inaltime=' + TRANSFORM(goFormT.Height) + ')' + ELSE + DO VpaLog WITH 'FAIL activare: lb_anaf tip=' + TRANSFORM(VARTYPE(goFormT.lb_anaf)) + ' inaltime=' + TRANSFORM(goFormT.Height) + ; + ' (initiala=' + TRANSFORM(m.lnInaltimeInitiala) + ')' + ENDIF + ELSE + IF VARTYPE(goFormT.lb_anaf) = 'O' AND goFormT.Height = m.lnInaltimeInitiala + 38 + DO VpaLog WITH 'PASS activare (fara cmd_select): lb_anaf creat, forma marita cu 38px (inaltime=' + TRANSFORM(goFormT.Height) + ')' + ELSE + DO VpaLog WITH 'FAIL activare (fara cmd_select): lb_anaf tip=' + TRANSFORM(VARTYPE(goFormT.lb_anaf)) + ' inaltime=' + TRANSFORM(goFormT.Height) + ENDIF + ENDIF + + *-- RUNDA 11: geometria label-ului DUPA Show() - bug-ul live era ca Anchor setat inainte de Top + *-- il readucea sus peste banda de titlu, iar gridul (Anchor=15) se intindea de doua ori. + IF VARTYPE(goFormT.lb_anaf) = 'O' + IF goFormT.lb_anaf.Top >= goFormT._GRID1.Top + goFormT._GRID1.Height ; + AND goFormT.lb_anaf.Top + goFormT.lb_anaf.Height <= goFormT.Height ; + AND goFormT.lb_anaf.Top > 30 + DO VpaLog WITH 'PASS geometrie-label: lb_anaf sub grid si in forma (Top=' + TRANSFORM(goFormT.lb_anaf.Top) + ; + ' grid jos=' + TRANSFORM(goFormT._GRID1.Top + goFormT._GRID1.Height) + ' forma=' + TRANSFORM(goFormT.Height) + ')' + ELSE + DO VpaLog WITH 'FAIL geometrie-label: Top=' + TRANSFORM(goFormT.lb_anaf.Top) + ' inaltime label=' + TRANSFORM(goFormT.lb_anaf.Height) + ; + ' grid jos=' + TRANSFORM(goFormT._GRID1.Top + goFormT._GRID1.Height) + ' forma=' + TRANSFORM(goFormT.Height) + ENDIF + ENDIF +ENDPROC + +PROCEDURE AsteaptaTimer + LPARAMETERS toVerif + *-- LIMITARE CONFIRMATA (vezi raport): Timer.Interval (anaf_timer, 400ms) NU se declanseaza + *-- fiabil in acest runtime headless prin DOEVENTS FORCE + INKEY in bucla (testat: 1.5s asteptare, + *-- 0 apeluri) - WM_TIMER pare sa ceara o bucla de mesaje continua (READ EVENTS / Show(1) modal + *-- intern), nu pompari discrete. Apel DIRECT VerificaRand(.F.) - echivalent functional cu + *-- "timerul s-a declansat" - ca sa testez restul logicii (verdict/cache/dialog). Debounce-ul + *-- PROPRIU-ZIS (timerul reseteaza la fiecare navigare) e verificat separat, fara acest apel. + LOCAL loV + loV = IIF(VARTYPE(m.toVerif) = 'O', m.toVerif, poVerifAlegere) + IF VARTYPE(m.loV) = 'O' + m.loV.VerificaRand(.F.) + ENDIF + DOEVENTS FORCE +ENDPROC + +PROCEDURE VerificaLabelConcordant + *-- runda 17 (B2): textul spune acum "F4 = detalii" (nu "click detalii"); bold doar la avertisment. + LOCAL lcCap + lcCap = ALLTRIM(goFormT.lb_anaf.Caption) + IF 'ANAF:' $ m.lcCap AND 'F4 = detalii' $ m.lcCap AND goFormT.lb_anaf.ForeColor = RGB(0,128,0) AND !goFormT.lb_anaf.FontBold + DO VpaLog WITH 'PASS label-concordant: [' + m.lcCap + '] verde, fara bold' + ELSE + DO VpaLog WITH 'FAIL label-concordant: [' + m.lcCap + '] ForeColor=' + TRANSFORM(goFormT.lb_anaf.ForeColor) + ' Bold=' + TRANSFORM(goFormT.lb_anaf.FontBold) + ENDIF +ENDPROC + +PROCEDURE VerificaLabelDiscordant + *-- runda 17 (B2): discordanta e acum bold (SeteazaLabel: FontBold = tlAvertisment); text "F4 = detalii". + LOCAL lcCap + lcCap = ALLTRIM(goFormT.lb_anaf.Caption) + IF 'ANAF:' $ m.lcCap AND 'F4 = detalii' $ m.lcCap AND goFormT.lb_anaf.ForeColor = RGB(192,0,0) AND goFormT.lb_anaf.FontBold AND goFormT.lb_anaf.MousePointer = 15 + DO VpaLog WITH 'PASS label-discordant (B2): [' + m.lcCap + '] rosu, BOLD, cursor mana' + ELSE + DO VpaLog WITH 'FAIL label-discordant (B2): [' + m.lcCap + '] ForeColor=' + TRANSFORM(goFormT.lb_anaf.ForeColor) + ' Bold=' + TRANSFORM(goFormT.lb_anaf.FontBold) + ENDIF +ENDPROC + +PROCEDURE VerificaCodInvalid + *-- runda 15: validarea codului se face INAINTE de ANAF (fara apel), dupa TIP_PERSOANA din cursor + *-- (1 = juridica -> CIF, 2 = fizica -> CNP). + LOCAL lnInainte, lcCap + poVerifAlegere.nIdPart = 0 + lnInainte = gnANAFCallCount + SELECT ctestparteneri + LOCATE FOR id_part = gnIdCifInv + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + lcCap = ALLTRIM(goFormT.lb_anaf.Caption) + *-- runda 17 (B2): eticheta primeste sufixul "F4 = detalii" si e BOLD (avertisment), ca discordanta ANAF + IF m.lcCap == 'CIF invalid (1234567) (F4 = detalii)' AND goFormT.lb_anaf.ForeColor = RGB(192,0,0) AND goFormT.lb_anaf.FontBold ; + AND gnANAFCallCount = m.lnInainte + DO VpaLog WITH 'PASS cod-invalid-cif (B2): [' + m.lcCap + '] rosu, bold, fara apel ANAF' + ELSE + DO VpaLog WITH 'FAIL cod-invalid-cif (B2): [' + m.lcCap + '] ForeColor=' + TRANSFORM(goFormT.lb_anaf.ForeColor) + ; + ' Bold=' + TRANSFORM(goFormT.lb_anaf.FontBold) + ' apeluri=' + TRANSFORM(gnANAFCallCount - m.lnInainte) + ENDIF + + SELECT ctestparteneri + LOCATE FOR id_part = gnIdCnpInv + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + lcCap = ALLTRIM(goFormT.lb_anaf.Caption) + IF m.lcCap == 'CNP invalid (1234567890123) (F4 = detalii)' AND goFormT.lb_anaf.ForeColor = RGB(192,0,0) AND goFormT.lb_anaf.FontBold + DO VpaLog WITH 'PASS cod-invalid-cnp (B2): [' + m.lcCap + '] rosu, bold' + ELSE + DO VpaLog WITH 'FAIL cod-invalid-cnp (B2): [' + m.lcCap + '] ForeColor=' + TRANSFORM(goFormT.lb_anaf.ForeColor) + ' Bold=' + TRANSFORM(goFormT.lb_anaf.FontBold) + ENDIF + + SELECT ctestparteneri + LOCATE FOR id_part = gnIdPersfiz + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + lcCap = ALLTRIM(goFormT.lb_anaf.Caption) + IF EMPTY(m.lcCap) + DO VpaLog WITH 'PASS cod-valid-cnp: persoana fizica cu CNP valid - fara label, fara verificare ANAF' + ELSE + DO VpaLog WITH 'FAIL cod-valid-cnp: label neasteptat [' + m.lcCap + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaAlegereVarianta + *-- runda 15/16: la 2+ variante, "Nu" cere numarul variantei prin aInputBox (numar invalid = revine + *-- la mesaj); la o singura varianta se pastreaza comportamentul vechi (fara intrebare). + LOCAL llRez, lcM, lnInputInainte + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gcMockUltimMesaj = '' + gcMockUltimPrompt = '' + gnMockRaspuns = 7 + gnMockInputCount = 0 + gcMockInputSecventa = '0,2' && primul raspuns invalid (Renunta), al doilea = varianta 2 + PRIVATE poANAFInlocuire + poANAFInlocuire = .NULL. + llRez = poVerifAlegere.VerificaAlegere(goFormT) + lcM = gcMockUltimMesaj + IF m.llRez AND VARTYPE(poANAFInlocuire) = 'O' AND poANAFInlocuire.nIdPart = gnIdSpatiu ; + AND gnMockInputCount = 2 AND 'Nu = Alege din lista (1-2)' $ m.lcM AND '(1-2)' $ gcMockUltimPrompt + DO VpaLog WITH 'PASS varianta-aleasa: numar invalid -> revine la mesaj, apoi varianta 2 (id_part=' + ; + TRANSFORM(poANAFInlocuire.nIdPart) + '), apeluri aInputBox=' + TRANSFORM(gnMockInputCount) + ELSE + DO VpaLog WITH 'FAIL varianta-aleasa: llRez=' + TRANSFORM(m.llRez) + ' inlocuire=' + ; + TRANSFORM(IIF(VARTYPE(poANAFInlocuire) = 'O', poANAFInlocuire.nIdPart, -1)) + ' asteptat=' + TRANSFORM(gnIdSpatiu) + ; + ' apeluri=' + TRANSFORM(gnMockInputCount) + ' prompt=[' + gcMockUltimPrompt + '] mesaj=[' + STRTRAN(m.lcM, CHR(13), ' | ') + ']' + ENDIF + + *-- o singura varianta ramasa (perechea) - nu se mai cere numarul + =goExecutor.oExecuta([UPDATE NOM_PARTENERI SET STERS = 1 WHERE ID_PART = ] + TRANSFORM(gnIdSpatiu)) + =goExecutor.oExecuta('COMMIT') + gcMockUltimMesaj = '' + gnMockInputCount = 0 + gcMockInputSecventa = '' + poANAFInlocuire = .NULL. + llRez = poVerifAlegere.VerificaAlegere(goFormT) + lcM = gcMockUltimMesaj + IF m.llRez AND VARTYPE(poANAFInlocuire) = 'O' AND poANAFInlocuire.nIdPart = gnIdPereche ; + AND gnMockInputCount = 0 AND 'Nu = Alege 1 TEST ANAF DISCORD SRL' $ m.lcM + DO VpaLog WITH 'PASS varianta-unica: o singura varianta - fara intrebare, aleasa direct (id_part=' + ; + TRANSFORM(poANAFInlocuire.nIdPart) + ')' + ELSE + DO VpaLog WITH 'FAIL varianta-unica: llRez=' + TRANSFORM(m.llRez) + ' inlocuire=' + ; + TRANSFORM(IIF(VARTYPE(poANAFInlocuire) = 'O', poANAFInlocuire.nIdPart, -1)) + ' asteptat=' + TRANSFORM(gnIdPereche) + ; + ' apeluri=' + TRANSFORM(gnMockInputCount) + ' mesaj=[' + STRTRAN(m.lcM, CHR(13), ' | ') + ']' + ENDIF + =goExecutor.oExecuta([UPDATE NOM_PARTENERI SET STERS = 0 WHERE ID_PART = ] + TRANSFORM(gnIdSpatiu)) + =goExecutor.oExecuta('COMMIT') + gnMockRaspuns = 6 +ENDPROC + +PROCEDURE VerificaDebounce + LOCAL lnInainte + *-- reseteaza cache-ul de sesiune ca sa fim siguri ca fara debounce ar fi aparut apeluri noi + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + poVerifAlegere.nIdPart = 0 && forteaza "randul curent" sa difere, ca VerificaRand sa nu iasa devreme din cache local + lnInainte = gnANAFCallCount + SELECT ctestparteneri + LOCATE FOR id_part = gnIdConcord + goFormT._GRID1.AfterRowColChange(1) + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + LOCATE FOR id_part = gnIdNopereche + goFormT._GRID1.AfterRowColChange(1) + DOEVENTS FORCE + IF gnANAFCallCount = m.lnInainte + DO VpaLog WITH 'PASS debounce: 3 navigari rapide, 0 apeluri ANAF noi (timer resetat de fiecare data)' + ELSE + DO VpaLog WITH 'FAIL debounce: gnANAFCallCount a crescut cu ' + TRANSFORM(gnANAFCallCount - m.lnInainte) + ' in timpul navigarii rapide' + ENDIF + DO AsteaptaTimer + IF gnANAFCallCount = m.lnInainte + 1 + DO VpaLog WITH 'PASS debounce-final: dupa oprire pe ultimul rand (nopereche), exact 1 apel ANAF nou' + ELSE + DO VpaLog WITH 'FAIL debounce-final: gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(m.lnInainte+1) + ENDIF +ENDPROC + +PROCEDURE VerificaCache + LOCAL lnInainte, loForm2, loVerif2, lnOk + *-- pre-incalzeste cache-ul pt. CUI 7654320 (VerificaDebounce, care ruleaza inainte, RESETEAZA + *-- goCacheANAF_Sesiune la inceputul ei - fara acest pas, primul apel de mai jos ar fi cache-miss + *-- legitim, nu ce vreau sa testez aici: AL DOILEA apel, pe formular nou, e cache-hit). + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + lnInainte = gnANAFCallCount + *-- formular NOU (alta instanta anaf_verif_cautare), acelasi CUI (gnIdDiscord/7654320) deja + *-- verificat mai sus - goCacheANAF_Sesiune e PUBLIC, pe toata sesiunea, nu per-formular. + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdDiscord), 'ctestcache2') + loForm2 = CREATEOBJECT('cauta_alfa_form', 'ctestcache2', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loForm2.crs_cursor = 'ctestcache2' + loForm2.lAles = .F. + loVerif2 = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loForm2, 'oVerifAlegere', loVerif2) + loVerif2.Activeaza(loForm2) + loForm2.WindowType = 0 + loForm2.Show() + SELECT ctestcache2 + GO TOP + loForm2._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH loVerif2 + IF gnANAFCallCount = m.lnInainte AND 'F4 = detalii' $ ALLTRIM(loForm2.lb_anaf.Caption) + DO VpaLog WITH 'PASS cache: formular nou, acelasi CUI 7654320 - 0 apeluri ANAF noi, label tot discordant (din cache)' + ELSE + DO VpaLog WITH 'FAIL cache: gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(m.lnInainte) + ' label=[' + ALLTRIM(loForm2.lb_anaf.Caption) + ']' + ENDIF + TRY + loVerif2.Dezactiveaza() + DO VpaLog WITH 'PASS Dezactiveaza (cache, instanta 2): fara eroare (fix runda 10)' + CATCH TO loExcDez + DO VpaLog WITH 'FAIL Dezactiveaza (cache, instanta 2): ' + loExcDez.Message + ENDTRY + loForm2.Release() + IF USED('ctestcache2') + USE IN ctestcache2 + ENDIF +ENDPROC + +PROCEDURE VerificaDetalii + LOCAL lnLenInainte, lcLog, llClick + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + *-- runda 14: Detalii se declanseaza la Click simplu (Bindevent pe Click, nu pe DblClick) + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + goFormT.lb_anaf.Click() + llClick = 'MOCK amessagebox' $ SUBSTR(FILETOSTR(gcUILog), m.lnLenInainte + 1) + IF m.llClick + DO VpaLog WITH 'PASS detalii-click: click simplu pe label -> AMESSAGEBOX de detalii' + ELSE + DO VpaLog WITH 'FAIL detalii-click: click simplu pe label nu a deschis detaliile' + ENDIF + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + poVerifAlegere.Detalii() + lcLog = FILETOSTR(gcUILog) + lcLog = SUBSTR(m.lcLog, m.lnLenInainte + 1) + *-- runda 12: antet " (CUI: , ID: )" + lista "Parteneri ROA cu CUI :" + IF 'MOCK amessagebox' $ m.lcLog ; + AND ('TEST ANAF DISCORD SRL (CUI: 7654320, ID: ' + TRANSFORM(gnIdDiscord) + ')') $ m.lcLog ; + AND 'Parteneri ROA cu CUI RO7654320:' $ m.lcLog ; + AND ('1. TEST ANAF DISCORD SRL (ID: ' + TRANSFORM(gnIdPereche) + ') inactiv') $ m.lcLog ; + AND ('2. TEST ANAF SPATIU SRL (ID: ' + TRANSFORM(gnIdSpatiu) + ')') $ m.lcLog + DO VpaLog WITH 'PASS detalii: AMESSAGEBOX apelat cu antet + lista completa de candidati (inclusiv cod cu spatiu), cod fiscal corect RO7654320' + ELSE + DO VpaLog WITH 'FAIL detalii: log dupa apel = [' + m.lcLog + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaAlegereRapidaD2 + *-- D2: alege un rand FARA sa astepte timerul (VerificaRand(.T.) sincron in VerificaAlegere) + LOCAL lnInainte + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') && reset - CUI 1112223 nu a mai fost verificat "proaspat" pt. acest test + ENDIF + poVerifAlegere.nIdPart = 0 + SELECT ctestparteneri + LOCATE FOR id_part = gnIdConcord + goFormT._GRID1.AfterRowColChange(1) && porneste timer-ul, dar NU il astept + lnInainte = gnANAFCallCount + PRIVATE poANAFInlocuire + poANAFInlocuire = .NULL. + poVerifAlegere.nNivel = 3 && runda 17: verificarea sincrona la alegere exista doar la nivelul 3 + LOCAL llRez + llRez = poVerifAlegere.VerificaAlegere(goFormT) + IF gnANAFCallCount = m.lnInainte + 1 AND m.llRez + DO VpaLog WITH 'PASS D2-alegere-rapida: verificarea s-a facut SINCRON (apel ANAF imediat, fara sa astepte timerul), concordant -> continua' + ELSE + DO VpaLog WITH 'FAIL D2-alegere-rapida: gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(m.lnInainte+1) + ' llRez=' + TRANSFORM(m.llRez) + ENDIF + *-- lasa timerul ramas activ sa se stinga, ca sa nu interfereze cu pasii urmatori + DO AsteaptaTimer +ENDPROC + +PROCEDURE VerificaKillSwitch + *-- RE-TEST RUNDA 10: kill-switch mutat la instantierea poVerifAlegere in apelanti + *-- (CautPartenerContabilitate/caut_parteneri) - cu switch OFF, poVerifAlegere ramane .NULL. + *-- si Activeaza NU se mai apeleaza deloc. Replic aici EXACT conditia din productie + *-- (Alltrim(Nvl(getini(...),'')) <> '0'), fara sa creez deloc anaf_verif_cautare cand e OFF. + LOCAL lcOrig, lnInainte, loFormK, loVerifK, lnOk, llActiveaza + lcOrig = getini(gcGeneralIniFile, 'anaf', 'verificare_selectie') + DO VpaLog WITH 'kill-switch: valoare originala=[' + TRANSFORM(NVL(m.lcOrig,'.NULL.')) + ']' + TRY + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '0') + lnInainte = gnANAFCallCount + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdDiscord), 'ctestkill') + loFormK = CREATEOBJECT('cauta_alfa_form', 'ctestkill', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormK.crs_cursor = 'ctestkill' + loFormK.lAles = .F. + LOCAL lnInaltimeK + lnInaltimeK = loFormK.Height + *-- aceeasi conditie ca in CautPartenerContabilitate/caut_parteneri (ocautare.prg) + llActiveaza = (Alltrim(Nvl(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) <> '0') + IF m.llActiveaza + loVerifK = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormK, 'oVerifAlegere', loVerifK) + loVerifK.Activeaza(loFormK) + ENDIF + loFormK.WindowType = 0 + loFormK.Show() + SELECT ctestkill + GO TOP + loFormK._GRID1.AfterRowColChange(1) + DOEVENTS FORCE + IF gnANAFCallCount = m.lnInainte AND loFormK.Height = m.lnInaltimeK AND !PEMSTATUS(loFormK, 'lb_anaf', 5) + DO VpaLog WITH 'PASS kill-switch: verificare_selectie=0 -> nimic nu se ataseaza (poVerifAlegere=.NULL.), 0 apeluri ANAF, fara lb_anaf, inaltime neschimbata (' + TRANSFORM(loFormK.Height) + ')' + ELSE + DO VpaLog WITH 'FAIL kill-switch: gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(m.lnInainte) + ' inaltime=' + TRANSFORM(loFormK.Height) + '/' + TRANSFORM(m.lnInaltimeK) + ' PEMSTATUS lb_anaf=' + TRANSFORM(PEMSTATUS(loFormK,'lb_anaf',5)) + ENDIF + IF VARTYPE(loVerifK) = 'O' + loVerifK.Dezactiveaza() + ENDIF + loFormK.Release() + IF USED('ctestkill') + USE IN ctestkill + ENDIF + CATCH TO loExcK + DO VpaLog WITH 'FAIL kill-switch (exceptie): ' + loExcK.Message + FINALLY + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', NVL(m.lcOrig,'')) + DO VpaLog WITH 'kill-switch: restaurat la [' + TRANSFORM(NVL(m.lcOrig,'')) + ']' + ENDTRY +ENDPROC + +PROCEDURE VerificaRegresieNonPartener + *-- cautare generica FARA activare ANAF (poVerifAlegere ramane .NULL. - ca la orice + *-- nomenclator care nu e partener, ex. cont/articol): fara oVerifAlegere atasat deloc. + LOCAL loFormR, lnInaltimeOrig, lnOk + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdConcord), 'ctestregr') + loFormR = CREATEOBJECT('cauta_alfa_form', 'ctestregr', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormR.crs_cursor = 'ctestregr' + loFormR.lAles = .F. + lnInaltimeOrig = loFormR.Height + *-- FARA AddProperty('oVerifAlegere',...) - simuleaza cauta_alfa()/CautPartenerContabilitate() + *-- apelate cu hook-ul dezactivat (llNuVerificaANAF / tlVerificaANAF=.F., cazul implicit + *-- caut_parteneri fara activare explicita) + loFormR.WindowType = 0 + loFormR.Show() + SELECT ctestregr + GO TOP + loFormR._GRID1.AfterRowColChange(1) + DOEVENTS FORCE + IF loFormR.Height = m.lnInaltimeOrig AND PEMSTATUS(loFormR, 'lb_anaf', 5) = .F. + DO VpaLog WITH 'PASS regresie-non-ANAF: fara oVerifAlegere -> fara lb_anaf, inaltime neschimbata (' + TRANSFORM(loFormR.Height) + ')' + ELSE + DO VpaLog WITH 'FAIL regresie-non-ANAF: inaltime=' + TRANSFORM(loFormR.Height) + '/' + TRANSFORM(m.lnInaltimeOrig) + ' PEMSTATUS lb_anaf=' + TRANSFORM(PEMSTATUS(loFormR,'lb_anaf',5)) + ENDIF + loFormR.Release() + IF USED('ctestregr') + USE IN ctestregr + ENDIF +ENDPROC + +PROCEDURE VerificaMesajDecizie + *-- runda 11: mesajul e scurt si structurat, iar dialogul e AMESSAGEBOX tip 3+48 (Da/Nu/Abandon). + LOCAL llRez, lcM, llLinii, llLista + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gcMockUltimMesaj = '' + gnMockUltimTip = 0 + gnMockRaspuns = 6 + PRIVATE poANAFInlocuire + poANAFInlocuire = .NULL. + llRez = poVerifAlegere.VerificaAlegere(goFormT) + lcM = gcMockUltimMesaj + + *-- runda 14: antet " (CUI: , ID: )" + "ANAF: (, ) la ", fara "!" + llLinii = OCCURS(CHR(13), m.lcM) >= 3 AND 'ANAF: Platitor TVA' $ m.lcM AND !('! ANAF:' $ m.lcM) ; + AND ('(CUI: 7654320, ID: ' + TRANSFORM(gnIdDiscord) + ')') $ m.lcM + llLista = 'Parteneri ROA cu CUI RO7654320:' $ m.lcM AND ('1. TEST ANAF DISCORD SRL (ID: ' + TRANSFORM(gnIdPereche) + ') inactiv') $ m.lcM ; + AND ('2. TEST ANAF SPATIU SRL (ID: ' + TRANSFORM(gnIdSpatiu) + ')') $ m.lcM ; + AND 'Nu = Alege din lista (1-2)' $ m.lcM ; + AND 'Da = Pastreaza selectia' $ m.lcM AND 'Abandon = Inapoi la cautare' $ m.lcM + IF m.llLinii AND m.llLista AND gnMockUltimTip = 51 + DO VpaLog WITH 'PASS mesaj-decizie: 3 linii + lista numerotata, tip=51 (3+48) - [' + STRTRAN(m.lcM, CHR(13), ' | ') + ']' + ELSE + DO VpaLog WITH 'FAIL mesaj-decizie: linii=' + TRANSFORM(m.llLinii) + ' lista=' + TRANSFORM(m.llLista) + ; + ' tip=' + TRANSFORM(gnMockUltimTip) + ' mesaj=[' + STRTRAN(m.lcM, CHR(13), ' | ') + ']' + ENDIF +ENDPROC + +PROCEDURE PregatesteFormularD1a + *-- reface goFormT (a fost Release-uit dupa scenariile 1-8) pozitionat pe randul discordant + *-- CU pereche (gnIdDiscord), pentru scenariile de VerificaAlegere end-to-end (dialog real). + LOCAL lnOk + IF VARTYPE(goFormT) = 'O' + TRY + goFormT.Release() + CATCH + ENDTRY + ENDIF + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + IF USED('ctestparteneri') + USE IN ctestparteneri + ENDIF + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART IN (] + TRANSFORM(gnIdConcord) + [,] + TRANSFORM(gnIdDiscord) + [,] + TRANSFORM(gnIdPereche) + [,] + ; + TRANSFORM(gnIdNopereche) + [) AND INACTIV = 0 ORDER BY ID_PART], 'ctestparteneri') + PUBLIC goFormT, poVerifAlegere + goFormT = CREATEOBJECT('cauta_alfa_form', 'ctestparteneri', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + goFormT.crs_cursor = 'ctestparteneri' + goFormT.lAles = .F. + poVerifAlegere = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(goFormT, 'oVerifAlegere', poVerifAlegere) + poVerifAlegere.Activeaza(goFormT) + poVerifAlegere.nNivel = 3 && runda 17: dialogul de confirmare exista doar la nivelul 3 (opt-in) + goFormT.WindowType = 0 + goFormT.Show() +ENDPROC + +PROCEDURE VerificaAlegereD1aButonPereche + *-- clic pe butonul 1 (Alege perechea) - poANAFInlocuire trebuie sa fie perechea (gnIdPereche) + LOCAL llRez, lnInactivInainte + *-- verificare Oracle INAINTE (fara reactivare - vezi si verificarea de dupa, mai jos) + lnInactivInainte = 0 + =goExecutor.oSelect2Value([SELECT INACTIV AS NR FROM NOM_PARTENERI WHERE ID_PART = ] + TRANSFORM(gnIdPereche), @lnInactivInainte) + DO VpaLog WITH 'DEBUG fara-reactivare: INACTIV INAINTE de alegere = ' + TRANSFORM(m.lnInactivInainte) + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gnMockRaspuns = 7 && Nu + PRIVATE poANAFInlocuire + poANAFInlocuire = .NULL. + llRez = poVerifAlegere.VerificaAlegere(goFormT) + + IF m.llRez AND VARTYPE(poANAFInlocuire) = 'O' AND poANAFInlocuire.nIdPart = gnIdPereche AND poANAFInlocuire.cCodFiscal == 'RO7654320' + DO VpaLog WITH 'PASS D1a-alege-perechea: raspuns Nu (7), poANAFInlocuire.nIdPart=' + TRANSFORM(gnIdPereche) + ' (perechea INACTIVA, doar folosita - NU reactivata)' + ELSE + DO VpaLog WITH 'FAIL D1a-alege-perechea: llRez=' + TRANSFORM(m.llRez) + ' poANAFInlocuire=' + TRANSFORM(VARTYPE(poANAFInlocuire)) + ENDIF + + *-- verificare FARA REACTIVARE: randul pereche ramane INACTIV=1 in Oracle (nicio scriere) - + *-- comparat explicit INAINTE vs DUPA (nu doar valoarea absoluta), cum a cerut orchestratorul. + LOCAL lnInactivDupa + lnInactivDupa = 0 + =goExecutor.oSelect2Value([SELECT INACTIV AS NR FROM NOM_PARTENERI WHERE ID_PART = ] + TRANSFORM(gnIdPereche), @lnInactivDupa) + DO VpaLog WITH 'DEBUG fara-reactivare: INACTIV DUPA alegere = ' + TRANSFORM(m.lnInactivDupa) + IF m.lnInactivDupa = m.lnInactivInainte AND m.lnInactivDupa = 1 + DO VpaLog WITH 'PASS fara-reactivare: NOM_PARTENERI.INACTIV neschimbat (inainte=' + TRANSFORM(m.lnInactivInainte) + ' dupa=' + TRANSFORM(m.lnInactivDupa) + ', ambele =1) dupa alegerea perechii (nicio scriere in Oracle)' + ELSE + DO VpaLog WITH 'FAIL fara-reactivare: INACTIV inainte=' + TRANSFORM(m.lnInactivInainte) + ' dupa=' + TRANSFORM(m.lnInactivDupa) + ' (astept ambele =1, neschimbat)' + ENDIF +ENDPROC + +PROCEDURE VerificaAlegereD1aButonAles + *-- raspuns Da (6) - pastreaza selectia curenta: llRez=.T., poANAFInlocuire ramane .NULL. + LOCAL llRez + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gnMockRaspuns = 6 && Da + PRIVATE poANAFInlocuire + poANAFInlocuire = .NULL. + llRez = poVerifAlegere.VerificaAlegere(goFormT) + + IF m.llRez AND ISNULL(poANAFInlocuire) + DO VpaLog WITH 'PASS D1a-alege-ales: raspuns Da (6), pastreaza alegerea initiala (poANAFInlocuire=.NULL.)' + ELSE + DO VpaLog WITH 'FAIL D1a-alege-ales: llRez=' + TRANSFORM(m.llRez) + ' poANAFInlocuire=' + TRANSFORM(VARTYPE(poANAFInlocuire)) + ENDIF +ENDPROC + +PROCEDURE VerificaAlegereD1aRenunta + *-- raspuns Abandon (2) - llRez=.F. (ramai in cautare, formularul NU se inchide) + LOCAL llRez + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gnMockRaspuns = 2 && Abandon + llRez = poVerifAlegere.VerificaAlegere(goFormT) + + IF !m.llRez AND goFormT.Visible + DO VpaLog WITH 'PASS D1a-renunta: raspuns Abandon (2), llRez=.F., formularul de cautare RAMANE deschis' + ELSE + DO VpaLog WITH 'FAIL D1a-renunta: llRez=' + TRANSFORM(m.llRez) + ' Visible=' + TRANSFORM(goFormT.Visible) + ENDIF +ENDPROC + +PROCEDURE VerificaAlegereFaraPereche + *-- randul nopereche (discordant, FARA pereche) - dialog OK/Abandon (tip 1+48), raspuns OK (1) + LOCAL llRez + SELECT ctestparteneri + LOCATE FOR id_part = gnIdNopereche + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + gcMockUltimMesaj = '' + gnMockUltimTip = 0 + gnMockRaspuns = 1 && OK + llRez = poVerifAlegere.VerificaAlegere(goFormT) + + IF m.llRez AND gnMockUltimTip = 49 ; + AND 'Nu exista partener cu CUI RO9000004 (il puteti crea cu butonul Nou).' $ gcMockUltimMesaj ; + AND 'De acord = Pastreaza selectia' $ gcMockUltimMesaj AND 'Abandon = Inapoi la cautare' $ gcMockUltimMesaj + DO VpaLog WITH 'PASS fara-pereche-continua: raspuns OK (1), tip=49 (1+48), llRez=.T. - [' + STRTRAN(gcMockUltimMesaj, CHR(13), ' | ') + ']' + ELSE + DO VpaLog WITH 'FAIL fara-pereche-continua: llRez=' + TRANSFORM(m.llRez) + ' tip=' + TRANSFORM(gnMockUltimTip) + ; + ' mesaj=[' + STRTRAN(gcMockUltimMesaj, CHR(13), ' | ') + ']' + ENDIF + + TRY + goFormT.oVerifAlegere.Dezactiveaza() + DO VpaLog WITH 'PASS Dezactiveaza (fara-pereche): fara eroare (fix runda 10)' + CATCH TO loExcDezFP + DO VpaLog WITH 'FAIL Dezactiveaza (fara-pereche): ' + loExcDezFP.Message + ENDTRY + TRY + goFormT.Release() + CATCH + ENDTRY +ENDPROC + +PROCEDURE VerificaDataDocument + *-- runda 12: dDataDoc explicit pe anaf_verif_cautare - trebuie sa ajunga la mock (gdANAFUltimaData) + *-- si sa apara in textul labelului ("... la " + Dtoc(data)). Instanta proprie (nu goFormT/poVerifAlegere + *-- - eliberate dupa scenariul 10), pe randul concordant (gnIdConcord), ca sa nu depinda de dialog. + LOCAL loFormD, loVerifD, lnOk, ldDataDoc, lcCap + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + ldDataDoc = {^2026/06/15} + gdANAFUltimaData = {} + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdConcord), 'ctestdatadoc') + loFormD = CREATEOBJECT('cauta_alfa_form', 'ctestdatadoc', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormD.crs_cursor = 'ctestdatadoc' + loFormD.lAles = .F. + loVerifD = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormD, 'oVerifAlegere', loVerifD) + loVerifD.dDataDoc = ldDataDoc + loVerifD.Activeaza(loFormD) + loFormD.WindowType = 0 + loFormD.Show() + SELECT ctestdatadoc + GO TOP + loFormD._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH loVerifD + lcCap = ALLTRIM(loFormD.lb_anaf.Caption) + IF gdANAFUltimaData == ldDataDoc AND (' la ' + DTOC(ldDataDoc)) $ lcCap + DO VpaLog WITH 'PASS data-document: mock a primit data documentului (' + DTOC(ldDataDoc) + '), label=[' + lcCap + ']' + ELSE + DO VpaLog WITH 'FAIL data-document: gdANAFUltimaData=' + TRANSFORM(gdANAFUltimaData) + ' astept=' + DTOC(ldDataDoc) + ' label=[' + lcCap + ']' + ENDIF + loVerifD.Dezactiveaza() + loFormD.Release() + IF USED('ctestdatadoc') + USE IN ctestdatadoc + ENDIF +ENDPROC + +PROCEDURE VerificaCacheData + *-- runda 12: cheia de cache pe sesiune e 'C'+CUI+'_'+Dtos(data) - acelasi CUI la 2 date diferite + *-- => 2 apeluri ANAF noi (chei diferite); acelasi CUI la ACEEASI data => 1 singur apel (cache-hit). + LOCAL lnOk, ldData1, ldData2, lnInainte + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + ldData1 = {^2026/03/10} + ldData2 = {^2026/04/20} + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdConcord), 'ctestcachedata') + lnInainte = gnANAFCallCount + + DO VerificaCacheDataUnRand WITH ldData1, 'ctestcachedata' + IF gnANAFCallCount = lnInainte + 1 + DO VpaLog WITH 'PASS cache-data (data1): prima verificare la ' + DTOC(ldData1) + ' - 1 apel ANAF nou' + ELSE + DO VpaLog WITH 'FAIL cache-data (data1): gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(lnInainte + 1) + ENDIF + + DO VerificaCacheDataUnRand WITH ldData1, 'ctestcachedata' + IF gnANAFCallCount = lnInainte + 1 + DO VpaLog WITH 'PASS cache-data (data1 repetata): ACEEASI data - 0 apeluri noi (cache-hit)' + ELSE + DO VpaLog WITH 'FAIL cache-data (data1 repetata): gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(lnInainte + 1) + ENDIF + + DO VerificaCacheDataUnRand WITH ldData2, 'ctestcachedata' + IF gnANAFCallCount = lnInainte + 2 + DO VpaLog WITH 'PASS cache-data (data2): data DIFERITA (' + DTOC(ldData2) + ') - 1 apel ANAF nou (chei de cache diferite)' + ELSE + DO VpaLog WITH 'FAIL cache-data (data2): gnANAFCallCount=' + TRANSFORM(gnANAFCallCount) + ' astept=' + TRANSFORM(lnInainte + 2) + ENDIF + + IF USED('ctestcachedata') + USE IN ctestcachedata + ENDIF +ENDPROC + +PROCEDURE VerificaCacheDataUnRand + *-- instanta NOUA de anaf_verif_cautare (nIdPart porneste de la 0) pe fiecare apel - altfel + *-- VerificaRand iese devreme din cache local (This.nIdPart), nu ajunge la goCacheANAF_Sesiune. + LPARAMETERS tdData, tcCursor + LOCAL loFormC, loVerifC + loFormC = CREATEOBJECT('cauta_alfa_form', tcCursor, '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormC.crs_cursor = tcCursor + loFormC.lAles = .F. + loVerifC = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormC, 'oVerifAlegere', loVerifC) + loVerifC.dDataDoc = tdData + loVerifC.Activeaza(loFormC) + loFormC.WindowType = 0 + loFormC.Show() + SELECT (tcCursor) + GO TOP + loFormC._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH loVerifC + loVerifC.Dezactiveaza() + loFormC.Release() +ENDPROC + +PROCEDURE VerificaDataFallback + *-- runda 12: dDataDoc gol (valoarea implicita {} din DEFINE CLASS) => ANAF_StarePartener / + *-- ANAF_VerificaCuiSingle folosesc Date() curent (fallback). + LOCAL loFormF, loVerifF, lnOk, lcCap + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + gdANAFUltimaData = {} + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdConcord), 'ctestfallback') + loFormF = CREATEOBJECT('cauta_alfa_form', 'ctestfallback', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormF.crs_cursor = 'ctestfallback' + loFormF.lAles = .F. + loVerifF = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormF, 'oVerifAlegere', loVerifF) + loVerifF.Activeaza(loFormF) + loFormF.WindowType = 0 + loFormF.Show() + SELECT ctestfallback + GO TOP + loFormF._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH loVerifF + lcCap = ALLTRIM(loFormF.lb_anaf.Caption) + IF gdANAFUltimaData == DATE() AND (' la ' + DTOC(DATE())) $ lcCap + DO VpaLog WITH 'PASS data-fallback: dDataDoc gol -> Date() curent (' + DTOC(DATE()) + ') folosit, label=[' + lcCap + ']' + ELSE + DO VpaLog WITH 'FAIL data-fallback: gdANAFUltimaData=' + TRANSFORM(gdANAFUltimaData) + ' Date()=' + DTOC(DATE()) + ' label=[' + lcCap + ']' + ENDIF + loVerifF.Dezactiveaza() + loFormF.Release() + IF USED('ctestfallback') + USE IN ctestfallback + ENDIF +ENDPROC + +PROCEDURE VerificaDataPoAct + *-- runda 14: dDataDoc gol, dar poAct.dataact vizibil in stiva (ca in formularele de + *-- introduceri, unde poAct e PRIVATE in lans()/viz_act) => se verifica la data documentului. + PRIVATE poAct + LOCAL loFormP, loVerifP, lnOk, lcCap, ldDoc + ldDoc = DATE() - 40 + poAct = CREATEOBJECT('Empty') + ADDPROPERTY(poAct, 'dataact', m.ldDoc) + IF TYPE('goCacheANAF_Sesiune') = 'O' + goCacheANAF_Sesiune = CREATEOBJECT('Collection') + ENDIF + gdANAFUltimaData = {} + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdConcord), 'ctestpoact') + loFormP = CREATEOBJECT('cauta_alfa_form', 'ctestpoact', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormP.crs_cursor = 'ctestpoact' + loFormP.lAles = .F. + loVerifP = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormP, 'oVerifAlegere', loVerifP) + loVerifP.Activeaza(loFormP) + loFormP.WindowType = 0 + loFormP.Show() + SELECT ctestpoact + GO TOP + loFormP._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH loVerifP + lcCap = ALLTRIM(loFormP.lb_anaf.Caption) + IF gdANAFUltimaData == m.ldDoc AND (' la ' + DTOC(m.ldDoc)) $ lcCap + DO VpaLog WITH 'PASS data-poact: dDataDoc gol + poAct.dataact (' + DTOC(m.ldDoc) + ') -> data documentului folosita, label=[' + lcCap + ']' + ELSE + DO VpaLog WITH 'FAIL data-poact: gdANAFUltimaData=' + TRANSFORM(gdANAFUltimaData) + ' poAct.dataact=' + DTOC(m.ldDoc) + ' label=[' + lcCap + ']' + ENDIF + loVerifP.Dezactiveaza() + loFormP.Release() + IF USED('ctestpoact') + USE IN ctestpoact + ENDIF +ENDPROC + +PROCEDURE RuleazaIzolat + *-- izoleaza fiecare scenariu nou REVIZIA 4 - o eroare neasteptata intr-unul singur nu opreste + *-- restul suitei (spre deosebire de eroarea din TRY-ul principal, care oricum face QUIT). + LPARAMETERS tcProcedura + LOCAL loExcIz + TRY + DO (tcProcedura) + CATCH TO loExcIz + DO VpaLog WITH 'FAIL ' + tcProcedura + ' (EXCEPTIE): ErrorNo=' + TRANSFORM(loExcIz.ErrorNo) + ; + ' Message=' + loExcIz.Message + ' Proc=' + loExcIz.Procedure + ' Line=' + TRANSFORM(loExcIz.LineNo) + ENDTRY +ENDPROC + +PROCEDURE VerificaCascadaOptiuni + *-- REVIZIA 4 pct.1: ini '0' bate tot; utilizator bate firma; firma bate hardcodatul; + *-- absent != 0 (H7); fara crsOptiuni/crsOptiuniUtilizator -> fara eroare (nivel hardcodat). + LOCAL lcOptIni, lnNivel, llAveaRandFirma, lcValOrigFirma, llAveaRandUtil, lcValOrigUtil + LOCAL lcAliasInainte, lcAliasDupa, llEroareCascada, loExcCasc + + lcOptIni = getini(gcGeneralIniFile, 'anaf', 'verificare_selectie') + llAveaRandFirma = .F. + lcValOrigFirma = '' + IF USED('crsOptiuni') + SELECT crsOptiuni + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + llAveaRandFirma = FOUND() + IF llAveaRandFirma + lcValOrigFirma = varvalue + ENDIF + ENDIF + + *=== a) kill-switch ini='0' bate tot (chiar cu firma=3) === + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '0') + IF USED('crsOptiuni') + SELECT crsOptiuni + IF llAveaRandFirma + REPLACE varvalue WITH '3' + ELSE + INSERT INTO crsOptiuni (varname, varvalue) VALUES ('RC_ANAF_VERIF_SELECTIE', '3') + ENDIF + ENDIF + RELEASE goCacheANAF_Nivel + lnNivel = ANAF_NivelVerificare() + IF lnNivel = 0 + DO VpaLog WITH 'PASS cascada-kill-switch: ini=0 bate tot (firma=3) -> nivel=0' + ELSE + DO VpaLog WITH 'FAIL cascada-kill-switch: nivel=' + TRANSFORM(lnNivel) + ' astept=0' + ENDIF + + *=== b) firma bate hardcodatul (fara kill-switch, fara utilizator) === + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '1') + RELEASE goCacheANAF_Nivel + lnNivel = ANAF_NivelVerificare() + IF lnNivel = 3 + DO VpaLog WITH 'PASS cascada-firma: fara kill-switch, fara utilizator, firma=3 -> nivel=3 (bate hardcodatul 1)' + ELSE + DO VpaLog WITH 'FAIL cascada-firma: nivel=' + TRANSFORM(lnNivel) + ' astept=3' + ENDIF + + *=== c) utilizator bate firma === + IF !USED('crsOptiuniUtilizator') + =actualizeaza_optiuni_utilizator() + ENDIF + llAveaRandUtil = .F. + lcValOrigUtil = '' + IF USED('crsOptiuniUtilizator') + SELECT crsOptiuniUtilizator + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + llAveaRandUtil = FOUND() + IF llAveaRandUtil + lcValOrigUtil = varvalue + REPLACE varvalue WITH '2' + ELSE + INSERT INTO crsOptiuniUtilizator (varname, varvalue) VALUES ('RC_ANAF_VERIF_SELECTIE', '2') + ENDIF + ENDIF + RELEASE goCacheANAF_Nivel + lnNivel = ANAF_NivelVerificare() + IF lnNivel = 2 + DO VpaLog WITH 'PASS cascada-utilizator: utilizator=2 bate firma=3 -> nivel=2' + ELSE + DO VpaLog WITH 'FAIL cascada-utilizator: nivel=' + TRANSFORM(lnNivel) + ' astept=2' + ENDIF + + *=== d) absent != 0 (H7): fara utilizator, fara firma -> hardcodat 1, NU 0 === + IF USED('crsOptiuniUtilizator') + SELECT crsOptiuniUtilizator + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + IF FOUND() + IF llAveaRandUtil + REPLACE varvalue WITH lcValOrigUtil + ELSE + DELETE + ENDIF + ENDIF + ENDIF + IF USED('crsOptiuni') + SELECT crsOptiuni + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + IF FOUND() + IF llAveaRandFirma + REPLACE varvalue WITH lcValOrigFirma + ELSE + DELETE + ENDIF + ENDIF + ENDIF + RELEASE goCacheANAF_Nivel + lnNivel = ANAF_NivelVerificare() + IF lnNivel = 1 + DO VpaLog WITH 'PASS cascada-absent (H7): fara ini-kill-switch/utilizator/firma -> nivel=1 (NU 0)' + ELSE + DO VpaLog WITH 'FAIL cascada-absent (H7): nivel=' + TRANSFORM(lnNivel) + ' astept=1' + ENDIF + + *=== e) fara crsOptiuni/crsOptiuniUtilizator deloc -> fara eroare, nivel hardcodat, Alias() neschimbat === + *-- zona de lucru neutra INAINTE de a inchide cursoarele - altfel USE IN pe alias-ul curent + *-- goleste singur Alias(), fals-negativ nelegat de H6 (ANAF_NivelVerificare nu e cauza). + SELECT dual + lcAliasInainte = ALIAS() + llEroareCascada = .F. + IF USED('crsOptiuniUtilizator') + USE IN crsOptiuniUtilizator + ENDIF + IF USED('crsOptiuni') + USE IN crsOptiuni + ENDIF + RELEASE goCacheANAF_Nivel + TRY + lnNivel = ANAF_NivelVerificare() + CATCH TO loExcCasc + llEroareCascada = .T. + lnNivel = -99 + ENDTRY + lcAliasDupa = ALIAS() + IF !llEroareCascada AND lnNivel = 1 + DO VpaLog WITH 'PASS cascada-fara-cursoare: crsOptiuni/crsOptiuniUtilizator inchise -> fara eroare, nivel=1' + ELSE + DO VpaLog WITH 'FAIL cascada-fara-cursoare: eroare=' + TRANSFORM(llEroareCascada) + ' nivel=' + TRANSFORM(lnNivel) + ENDIF + IF lcAliasInainte == lcAliasDupa + DO VpaLog WITH 'PASS cascada-alias (H6, fara cursoare): Alias() neschimbat [' + lcAliasDupa + ']' + ELSE + DO VpaLog WITH 'FAIL cascada-alias (H6, fara cursoare): inainte=[' + lcAliasInainte + '] dupa=[' + lcAliasDupa + ']' + ENDIF + + *-- restaureaza mediul (numai date locale/ini - nicio scriere in Oracle in aceasta procedura) + =actualizeaza_optiuni() + =actualizeaza_optiuni_utilizator() + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', NVL(lcOptIni, '')) + RELEASE goCacheANAF_Nivel +ENDPROC + +PROCEDURE VerificaGatingNivel + *-- REVIZIA 4 pct.2/3/12: replica gating-ul din CautPartenerContabilitate (ocautare.prg:834-844). + LOCAL lVerificaANAF, lnNivelANAF, lnInainte, lcOptIni, loFormG, lnOk, lcCapG, llLabelOk, llRezG + PRIVATE poVerifAlegereG + poVerifAlegereG = .NULL. + + *=== 12) regresie: apelant FARA lVerificaANAF=>1 -> poVerifAlegere ramane .NULL. === + lVerificaANAF = .F. + IF m.lVerificaANAF + lnNivelANAF = ANAF_NivelVerificare() + IF m.lnNivelANAF > 0 + poVerifAlegereG = CREATEOBJECT('anaf_verif_cautare') + ENDIF + ENDIF + IF ISNULL(poVerifAlegereG) + DO VpaLog WITH 'PASS gating-regresie (12): lVerificaANAF=.F. -> poVerifAlegere ramane .NULL.' + ELSE + DO VpaLog WITH 'FAIL gating-regresie (12): poVerifAlegere s-a instantiat fara lVerificaANAF=>1' + ENDIF + + *=== 3) nivel 0 (kill-switch): opt-in cerut, dar nivelul=0 -> poVerifAlegere ramane .NULL., 0 apeluri === + lcOptIni = getini(gcGeneralIniFile, 'anaf', 'verificare_selectie') + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '0') + RELEASE goCacheANAF_Nivel + poVerifAlegereG = .NULL. + lVerificaANAF = .T. + lnInainte = gnANAFCallCount + IF m.lVerificaANAF + lnNivelANAF = ANAF_NivelVerificare() + IF m.lnNivelANAF > 0 + poVerifAlegereG = CREATEOBJECT('anaf_verif_cautare') + ENDIF + ENDIF + IF ISNULL(poVerifAlegereG) AND lnNivelANAF = 0 AND gnANAFCallCount = lnInainte + DO VpaLog WITH 'PASS gating-nivel0 (3): kill-switch=0, opt-in -> poVerifAlegere ramane .NULL., 0 apeluri ANAF' + ELSE + DO VpaLog WITH 'FAIL gating-nivel0 (3): nivel=' + TRANSFORM(lnNivelANAF) + ' poVerifAlegere=' + TRANSFORM(VARTYPE(poVerifAlegereG)) + ' apeluri=' + TRANSFORM(gnANAFCallCount-lnInainte) + ENDIF + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', NVL(lcOptIni,'')) + RELEASE goCacheANAF_Nivel + + *=== 2) nivel 1 (implicit): label prezent, VerificaAlegere NU face apel HTTP la alegere === + lnNivelANAF = ANAF_NivelVerificare() + IF lnNivelANAF <= 0 OR lnNivelANAF >= 3 + DO VpaLog WITH 'FAIL gating-nivel1 (2): mediul nu e la nivelul implicit asteptat (nivel=' + TRANSFORM(lnNivelANAF) + '), test omis' + ELSE + lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ; + [WHERE ID_PART = ] + TRANSFORM(gnIdDiscord), 'ctestgating1') + loFormG = CREATEOBJECT('cauta_alfa_form', 'ctestgating1', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ; + 'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '') + loFormG.crs_cursor = 'ctestgating1' + loFormG.lAles = .F. + poVerifAlegereG = CREATEOBJECT('anaf_verif_cautare') + ADDPROPERTY(loFormG, 'oVerifAlegere', poVerifAlegereG) + poVerifAlegereG.nNivel = lnNivelANAF + poVerifAlegereG.Activeaza(loFormG) + loFormG.WindowType = 0 + loFormG.Show() + SELECT ctestgating1 + GO TOP + loFormG._GRID1.AfterRowColChange(1) + DO AsteaptaTimer WITH poVerifAlegereG + lcCapG = ALLTRIM(loFormG.lb_anaf.Caption) + llLabelOk = 'ANAF:' $ lcCapG + lnInainte = gnANAFCallCount + llRezG = poVerifAlegereG.VerificaAlegere(loFormG) + IF llLabelOk AND llRezG AND gnANAFCallCount = lnInainte + DO VpaLog WITH 'PASS gating-nivel1 (2): label prezent [' + lcCapG + '], VerificaAlegere -> 0 apeluri ANAF noi, llRez=.T.' + ELSE + DO VpaLog WITH 'FAIL gating-nivel1 (2): label=[' + lcCapG + '] llRez=' + TRANSFORM(llRezG) + ' apeluri=' + TRANSFORM(gnANAFCallCount-lnInainte) + ENDIF + poVerifAlegereG.Dezactiveaza() + loFormG.Release() + IF USED('ctestgating1') + USE IN ctestgating1 + ENDIF + ENDIF +ENDPROC + +PROCEDURE VerificaC2Renunta + *-- REVIZIA 4 C2 (cel mai important): poANAFInlocuire setat + gnbuton=2 (Renunta) => + *-- AplicaInlocuirePartenerANAF NU se apeleaza, obiectul intors ramane blank (id_part=0). + LOCAL loCauta + PRIVATE poANAFInlocuire, gnbuton + poANAFInlocuire = CREATEOBJECT('Empty') + ADDPROPERTY(poANAFInlocuire, 'nIdPart', gnIdPereche) + ADDPROPERTY(poANAFInlocuire, 'cDenumire', 'TEST ANAF DISCORD SRL') + ADDPROPERTY(poANAFInlocuire, 'cCodFiscal', 'RO7654320') + loCauta = CREATEOBJECT('Empty') + ADDPROPERTY(loCauta, 'id_part', 0) + ADDPROPERTY(loCauta, 'denumire', '') + ADDPROPERTY(loCauta, 'nume', '') + ADDPROPERTY(loCauta, 'cod_fiscal', '') + + gnbuton = 2 && Renunta - utilizatorul a ales o varianta in Detalii, apoi a anulat cautarea + *-- replica exact garda din CautPartenerContabilitate (ocautare.prg:848-850) + IF TYPE('gnbuton') = 'N' AND gnbuton = 1 + AplicaInlocuirePartenerANAF(loCauta, poANAFInlocuire, '') + ENDIF + IF loCauta.id_part = 0 AND EMPTY(loCauta.cod_fiscal) + DO VpaLog WITH 'PASS C2-renunta: gnbuton=2 -> AplicaInlocuirePartenerANAF NU se apeleaza, obiectul ramane blank (id_part=0)' + ELSE + DO VpaLog WITH 'FAIL C2-renunta: id_part=' + TRANSFORM(loCauta.id_part) + ' cod_fiscal=[' + loCauta.cod_fiscal + ']' + ENDIF + + *-- control: cu gnbuton=1, acelasi poANAFInlocuire CHIAR se aplica + gnbuton = 1 + IF TYPE('gnbuton') = 'N' AND gnbuton = 1 + AplicaInlocuirePartenerANAF(loCauta, poANAFInlocuire, '') + ENDIF + IF loCauta.id_part = gnIdPereche AND loCauta.cod_fiscal == 'RO7654320' + DO VpaLog WITH 'PASS C2-control: gnbuton=1 -> AplicaInlocuirePartenerANAF SE aplica (id_part=' + TRANSFORM(loCauta.id_part) + ')' + ELSE + DO VpaLog WITH 'FAIL C2-control: id_part=' + TRANSFORM(loCauta.id_part) + ' cod_fiscal=[' + loCauta.cod_fiscal + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaH2EroareListaCorecti + *-- H2: ANAF_CautaPereche esuat (mock pe goExecutor) => mesaj de eroare, FARA sugestia "Nou". + LOCAL loReal, lnLenInainte, lcLog, loExcH2 + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + loReal = goExecutor + goExecutor = CREATEOBJECT('dummyexecutorH2test') + goExecutor.oReal = loReal + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + lcLog = '' + TRY + poVerifAlegere.Detalii() + lcLog = SUBSTR(FILETOSTR(gcUILog), lnLenInainte + 1) + CATCH TO loExcH2 + lcLog = 'EXCEPTIE: ' + loExcH2.Message + FINALLY + goExecutor = loReal + ENDTRY + + IF 'MOCK amessagebox' $ lcLog AND 'Nu s-a putut citi lista de parteneri.' $ lcLog AND !('Nou' $ lcLog) + DO VpaLog WITH 'PASS H2-eroare-lista: ANAF_CautaPereche esuat -> mesaj eroare, fara sugestia Nou' + ELSE + DO VpaLog WITH 'FAIL H2-eroare-lista: log=[' + lcLog + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaDetaliiStareNula + *-- Detalii cu oStare=.Null. (ANAF picat/cod invalid) => se deschide, cu linia explicativa. + LOCAL lnLenInainte, lcLog + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + poVerifAlegere.oStare = .NULL. + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + poVerifAlegere.Detalii() + lcLog = SUBSTR(FILETOSTR(gcUILog), lnLenInainte + 1) + IF 'MOCK amessagebox' $ lcLog AND 'ANAF nu a raspuns - verificarea a fost sarita.' $ lcLog + DO VpaLog WITH 'PASS detalii-stare-nula (7): oStare=.Null. -> se deschide, cu linia explicativa' + ELSE + DO VpaLog WITH 'FAIL detalii-stare-nula (7): log=[' + lcLog + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaDiscriminatorDocumente + *-- discriminatorul "are documente in perioada" (mock pe goExecutor - IREG_PARTENERI), cu si fara randuri. + LOCAL loReal, lnLenInainte, lcLog1, lcLog2, loExcDoc + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + + loReal = goExecutor + goExecutor = CREATEOBJECT('dummyexecutordoctest') + goExecutor.oReal = loReal + lcLog1 = '' + lcLog2 = '' + TRY + goExecutor.nIdsConDocumente = 0 + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + poVerifAlegere.Detalii() + lcLog1 = SUBSTR(FILETOSTR(gcUILog), lnLenInainte + 1) + + goExecutor.nIdsConDocumente = gnIdPereche + lnLenInainte = IIF(FILE(gcUILog), LEN(FILETOSTR(gcUILog)), 0) + poVerifAlegere.Detalii() + lcLog2 = SUBSTR(FILETOSTR(gcUILog), lnLenInainte + 1) + CATCH TO loExcDoc + lcLog1 = 'EXCEPTIE: ' + loExcDoc.Message + lcLog2 = lcLog1 + FINALLY + goExecutor = loReal + ENDTRY + + IF 'MOCK amessagebox' $ lcLog1 AND !('are documente in perioada' $ lcLog1) + DO VpaLog WITH 'PASS discriminator-fara-documente (8): niciun candidat marcat "are documente in perioada"' + ELSE + DO VpaLog WITH 'FAIL discriminator-fara-documente (8): log=[' + lcLog1 + ']' + ENDIF + + IF ('1. TEST ANAF DISCORD SRL (ID: ' + TRANSFORM(gnIdPereche) + ') inactiv are documente in perioada') $ lcLog2 ; + AND !(('2. TEST ANAF SPATIU SRL (ID: ' + TRANSFORM(gnIdSpatiu) + ') are documente in perioada') $ lcLog2) + DO VpaLog WITH 'PASS discriminator-cu-documente (8): perechea marcata "are documente in perioada", spatiu nu' + ELSE + DO VpaLog WITH 'FAIL discriminator-cu-documente (8): log=[' + lcLog2 + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaB1LabelGolit + *-- B1: verdictul anterior nu ramane pe ecran cand cautarea nu mai are rezultate. + LOCAL lcCapInainte, lcCapDupa + DO PregatesteFormularD1a + SELECT ctestparteneri + LOCATE FOR id_part = gnIdDiscord + goFormT._GRID1.AfterRowColChange(1) + DO AsteaptaTimer + lcCapInainte = ALLTRIM(goFormT.lb_anaf.Caption) + + SELECT ctestparteneri + ZAP + poVerifAlegere.VerificaRand(.F.) + lcCapDupa = ALLTRIM(goFormT.lb_anaf.Caption) + + IF !EMPTY(lcCapInainte) AND EMPTY(lcCapDupa) + DO VpaLog WITH 'PASS B1-label-golit (9): verdict anterior [' + lcCapInainte + '] -> golit dupa cautare fara rezultate' + ELSE + DO VpaLog WITH 'FAIL B1-label-golit (9): inainte=[' + lcCapInainte + '] dupa=[' + lcCapDupa + ']' + ENDIF +ENDPROC + +PROCEDURE VerificaComutareOptiune + *-- ANAF_ComutaVerificare scrie valoarea corecta si are efect imediat (10/11), Alias() neschimbat (H6). + LOCAL lcOptIni, lnNivelInainte, lnNivelDupa, lcAliasInainte, lcAliasDupa, llAveaRand, lcValOrig + lcOptIni = getini(gcGeneralIniFile, 'anaf', 'verificare_selectie') + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', '') + IF !USED('crsOptiuniUtilizator') + =actualizeaza_optiuni_utilizator() + ENDIF + llAveaRand = .F. + lcValOrig = '' + SELECT crsOptiuniUtilizator + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + llAveaRand = FOUND() + IF llAveaRand + lcValOrig = varvalue + REPLACE varvalue WITH '1' + ELSE + INSERT INTO crsOptiuniUtilizator (varname, varvalue) VALUES ('RC_ANAF_VERIF_SELECTIE', '1') + ENDIF + RELEASE goCacheANAF_Nivel + lnNivelInainte = ANAF_NivelVerificare() + + gnMockRaspuns = 6 + gnMockInputBox = 0 && valoarea noua ceruta in aInputBox + lcAliasInainte = ALIAS() + ANAF_ComutaVerificare() && intrare unica: arata valoarea curenta, cere valoarea noua (0) + lcAliasDupa = ALIAS() + lnNivelDupa = ANAF_NivelVerificare() && fara Release manual - trebuie sa se invalideze singur + + IF lnNivelInainte = 1 AND lnNivelDupa = 0 + DO VpaLog WITH 'PASS comutare-optiune (11): valoare noua 0 scrisa, efect imediat (cache invalidat automat)' + ELSE + DO VpaLog WITH 'FAIL comutare-optiune (11): nivelInainte=' + TRANSFORM(lnNivelInainte) + ' nivelDupa=' + TRANSFORM(lnNivelDupa) + ENDIF + IF lcAliasInainte == lcAliasDupa + DO VpaLog WITH 'PASS comutare-alias (10/H6): Alias() neschimbat de ANAF_ComutaVerificare [' + lcAliasDupa + ']' + ELSE + DO VpaLog WITH 'FAIL comutare-alias (10/H6): inainte=[' + lcAliasInainte + '] dupa=[' + lcAliasDupa + ']' + ENDIF + + RELEASE goCacheANAF_Nivel + SELECT crsOptiuniUtilizator + LOCATE FOR UPPER(ALLTRIM(varname)) = 'RC_ANAF_VERIF_SELECTIE' + IF FOUND() + REPLACE varvalue WITH '1' + ENDIF + RELEASE goCacheANAF_Nivel + gnMockInputBox = 3 + ANAF_ComutaVerificare() && valoare noua 3, pornind de la 1 + lnNivelDupa = ANAF_NivelVerificare() + IF lnNivelDupa = 3 + DO VpaLog WITH 'PASS comutare-optiune2 (11): valoare noua 3 scrisa' + ELSE + DO VpaLog WITH 'FAIL comutare-optiune2 (11): nivelDupa=' + TRANSFORM(lnNivelDupa) + ENDIF + + *-- 9 = oprire pe calculatorul curent (settings.ini), fara sa atinga optiunea utilizatorului + RELEASE goCacheANAF_Nivel + gnMockInputBox = 9 + ANAF_ComutaVerificare() + lnNivelDupa = ANAF_NivelVerificare() + IF lnNivelDupa = 0 AND ALLTRIM(NVL(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) == '0' + DO VpaLog WITH 'PASS comutare-ini (11): valoarea 9 scrie settings.ini=0, nivel efectiv 0' + ELSE + DO VpaLog WITH 'FAIL comutare-ini (11): nivelDupa=' + TRANSFORM(lnNivelDupa) + ' ini=[' + ALLTRIM(NVL(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) + ']' + ENDIF + + *-- alegerea unei valori 0/1/3 cand ini=0 trebuie sa ridice si kill-switch-ul, altfel optiunea ramane inoperanta + RELEASE goCacheANAF_Nivel + gnMockInputBox = 1 + ANAF_ComutaVerificare() + lnNivelDupa = ANAF_NivelVerificare() + IF lnNivelDupa = 1 AND !(ALLTRIM(NVL(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) == '0') + DO VpaLog WITH 'PASS comutare-ini-ridicat (11): valoarea 1 ridica kill-switch-ul din settings.ini, nivel efectiv 1' + ELSE + DO VpaLog WITH 'FAIL comutare-ini-ridicat (11): nivelDupa=' + TRANSFORM(lnNivelDupa) + ' ini=[' + ALLTRIM(NVL(getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), '')) + ']' + ENDIF + + *-- restaureaza (scriere reala in Oracle, pt. utilizatorul de test gnIdUtil=-3) + scrie_optiune_utilizator('RC_ANAF_VERIF_SELECTIE', NVL(lcValOrig,''), 'Intreaba la alegerea unui partener discordant') + =actualizeaza_optiuni_utilizator() + =setini(gcGeneralIniFile, 'anaf', 'verificare_selectie', NVL(lcOptIni,'')) + RELEASE goCacheANAF_Nivel +ENDPROC + +PROCEDURE VpaErr + *-- OBLIGATORIU headless (depanare_testare_vfp.md): handlerul ON ERROR se termina cu QUIT. + *-- In fluxul normal, erorile din TRY-ul principal ajung la CATCH TO loExc (nu aici) - VpaErr + *-- prinde doar erori DIN AFARA acelui TRY (ex. evenimente async, Timer.Timer) care altfel ar + *-- lasa un dialog modal si ar agata rularea. Curatare best-effort inainte de QUIT. + LPARAMETERS tnErr, tcMsg, tcProg, tnLine + DO VpaLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg + DO VpaLog WITH 'ON ERROR: oprire fortata (QUIT) - eroare in afara TRY/CATCH principal' + TRY + DO CurataDateTest + CATCH + ENDTRY + QUIT +ENDPROC + +PROCEDURE VpaLog + LPARAMETERS tcMsg + SET SAFETY OFF + LOCAL lcL + lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '') + STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog) +ENDPROC + +*-- runda 11: clicker-ul de dialog (anaf_test_dlg_clicker) a fost eliminat odata cu anaf_dialog - +*-- deciziile trec acum prin mock_amessagebox.prg (gnMockRaspuns), sincron, fara Show(1) modal. + +*-- runda 17: dublura de goExecutor pentru H2 (ANAF_CautaPereche esuat) - delegheaza la executorul +*-- real pentru orice alt SELECT, intercepteaza doar interogarea NOM_PARTENERI din ANAF_CautaPereche. +DEFINE CLASS dummyexecutorH2test AS Custom + oReal = .NULL. + cEroare = '' + PROCEDURE oExecute + LPARAMETERS tcSql, tcCursor + LOCAL lnRez + IF 'NOM_PARTENERI' $ UPPER(tcSql) AND 'STERS = 0' $ UPPER(tcSql) AND 'COD_FISCAL' $ UPPER(tcSql) + This.cEroare = 'eroare simulata test H2' + RETURN -1 + ENDIF + lnRez = This.oReal.oExecute(tcSql, tcCursor) + This.cEroare = This.oReal.cEroare + RETURN lnRez + ENDPROC + *-- pass-through defensiv: orice alt apel (ex. din goLog.Log) merge la executorul real, nu la eroarea simulata + PROCEDURE oExecuta + LPARAMETERS tcSql, tcCursor + RETURN This.oReal.oExecuta(m.tcSql, m.tcCursor) + ENDPROC + PROCEDURE oSelect2Value + LPARAMETERS tcSql, tuValue + RETURN This.oReal.oSelect2Value(m.tcSql, @tuValue) + ENDPROC +ENDDEFINE + +*-- runda 17: dublura de goExecutor pentru discriminatorul "are documente in perioada" - intercepteaza +*-- doar interogarea IREG_PARTENERI din MarcheazaDocumente, cu raspuns controlat de nIdsConDocumente. +DEFINE CLASS dummyexecutordoctest AS Custom + oReal = .NULL. + cEroare = '' + nIdsConDocumente = 0 + PROCEDURE oExecute + LPARAMETERS tcSql, tcCursor + LOCAL lnRez + IF 'IREG_PARTENERI' $ UPPER(tcSql) AND 'ID_PART IN' $ UPPER(tcSql) + IF USED(tcCursor) + USE IN (tcCursor) + ENDIF + CREATE CURSOR (tcCursor) (id_part N(10)) + IF This.nIdsConDocumente > 0 + INSERT INTO (tcCursor) (id_part) VALUES (This.nIdsConDocumente) + ENDIF + RETURN 1 + ENDIF + lnRez = This.oReal.oExecute(tcSql, tcCursor) + This.cEroare = This.oReal.cEroare + RETURN lnRez + ENDPROC + *-- pass-through defensiv: orice alt apel (ex. din goLog.Log) merge la executorul real + PROCEDURE oExecuta + LPARAMETERS tcSql, tcCursor + RETURN This.oReal.oExecuta(m.tcSql, m.tcCursor) + ENDPROC + PROCEDURE oSelect2Value + LPARAMETERS tcSql, tuValue + RETURN This.oReal.oSelect2Value(m.tcSql, @tuValue) + ENDPROC +ENDDEFINE diff --git a/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1 b/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1 new file mode 100644 index 0000000..d5d83d4 --- /dev/null +++ b/utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1 @@ -0,0 +1,12 @@ +# test_verif_partener_anaf_v2_ui.ps1 - wrapper peste harness-ul generic pentru testul UI V2' +# (verdict ANAF in formularul de cautare, cauta_alfa_form + anaf_verif_cautare, decizie prin AMESSAGEBOX). +# Rulare: powershell -ExecutionPolicy Bypass -File test_verif_partener_anaf_v2_ui.ps1 +$ErrorActionPreference = 'Stop' +$Teste = $PSScriptRoot +& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') ` + -TestPrg (Join-Path $Teste 'test_verif_partener_anaf_v2_ui.prg') ` + -Steps @('concordant','discordant','mesaj_decizie','decizii_6_7_2','gata') ` + -ShotsDir (Join-Path $Teste 'screenshots') ` + -SyncDir (Join-Path $Teste 'uisync') ` + -StepTimeoutSec 90 ` + -ReadyTimeoutSec 150