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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6965,6 +6965,7 @@ DEFINE CLASS frm_note_contabile2007_nou AS _frmbase OF "_frm_base.vcx"
|
||||
WITH loHash
|
||||
.SetValue("cTitlu", "Alege<67>i partenerul")
|
||||
.SetValue("cCont", lcCont)
|
||||
.SetValue("lVerificaANAF", .T.) && 26.07.2026 claude - verificare ANAF la alegerea partenerului
|
||||
ENDWITH
|
||||
loPartener = CautPartenerContabilitate(loHash)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`
|
||||
(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.
|
||||
|
||||
@@ -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".
|
||||
@@ -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_<aplicatie>.txt`): text minimal, pe limba utilizatorului,
|
||||
nu tehnic - o fraza scurta per intrare `:nou:`/`:modificare:`/`:eroare:`.
|
||||
Changelog (`changelog_<aplicatie>.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 "<script.prg>" <param>` din PowerShell.
|
||||
Mediu, sabloane, capcane si metoda de depanare: `depanare_testare_vfp.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;`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
33
utile/Teste/mock_ainputbox.prg
Normal file
33
utile/Teste/mock_ainputbox.prg
Normal 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
|
||||
@@ -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
|
||||
|
||||
34
utile/Teste/partener_anaf/mock_anaf_verificare.prg
Normal file
34
utile/Teste/partener_anaf/mock_anaf_verificare.prg
Normal 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
|
||||
146
utile/Teste/partener_anaf/shot_dialog_anaf.prg
Normal file
146
utile/Teste/partener_anaf/shot_dialog_anaf.prg
Normal 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
|
||||
177
utile/Teste/partener_anaf/shot_dialog_anaf.ps1
Normal file
177
utile/Teste/partener_anaf/shot_dialog_anaf.ps1
Normal 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"
|
||||
1660
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg
Normal file
1660
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg
Normal file
File diff suppressed because it is too large
Load Diff
12
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1
Normal file
12
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1
Normal 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
|
||||
Reference in New Issue
Block a user