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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019H3r66sVojGhgaKq5niu1u
This commit is contained in:
2026-07-27 01:29:41 +03:00
parent df9698375a
commit 889840357a
20 changed files with 3083 additions and 110 deletions

View File

@@ -10397,7 +10397,8 @@ DEFINE CLASS item AS container
*!* 03.10.2006 *!* 03.10.2006
*!* MARIUS.MUTU *!* 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 *!* modificare migrare v 1.0 > v 2.0
If poAct.id_set = 229 If poAct.id_set = 229
poAct.vid_part_rez = locauta.id_part poAct.vid_part_rez = locauta.id_part

View File

@@ -564,6 +564,13 @@ DEFINE CLASS cauta_alfa_form AS _frmbase OF "_frm_base.vcx"
ENDPROC 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 PROCEDURE Init
Lparameters tcCursor, tcNume_Proc, tcTitluColoana, tccoloana, tl_AllInList, ; Lparameters tcCursor, tcNume_Proc, tcTitluColoana, tccoloana, tl_AllInList, ;
tcPrimaColoana, tnPornire, tcGridDynamicBackColor, tcGridToolTip, ; tcPrimaColoana, tnPornire, tcGridDynamicBackColor, tcGridToolTip, ;
@@ -705,6 +712,12 @@ DEFINE CLASS cauta_alfa_form AS _frmbase OF "_frm_base.vcx"
THIS.cb_tx_cautare1.SETFOCUS THIS.cb_tx_cautare1.SETFOCUS
KEYBOARD '{END}' KEYBOARD '{END}'
CASE nKeyCode = -3 && F4
NODEFAULT
IF TYPE('THIS.oVerifAlegere') = 'O' AND !ISNULL(THIS.oVerifAlegere)
THIS.oVerifAlegere.Detalii()
ENDIF
OTHERWISE OTHERWISE
DODEFAULT(nKeyCode, nShiftAltCtrl) DODEFAULT(nKeyCode, nShiftAltCtrl)
ENDCASE ENDCASE

View File

@@ -6949,7 +6949,9 @@ DEFINE CLASS frm_date_aviz AS _frmbase OF "_frm_base.vcx"
Endif Endif
Otherwise Otherwise
&& modificare v 2.0.93 : am adaugat 47 && 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) If !Empty(Nvl(loCauta.id_part,0)) And !Empty(loCauta.denumire)
poDate.id_client = loCauta.id_part poDate.id_client = loCauta.id_part
poDate.nume_client = loCauta.denumire 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 PROCEDURE do_cauta_furnizor
Local loCauta Local loCauta
*!* loCauta = CautPartenerContabilitate(GetHash([cTitlu=>Alegeti furnizorul??cCont=>401??lAdaugCorespondente=>1])) *!* 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) If !Empty(loCauta.id_part) And !Empty(loCauta.denumire) AND !ISNULL(loCauta.id_part)
poDate.id_furnizor = loCauta.id_part poDate.id_furnizor = loCauta.id_part
poDate.furnizor = Alltrim(loCauta.denumire) poDate.furnizor = Alltrim(loCauta.denumire)
@@ -8970,7 +8974,9 @@ DEFINE CLASS frm_date_factura AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_cauta_client PROCEDURE do_cauta_client
Local loCauta 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 !Empty(Nvl(loCauta.id_part,0)) And !Empty(loCauta.denumire)
If loCauta.id_part <> poDate.id_client If loCauta.id_part <> poDate.id_client
poDate.listaid = [] poDate.listaid = []

View File

@@ -1607,12 +1607,17 @@ DEFINE CLASS frm_modific AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_cauta PROCEDURE do_cauta
PARAMETERS tcCont PARAMETERS tcCont
LOCAL loCauta LOCAL loCauta, loHash
IF EMPTY(tcCont) IF EMPTY(tcCont)
RETURN RETURN
ENDIF 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 RETURN loCauta
@@ -4601,12 +4606,17 @@ DEFINE CLASS frm_modific2007 AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_cauta PROCEDURE do_cauta
PARAMETERS tcCont PARAMETERS tcCont
LOCAL loCauta LOCAL loCauta, loHash
IF EMPTY(NVL(tcCont,'')) IF EMPTY(NVL(tcCont,''))
RETURN RETURN
ENDIF 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 RETURN loCauta
@@ -12613,12 +12623,17 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_cauta PROCEDURE do_cauta
PARAMETERS tcCont PARAMETERS tcCont
LOCAL loCauta LOCAL loCauta, loHash
IF EMPTY(NVL(tcCont,'')) IF EMPTY(NVL(tcCont,''))
RETURN RETURN
ENDIF 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 RETURN loCauta

View File

@@ -6965,6 +6965,7 @@ DEFINE CLASS frm_note_contabile2007_nou AS _frmbase OF "_frm_base.vcx"
WITH loHash WITH loHash
.SetValue("cTitlu", "Alege<67>i partenerul") .SetValue("cTitlu", "Alege<67>i partenerul")
.SetValue("cCont", lcCont) .SetValue("cCont", lcCont)
.SetValue("lVerificaANAF", .T.) && 26.07.2026 claude - verificare ANAF la alegerea partenerului
ENDWITH ENDWITH
loPartener = CautPartenerContabilitate(loHash) loPartener = CautPartenerContabilitate(loHash)

View File

@@ -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 = 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`. 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 ## Vocabular
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, aer aerisit, 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 - `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). (relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back).
- Capcana de encoding cp1252 la editarea `.sc2`/`.vc2` (corupere diacritice) — documentată în - `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la
proiectul unde a fost descoperită (ROAAUTO `docs/conventie_encoding_cp1252.md`); relevantă ori editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie
de câte ori editezi text-cache-ul unui formular/librărie pentru a aplica aceste reguli de UX. pentru a aplica aceste reguli de UX.

View File

@@ -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 <bak> <editat> > docs/diff_runda<N>_<subiect>.patch` 3. Patch review: `git diff --no-index <bak> <editat> > docs/diff_runda<N>_<subiect>.patch`
(exit 1 = normal). Utilizatorul revizuieste FISIERUL de patch si aproba; write-back-ul (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. (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 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 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. argumente, deduplicari care nu se declanseaza niciodata, interogari mai largi decat e nevoie.

View File

@@ -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/<nume-folder-lowercase>.git
(ex. romfast/roaimob.git). INAINTE sa creezi/pushezi orice, verifica cu
`git ls-remote git@gitea.romfast.ro:romfast/<nume>.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 <PROIECT>", 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\<PROIECT>\<proiect>.PJX -ProjectRoot D:\ROA\<PROIECT> `
-CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_<proiect>
- 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/<proiect>.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".

View File

@@ -5,11 +5,19 @@
Write-back in binar (txt2vcx) si commit DOAR dupa aprobarea patch-ului de catre utilizator. 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 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. .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 2. Comentarii in cod: NU se pun comentarii in corpul codului (nici la functionalitati noi).
functionalitati noi/schimbate. La rezolvari de erori NU se adauga comentarii. 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. Explicatiile merg in docs/ sau in mesajul de commit, nu in cod.
Changelog (`changelog_<aplicatie>.txt`): text minimal, pe limba utilizatorului, Changelog (`changelog_<aplicatie>.txt`): text minimal, pe limba utilizatorului, nu tehnic,
nu tehnic - o fraza scurta per intrare `:nou:`/`:modificare:`/`:eroare:`. 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. 3. Modificari minime: doar ce s-a cerut; fara refactorizari sau curatenie din oficiu.
4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell. 4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell.
Mediu, sabloane, capcane si metoda de depanare: `depanare_testare_vfp.md`. Mediu, sabloane, capcane si metoda de depanare: `depanare_testare_vfp.md`.

View File

@@ -5,3 +5,14 @@ Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in
`gcDirMare`/`dirgen` — ex. `D:\ROA\DATABASE\SCRIPTURI_CLAR`). `gcDirMare`/`dirgen` — ex. `D:\ROA\DATABASE\SCRIPTURI_CLAR`).
Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`. Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`.
Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo. 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;`.

View File

@@ -207,8 +207,18 @@ ENDIF
Endif Endif
.cIdColumn = lcIdColumn .cIdColumn = lcIdColumn
Endwith Endwith
If Type('poVerifAlegere') = 'O' And !Isnull(poVerifAlegere)
AddProperty(oForm_cautare, 'oVerifAlegere', poVerifAlegere)
poVerifAlegere.Activeaza(oForm_cautare)
Endif
oForm_cautare.Show() oForm_cautare.Show()
If Type('poVerifAlegere') = 'O' And !Isnull(poVerifAlegere)
poVerifAlegere.Dezactiveaza()
Endif
*!* modificare 30.11.2006 *!* modificare 30.11.2006
If Type("lorec") = "O" If Type("lorec") = "O"
poRec = lorec poRec = lorec

View File

@@ -39,9 +39,762 @@
*!* marius.mutu *!* marius.mutu
*!* caut_client_contract_activ - nu se iau contracte active de pe clienti inactivi *!* 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) *!* #DEFINE CRLF CHR(13) + CHR(10)
#INCLUDE COMUN\ROA.H #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) * CautPartenerContabilitate(cTitlu, cTipuriParteneri)
* Date : 04/10/2006 * Date : 04/10/2006
@@ -63,6 +816,7 @@ Procedure CautPartenerContabilitate
Local loHash As MyHash, lcSelect, lcTitlu, lcTipuriParteneri, lnSucces, llAllInList, lnPornire, lcFiltruOrig, lcNumeProcedura, llAdaugCorespondente Local loHash As MyHash, lcSelect, lcTitlu, lcTipuriParteneri, lnSucces, llAllInList, lnPornire, lcFiltruOrig, lcNumeProcedura, llAdaugCorespondente
Local lVerificaANAF, ldDataDoc, lnNivelANAF
*!* parametrii *!* parametrii
lcTitlu = toHash.GetValue("cTitlu") lcTitlu = toHash.GetValue("cTitlu")
@@ -73,6 +827,8 @@ Procedure CautPartenerContabilitate
lcFiltruOrig = toHash.GetValue("cFiltruOrig") lcFiltruOrig = toHash.GetValue("cFiltruOrig")
llAllInList = toHash.GetValue("lAllInList") llAllInList = toHash.GetValue("lAllInList")
lnPornire = toHash.GetValue("nPornire") lnPornire = toHash.GetValue("nPornire")
lVerificaANAF = toHash.GetValue("lVerificaANAF")
ldDataDoc = toHash.GetValue("dDataDoc")
*!* parametrii *!* parametrii
@@ -93,12 +849,12 @@ Procedure CautPartenerContabilitate
If !Empty(lcTipuriParteneri) If !Empty(lcTipuriParteneri)
*!* selectia se face din corespondente tipuri partener *!* 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,] + ; 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 ] + ; [ FROM CORESP_TIP_PART A ] + ;
[ LEFT JOIN NOM_PARTENERI B ON A.ID_PART = B.ID_PART ] [ LEFT JOIN NOM_PARTENERI B ON A.ID_PART = B.ID_PART ]
Else Else
*!* selectia se face din parteneri *!* 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 ] [ FROM NOM_PARTENERI B ]
Endif Endif
@@ -108,7 +864,7 @@ Procedure CautPartenerContabilitate
.SetValue("cFiltru", "1=2") .SetValue("cFiltru", "1=2")
.SetValue("cOrder", "1,NUME") .SetValue("cOrder", "1,NUME")
If !Empty(Nvl(lcTipuriParteneri, '')) 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 Endif
.SetValue("cColoana", "denumire,cod_fiscal,id_part") .SetValue("cColoana", "denumire,cod_fiscal,id_part")
.SetValue("cTitlu", lcTitlu) .SetValue("cTitlu", lcTitlu)
@@ -142,8 +898,24 @@ Procedure CautPartenerContabilitate
Endwith 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 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 *!* 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 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 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 * Date : 04/11/2004, 14:01:21
* author : lavinia.viziru * author : lavinia.viziru
******************************************* INCEPUT:caut_parteneri ******************************************* ******************************************* 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 lcCont, loCauta, lcFiltruOriginal
Local lcTitlu, lcFiltru, lcSchema, lcOrder, lcNumeProc, lcTitluColoane Local lcTitlu, lcFiltru, lcSchema, lcOrder, lcNumeProc, lcTitluColoane
Store "" To loCauta Store "" To loCauta
lcCont = tcCont 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) 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 ] [ join vcoresp_tip_cont c on p.id_tip_part=c.id_tip_part ]
lcFiltru = [1=2] lcFiltru = [1=2]
lcSchema = [] lcSchema = []
@@ -188,8 +960,26 @@ Procedure caut_parteneri( tcCont, tcTitlu, tlToateIreg, tlNou, tlInactiv)
ENDIF ENDIF
lcTitluColoane = [Denumire, Nume,Cod fiscal, Id, Inactiv] 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 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 Return loCauta
Endproc Endproc

View File

@@ -55,6 +55,10 @@
*!* marius.mutu *!* marius.mutu
*!* ANAF_SincronWebService_PlatitorTva api v9 *!* 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://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/CIF/1879855/MFIN
*!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CNP/1810228134187 *!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CNP/1810228134187
@@ -1546,6 +1550,123 @@ Define Class VerificareCod As Custom
Endfunc && GetEmptyMfinObj Endfunc && GetEmptyMfinObj
Enddefine 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 *** 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') goLog.Log('lcJsonString: ' + m.lcJsonString, 'ANAF_SincronWebService_PlatitorTva')
* *
SET STEP ON
If Not Empty(m.lcJsonString) If Not Empty(m.lcJsonString)
TRY TRY
loJsonObject = nfjsonread(m.lcJsonString) && nfJson from http://vfpx.codeplex.com/ loJsonObject = nfjsonread(m.lcJsonString) && nfJson from http://vfpx.codeplex.com/

View File

@@ -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

View File

@@ -10,6 +10,8 @@
* mock-ul raspunde cu ACEASTA valoare in loc de gnMockRaspuns - necesar cand doua dialoguri * 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 * 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). * 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 FUNCTION amessagebox
LPARAMETERS tcMessage, tnDialogBoxType, tcTitle, tcFont, tnTimeOut, tnTimeoutValue LPARAMETERS tcMessage, tnDialogBoxType, tcTitle, tcFont, tnTimeOut, tnTimeoutValue
LOCAL lnRaspuns LOCAL lnRaspuns
@@ -18,6 +20,10 @@ FUNCTION amessagebox
ELSE ELSE
lnRaspuns = IIF(TYPE('gnMockRaspuns') = 'N', gnMockRaspuns, 6) lnRaspuns = IIF(TYPE('gnMockRaspuns') = 'N', gnMockRaspuns, 6)
ENDIF ENDIF
IF TYPE('gcMockUltimMesaj') = 'C'
gcMockUltimMesaj = TRANSFORM(tcMessage)
gnMockUltimTip = IIF(TYPE('tnDialogBoxType') = 'N', tnDialogBoxType, 0)
ENDIF
IF TYPE('gcUILog') = 'C' IF TYPE('gcUILog') = 'C'
DO HarnessLog WITH 'MOCK amessagebox apelat: [' + ALLTRIM(TRANSFORM(tcMessage)) + '] -> returnez ' + TRANSFORM(lnRaspuns) DO HarnessLog WITH 'MOCK amessagebox apelat: [' + ALLTRIM(TRANSFORM(tcMessage)) + '] -> returnez ' + TRANSFORM(lnRaspuns)
ENDIF ENDIF

View File

@@ -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

View File

@@ -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

View File

@@ -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<IntPtr> FindByPidAndClass(int pid, string className) {
var result = new List<IntPtr>();
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"

File diff suppressed because it is too large Load Diff

View File

@@ -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