Compare commits

...

31 Commits

Author SHA1 Message Date
13b4f65723 sync SVN r18004/r18007: #6 editare factura emisa - pagina de articole
ofacturare_editare.prg (nou): helpere comune - garda eFactura, cursoarele
notei si ale rulajelor, randul de vanzare corespunzator notei si liniile de
articole citite din view-ul VVANZARI_ARTICOLE.

omodificari.vc2 (frm_modific2024): pagina noua de articole ale facturii,
deocamdata doar afisare. Apare numai cand ofacturare_editare.prg e
inregistrat si documentul are rand in VANZARI; in ROACONT si ROAGEST, unde
fisierul nu e incarcat, pagina lipseste si registrul jurnal ramane neatins.
Randul de vanzare al notei se cauta pe toate tripletele distincte (nract,
serie_act, dataact) din nota, pentru ca primul rand poate fi o incasare.

ofacturare_comun.vc2 (frm_facturi): do_editare_factura si butonul aferent,
dupa modelul lui do_sterge, cu garzile de luna inchisa, luna curenta,
document sters, referinte si eFactura.

docs: comentariile se scriu strict necesar, si in cod si in scripturile de
migrare - fara referinte la planuri, stories, decizii sau erori, istoricul
doar in antetul fisierului. Plus regula zero (predarea contextului),
capcanele de la testarea headless si completari pe fluxul text -> binar.

utile/Teste: suita de regresie pentru editarea facturii si harness-ul
watchdog (nu sunt in SVN, unde utile/Teste e ignorat). .gitignore ignora si
capturile PNG si watchdog_out/, ramase din rulari.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-08 16:47:24 +03:00
c5b0ce3a25 teste: suita headless pentru pretul cu TVA pe linie (ROAFACTURARE 2.11.14)
Patru niveluri, 38 de asertii, toate PASS pe binarul din SVN r17998:

- test_pret_cu_tva_dialog        - dialogul frm_articol_factura izolat (14)
- test_pret_cu_tva_nivel2        - factura in curs de compunere, adaugare si ambele cai de
                                   modificare (buton si dublu-clic), Renunta bit-identic (7)
- test_pret_cu_tva_nivel2_retur  - plafonul de cantitate recalculat, pe ramura de retur (4)
- test_pret_cu_tva_nivel3_gestiuni - ramura gestionabila, cu Oracle mockuit la granita prin
                                   dummyexecutor: preselectia gestiunii, excluderea liniei din
                                   propriul stoc, plafonul pe lot, multi-selectia (13)

Nivelurile 2 si 3 conduc dialoguri modale deschise din codul aplicatiei (Show(1) hardcodat),
prin Timer pe _SCREEN si detectie in _SCREEN.Forms - mecanismul e descris in
docs/testare-ui-vfp.md.

Suita nu e in SVN (utile/Teste e ignorat acolo), deci traieste doar in git.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-08 00:23:15 +03:00
f88b2b9a5b sync SVN r18000: todos - puncte marcate DONE si doua puncte noi
Marcate DONE: 2, 3, 4, 5, 8, 9. Punctul 13 precizeaza formularul unificat
frm_facturare_articole2. Noi: 16 (focus si renumerotare act la revenirea din formularul
de curs valutar) si 17 (eroare ORA neprietenoasa cand id_venchelt e null la finalizarea
facturii).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-08 00:23:01 +03:00
8df728cf8b sync SVN r17998: pret cu TVA pe linie si editarea liniei la introducerea facturii
ofacturare.vc2:
- frm_articol_factura: bifa "Pret cu TVA inclus" (preturi_cu_tva) editabila in dialogul
  per-articol; activa doar pe tipurile unde pretul e editabil.
- frm_facturare_articole: buton de modificare deasupra listei + dublu-clic pe linie, ambele
  redeschid dialogul pe linia curenta (do_modifica); Renunta lasa randul neschimbat.
- Plafonul de cantitate la modificare se recalculeaza din stocul disponibil (reversul
  decrementarii din do_adauga_articol), nu ramane la cantitatea aflata deja pe linie.
- Articolele gestionabile: modificarea redeschide tabelul cu gestiuni, pozitionat pe gestiunea
  liniei; do_alege_stoc primeste tnIdTempExclus, ca linia sa nu se scada pe ea insasi din stoc.
  Multi-selectia actualizeaza linia si adauga restul ca linii noi.
- frm_articol_gest_factura: bifa era desenata sub grd_gestiuni; forma inaltata si bifa mutata sub grid.

ofacturare_comun.vc2: scos un SET STEP ON ramas in cod.

docs/testare-ui-vfp.md: sectiune noua despre conducerea dialogurilor modale Show(1) din teste
(Timer pe _SCREEN, detectie prin _SCREEN.Forms, inchidere prin do_termin/do_renunt) si capcanele
platite pe parcurs.

Testat headless: Nivel 1 dialog 14 asertii, Nivel 2 factura in compunere 7, Nivel 2 retur 4,
Nivel 3 ramura gestionabila 13 - toate PASS, zero FAIL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-08 00:18:20 +03:00
0684485107 sync SVN r17994: tipuri de documente facturare (semnificatia VANZARI.TIP) 2026-08-07 13:28:58 +03:00
be37c2c99c sync SVN r17994: reguli suplimentare pentru scripturile de migrare DB
Niciun ';' la capat de linie intr-un comentariu '--' din interiorul unei instructiuni
(SQL*Plus termina instructiunea acolo, chiar daca ';'-ul e in comentariu). Fiecare
script se incheie cu exec pack_migrare.UpdateVersiune('<nume_script>'); urmat de
commit; (UpdateVersiune e DML, fara commit explicit VERSIUNE minte despre ce s-a aplicat).
2026-08-07 13:26:38 +03:00
837b455687 sync SVN r17991: garda valuta la nota de curs eFactura, scos SET STEP ON
xmlefactura.prg: mentiunea despre cursul valutar din textul aditional se emite doar
cand documentul e chiar in valuta (in_valuta = 1).
ofacturare.vcx: scos SET STEP ON neconditionat din frm_facturare.do_scrie_factura.
2026-08-07 13:15:25 +03:00
e21512240f todo 2026-08-07 00:17:45 +03:00
8421d7ba7f Merge branch 'claude/todos-roacont' 2026-08-07 00:00:58 +03:00
ec51097277 Merge branch 'main' of gitea.romfast.ro:romfast/comun 2026-08-07 00:00:37 +03:00
117f2fb88a eFactura, verificare partener, istoric CF: numar pe bife, TVA la incasare, explicatii pe cota
- borderou si import eFactura: bifele de cautare arata numarul de documente in eticheta, inca
  de la deschiderea ferestrei. Numararea se face local din cursorul deja adus cand nicio bifa
  nu e bifata (cursorul e chiar setul de baza) si prin interogare doar cand o bifa e bifata,
  ca sa nu apara interogari inutile. Latimile bifelor au fost marite: erau croite exact pe
  textul original, iar " (N)" era taiat de marginea controlului.
- verificare cod fiscal: starea partenerului include "TVA la incasare", cu perioada in detalii;
  sursa e ANAF live sau cache-ul ISTORIC_CODURI_FISCALE (ocautare.prg, validare.prg).
- modificare nota: lista de explicatii TVA se filtreaza dupa cota TVA a liniei curente
  (omodificari.vc2, caut_explicatie_tva din oproceduri_comune.prg).
- istoric coduri fiscale: coloane nefolosite ascunse, adaugate cele venite de la ANAF
  (TVA la incasare, split TVA, inactiv si perioadele aferente) - overificari.vc2.
- docs/scripturi-migrare-db.md: regulile de rulare manuala pe schema tinta si un pachet per script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8Ham1HJ8BB2v9nbtWgdZq
2026-08-07 00:00:21 +03:00
c6216e006e acces email Thunderbird + tabela de provenienta la top segmente in diagnosticul de spatiu 2026-08-06 23:29:18 +03:00
d0c2af8a31 Merge branch 'main' of gitea.romfast.ro:romfast/comun 2026-08-06 12:44:23 +03:00
8fa842888a sync SVN r17985: sursa de referinta DDL (MARIUSM_AUTO) + aliniere la origin
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Euno5AmwoFEvBTdWH8C8S
2026-08-06 12:44:15 +03:00
89695721f4 diag spatiu: emailul de alerta contine si logul complet al rularii
Nota in depanare-spatiu-oracle.md pentru co_2026_08_06_01_DIAG_SPATIU_PACK: pragul absolut
nu se mai aplica tablespace-urilor cu maximul sub el, iar emailul include tot
DIAG_SPATIU_LOG-ul rularii, plafonat la 30000 de caractere.
2026-08-06 10:40:06 +03:00
c599a9c053 sync SVN r17979 2026-08-06 00:34:35 +03:00
b35e62c880 achizitie import: linia de diferenta 6xx fara cod de taxa SAFT 2026-08-05 23:36:20 +03:00
54d97c0349 context_watch.ps1: nu mai raporteaza contextul altei sesiuni
La primul mesaj dintr-o sesiune noua transcriptul .jsonl inca nu e creat, asa
ca Test-Path pica si scriptul cadea pe fallback-ul "cel mai recent .jsonl din
directorul proiectului" - adica transcriptul sesiunii precedente, anuntand un
context de sute de k intr-o sesiune goala. Cand calea vine ca parametru sau pe
stdin si nu exista, iese tacut; fallback-ul pe director ramane doar pentru
invocarea manuala, fara cale.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UKTBDwMB1dAoN4DPBa1b2m
2026-08-05 22:21:32 +03:00
4d1179f8e5 diag_spatiu.ps1: aceleasi praguri ca jobul de diagnostic + plafonul editiei XE
Pragurile ies in capul scriptului si sunt cele din PACK_DIAG_SPATIU: tablespace-ul intra in atentie
sub 2048 MB ramasi sau sub 15% din maximul lui (inainte: sub 1 MB, adica dupa ce ORA-01653 e la usa),
iar FRA la 75% in loc de 80%.

Sectiune noua 2c: plafonul de date al editiei XE (4 GB pe 10.2, 11 GB pe 11.2, 12 GB de la 18c) -
limita e independenta de maxbytes-ul tablespace-urilor, baza poate refuza extinderea cu ORA-12952
desi tablespace-ul mai are loc. Pe alte editii sectiunea se sare.

Verificat pe XE 21c: sectiunea 2c da aceleasi cifre ca pachetul.
2026-08-05 21:55:13 +03:00
bd09073229 teste NNIR: avertisment .FXP stale (VFP ruleaza tacut versiunea veche a scriptului)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBFMe75MwdnDQk3qhp1YB2
2026-08-03 23:45:58 +03:00
26d2c205c9 NNIR editabil in Registrul Jurnal (frm_modific2024) + teste 2026-08-03 23:44:27 +03:00
4666262c92 publicare scripturi de baza de date: script + documentatie
COMUN/utile/publicare_scripturi.ps1 face cei doi pasi ai publicarii (import in
UPD_DATABASE + arhiva lunara database[n]_*.zip in _UPDATE), cu configurarea citita
din settings.ini-ul lui tasks.exe si verificare octet cu octet a continutului.
2026-08-03 23:14:47 +03:00
72bf63cd04 depanare-spatiu-oracle.md: jobul zilnic de diagnostic + mecanismele reutilizabile
Jobul DIAGSPATIU_ZILNIC (SVN r17969) si mecanismele generale desprinse din investigatie:
cheile SERVER_INFO si GetSchemaParola, rularea ca SYS/OS prin UpdateSQLPLUS/ExecuteScriptOS,
de ce EmailLog nu se reutilizeaza, ordinea de aplicare a scripturilor sys_.

Capcane noi: parola SYS nu e generica la toti clientii, iar rolurile nu se aplica in pachete cu
drepturi de definitor - de aici granturile directe din sys_2026_08_03_05.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 22:24:28 +03:00
05d91a05c6 todos 2026-08-03 20:42:46 +03:00
5f944e8bfa credentialele Oracle se muta in COMUN\docs\local\oracle.md
Fisierul era per proiect; acum e in COMUN, partajat de toate aplicatiile ROA.
Ramane neversionat in git (docs/local/ adaugat in .gitignore-ul COMUN), exista
doar in SVN. Parola SYS e generica, nu difera de la server la server.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 19:06:44 +03:00
1d3e75803f livrare.ps1: fisierul de mesaj fara BOM
Out-File -Encoding utf8 in PS 5.1 scrie BOM, care ajungea ca prim caracter in
mesajul de commit (ex. un mesaj despre "sync SVN"). Se scrie cu
[IO.File]::WriteAllText si UTF8Encoding $false.

Nota in scripturi-uzuale.md: mesajele catre git/svn din PowerShell trec prin
fisier, UTF-8 fara BOM, LF.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 18:26:41 +03:00
f4b48d9c20 livrare.ps1: mesajul de commit prin fisier, nu prin -m
PowerShell 5.1 nu escapeaza argumentele catre exe native, deci ghilimele duble
in mesaj (ex. un commit de "sync SVN") spargeau apelul git. Mesajul se scrie
intr-un fisier temporar si se foloseste git commit -F, sters in finally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 18:23:41 +03:00
d350119993 livrare.ps1: roa_sync la tree curat, rebase la push respins, garda SVN
- pasul 1 ruleaza roa_sync.ps1 cand tree-ul e curat (svn update + git_sync +
  reconciliere cu origin); cu modificari necomise ruleaza doar git_sync, ca
  roa_sync sa nu inglobeze munca in curs intr-un commit de sync SVN
- fetch inainte de commit: raporteaza cand ramura e in urma fata de origin
- push respins non-fast-forward: rebase + o singura reincercare, abort curat
  la conflict; fara --force
- avertisment pentru fisierele comise in git dar nefacute svn add
- docs: scripturi-uzuale.md - ce script se ruleaza si cand

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 18:18:45 +03:00
48f15c1da1 scripturi de diagnostic baza de date + script de livrare
- diag_actualizare.ps1: de ce s-a oprit actualizarea (UPD_ISTORIC, UPD_LOG,
  script_master.log prin UTL_FILE, versiuni per schema, spatiu tablespace, verdict)
- diag_spatiu.ps1: spatiu Oracle la clienti (tablespace, audit, ADR, FRA, disc server)
- livrare.ps1: git_sync + curatenie + verificari + commit/push
- curatenie.ps1: sterge si docs\propuneri_*.md
- docs: depanare-spatiu-oracle.md nou, depanare-pack-update.md completat cu cazul SIGMA

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sNn6dmAimtyXkDU4frJrh
2026-08-03 12:11:42 +03:00
5f3a17c5c7 fix: exportul Excel din GridExtras respecta ordinea de afisare a coloanelor
gridutils.copytoexcel parcurgea grid.Columns() pe indexul de creare, care in
VFP nu are legatura cu ColumnOrder. Coloanele se sorteaza acum dupa ColumnOrder
inainte de a construi lista de campuri, deci exportul iese in ordinea de pe
ecran, inclusiv dupa ce utilizatorul muta coloane (ordine salvata de
savegridpreferences).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YB2eA3Wd31DZiXjzVRc6VJ
2026-08-03 11:48:03 +03:00
a290a51276 docs: emailurile actualizarii si compatibilitatea scripturilor cu 10g/11g
Log-ul de actualizare (PACK_UPDATE.EmailLog, din baza) si buletinul informativ
(trimis de serverul de update) sunt doua fluxuri diferite, cu destinatari
configurati in locuri diferite.

Scripturile de migrare se scriu la nivelul Oracle 10.2 si trebuie sa ruleze
si pe 11.x; tabel cu versiunea minima a constructiilor uzuale si limitele XE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TM9Cxpzrn9wBSkyBNr22Qc
2026-08-03 10:46:08 +03:00
60 changed files with 10957 additions and 192 deletions

5
.gitignore vendored
View File

@@ -118,6 +118,9 @@ utile/hpdf/hpdferr.FPT
# --- SVN (COMUN este si working copy SVN) ---
.svn/
# --- notite neversionate in git (credentiale) - raman doar in SVN ---
docs/local/
# --- Windows / stare locala ---
*.lnk
Thumbs.db
@@ -130,3 +133,5 @@ bash.exe.stackdump
utile/Teste/**/screenshots*/
utile/Teste/**/uisync*/
utile/Teste/**/*_log.txt
utile/Teste/**/watchdog_out/
utile/Teste/**/*_dialog*.png

View File

@@ -609,12 +609,12 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
BackStyle = 1, ;
Caption = "Trimise (cu diferente Reg. Vz.)", ;
Height = 25, ;
Left = 522, ;
Left = 687, ;
Name = "chkDiferente", ;
Style = 0, ;
Top = 151, ;
Value = .F., ;
Width = 197
Width = 238
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'pgfeFactura.Page1.chkErori' AS _checkbox WITH ;
@@ -625,12 +625,12 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
BackStyle = 1, ;
Caption = "Trimise (cu raspuns Erori)", ;
Height = 25, ;
Left = 346, ;
Left = 470, ;
Name = "chkErori", ;
Style = 0, ;
Top = 151, ;
Value = .F., ;
Width = 170
Width = 211
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'pgfeFactura.Page1.chkFortareRaspunsuri' AS _checkbox WITH ;
@@ -655,12 +655,12 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
BackStyle = 1, ;
Caption = "Netrimise", ;
Height = 25, ;
Left = 112, ;
Left = 154, ;
Name = "chkNetrimise", ;
Style = 0, ;
Top = 151, ;
Value = .F., ;
Width = 79
Width = 117
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'pgfeFactura.Page1.chkPersFizice' AS _checkbox WITH ;
@@ -690,7 +690,7 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
Style = 0, ;
Top = 151, ;
Value = .F., ;
Width = 98
Width = 141
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'pgfeFactura.Page1.chkTrimis' AS _checkbox WITH ;
@@ -716,12 +716,12 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
BackStyle = 1, ;
Caption = "Trimise (fara raspuns)", ;
Height = 25, ;
Left = 195, ;
Left = 277, ;
Name = "chkTrimise", ;
Style = 0, ;
Top = 151, ;
Value = .F., ;
Width = 147
Width = 187
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'pgfeFactura.Page1.chkValidareOnline' AS _checkbox WITH ;
@@ -5363,7 +5363,7 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_cauta
LOCAL lcfiltru, lcFiltru2, lcFiltru3, lcval1, lcColoana, ldData1, ldData2
Local lcData1, lcData2, llErori, llNetrimise, llPJ, llTrimise, llDiferente, lnActivePage, lcCond, lcDif2, lcDif3, lcLipsa
Local lcData1, lcData2, llErori, llNetrimise, llPJ, llTrimise, llDiferente, lnActivePage, lcCond, lcDif1, lcDif2, lcDif3, lcLipsa, lcFiltruBaza1, lcFiltruBaza2, lcFiltruBaza3, lcPJ, lcNetrimise, lcTrimise, lcErori
WAIT WINDOW 'Selectie inregistrari...' NOWAIT
@@ -5411,19 +5411,25 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
lcFiltru3 = m.lcFiltru3 + " and (" + ALLTRIM(THISFORM.filtru_pretty) + ")"
ENDIF
* Filtrul de baza (fara bifele paginii 1), pentru numarul independent din caption (NumaraDiferente)
lcFiltruBaza1 = m.lcFiltru
lcPJ = [(tip_persoana=1)]
lcNetrimise = [(NVL(trimis,0) = 0)]
lcTrimise = [(trimis = 1 and data_raspuns IS NULL)]
lcErori = [(trimis = 1 and tip_mesaj_raspuns = 'ERORI FACTURA')]
IF m.llPJ
lcFiltru = m.lcfiltru + " and (tip_persoana=1)"
lcFiltru = m.lcfiltru + " and " + m.lcPJ
ENDIF
IF m.llDiferente
lcFiltru = m.lcFiltru + " and (jtotctva is null or ABS(decode(creditnote,0,1,-1) * ROUND(NVL(xtotal_cu_tva , 0.00) * decode(in_valuta,1,curs,1), 2)-NVL(jtotctva, 0.00)) > 0.15)"
ENDIF
* Bifele Diferente / Lipsa din registrul de TVA de pe paginile Primite si Trimise
* Bifele Diferente / Lipsa din registrul de TVA, folosite si de NumaraDiferente pentru numarul din caption
lcLipsa = [(jtotctva is null)]
lcDif1 = [(jtotctva is null or ABS(decode(creditnote,0,1,-1) * ROUND(NVL(xtotal_cu_tva , 0.00) * decode(in_valuta,1,curs,1), 2)-NVL(jtotctva, 0.00)) > 0.15)]
lcDif2 = [(jtotctva is not null and (NVL(nume_valuta,'RON') <> 'RON' or ABS(decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-(NVL(jtotctva, 0.00)-NVL(jtva_ti, 0.00))) > 0.15))]
lcDif3 = [(jtotctva is not null and (NVL(nume_valuta,'RON') <> 'RON' or ABS(decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-NVL(jtotctva, 0.00)) > 0.15))]
lcFiltruBaza2 = m.lcFiltru2
lcCond = []
WITH this.pgfeFactura.page2
IF .chkDiferente.Value
@@ -5437,6 +5443,7 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
lcFiltru2 = m.lcFiltru2 + [ and (] + m.lcCond + [)]
ENDIF
lcFiltruBaza3 = m.lcFiltru3
lcCond = []
WITH this.pgfeFactura.page3
IF .chkDiferente.Value
@@ -5455,14 +5462,18 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
IF m.llErori
lcFiltru = m.lcfiltru + " and (NVL(trimis,0) = 0 or tip_mesaj_raspuns = 'ERORI FACTURA')"
ELSE
lcFiltru = m.lcfiltru + " and (NVL(trimis,0) = 0)"
lcFiltru = m.lcfiltru + " and " + m.lcNetrimise
ENDIF
CASE m.llTrimise
lcFiltru = m.lcfiltru + " and (trimis = 1 and data_raspuns IS NULL)"
lcFiltru = m.lcfiltru + " and " + m.lcTrimise
CASE m.llErori
lcFiltru = m.lcfiltru + " and (trimis = 1 and tip_mesaj_raspuns = 'ERORI FACTURA')"
lcFiltru = m.lcfiltru + " and " + m.lcErori
ENDCASE
IF m.llDiferente
lcFiltru = m.lcFiltru + " and (" + m.lcDif1 + ")"
ENDIF
If Empty(m.lcFiltru)
aMessagebox("Alegeti un criteriu!",0+48,"Atentie")
Return
@@ -5512,6 +5523,8 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
This.pgfeFactura.page2._grdfooter1.calctotal()
This.pgfeFactura.page3._grdfooter1.calctotal()
This.NumaraDiferente(m.lcFiltruBaza1, m.lcFiltruBaza2, m.lcFiltruBaza3, m.lcDif1, m.lcDif2, m.lcDif3, m.lcLipsa, m.lcNetrimise, m.lcTrimise, m.lcErori, m.lcPJ)
WAIT CLEAR
Return m.lcFiltru
@@ -6032,6 +6045,16 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
* Mesajul era trunchiat la 41 de caractere
This.cMesajFurnizor = SPACE(200)
* Caption de baza pentru bifele Diferente/Lipsa, refolosit de NumaraDiferente/SeteazaCaptionDiferente
This.pgfeFactura.page1.chkPJ.Tag = This.pgfeFactura.page1.chkPJ.Caption
This.pgfeFactura.page1.chkNetrimise.Tag = This.pgfeFactura.page1.chkNetrimise.Caption
This.pgfeFactura.page1.chkTrimise.Tag = This.pgfeFactura.page1.chkTrimise.Caption
This.pgfeFactura.page1.chkErori.Tag = This.pgfeFactura.page1.chkErori.Caption
This.pgfeFactura.page1.chkDiferente.Tag = This.pgfeFactura.page1.chkDiferente.Caption
This.pgfeFactura.page2.chkDiferente.Tag = This.pgfeFactura.page2.chkDiferente.Caption
This.pgfeFactura.page2.chkLipsaRegistru.Tag = This.pgfeFactura.page2.chkLipsaRegistru.Caption
This.pgfeFactura.page3.chkDiferente.Tag = This.pgfeFactura.page3.chkDiferente.Caption
This.pgfeFactura.page3.chkLipsaRegistru.Tag = This.pgfeFactura.page3.chkLipsaRegistru.Caption
DODEFAULT()
ENDPROC
@@ -6044,6 +6067,147 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
Thisform.oAnaf.AnafeFacturaServer.lTest = m.tlTest
ENDPROC
PROCEDURE NumaraDiferente
LPARAMETERS tcFiltruBaza1, tcFiltruBaza2, tcFiltruBaza3, tcDif1, tcDif2, tcDif3, tcLipsa, tcNetrimise, tcTrimise, tcErori, tcPJ
LOCAL lnActivePage, lcView, lcFiltruBaza, lcDif, llLipsa, lcSql, llSucces, lnDif, lnLipsa, lnNetrimise, lnTrimise, lnErori, lnPJ, lcCursor, llFaraBife, lnSelect, lnRec
lnActivePage = This.pgfeFactura.ActivePage
lnDif = 0
lnLipsa = 0
*!* fara nicio bifa, cursorul afisat e chiar setul de baza: numaram local, fara interogare
DO CASE
CASE m.lnActivePage = 1
lcCursor = 'crsFacturiEmise'
llFaraBife = EMPTY(This.pgfeFactura.page1.chkPJ.Value) AND EMPTY(This.pgfeFactura.page1.chkNetrimise.Value) ;
AND EMPTY(This.pgfeFactura.page1.chkTrimise.Value) AND EMPTY(This.pgfeFactura.page1.chkErori.Value) ;
AND EMPTY(This.pgfeFactura.page1.chkDiferente.Value)
CASE m.lnActivePage = 2
lcCursor = 'crsFacturiTrimise'
llFaraBife = EMPTY(This.pgfeFactura.page3.chkDiferente.Value) AND EMPTY(This.pgfeFactura.page3.chkLipsaRegistru.Value)
CASE m.lnActivePage = 3
lcCursor = 'crsFacturiPrimite'
llFaraBife = EMPTY(This.pgfeFactura.page2.chkDiferente.Value) AND EMPTY(This.pgfeFactura.page2.chkLipsaRegistru.Value)
OTHERWISE
RETURN
ENDCASE
IF m.llFaraBife AND USED(m.lcCursor)
lnSelect = SELECT()
lnRec = RECNO(m.lcCursor)
IF m.lnActivePage = 1
SELECT SUM(IIF(NVL(tip_persoana,1) = 1, 1, 0)) as npj, ;
SUM(IIF(NVL(trimis,0) = 0, 1, 0)) as nnetrimise, ;
SUM(IIF(NVL(trimis,0) = 1 AND EMPTY(NVL(data_raspuns, {})), 1, 0)) as ntrimise, ;
SUM(IIF(NVL(trimis,0) = 1 AND ALLTRIM(NVL(tip_mesaj_raspuns,'')) == 'ERORI FACTURA', 1, 0)) as nerori, ;
SUM(IIF(ISNULL(jtotctva) OR ABS(NVL(diferenta,0)) > 0.15, 1, 0)) as ndif ;
FROM crsFacturiEmise INTO CURSOR crsNumarBifeLocal NOFILTER
lnPJ = NVL(crsNumarBifeLocal.npj,0)
lnNetrimise = NVL(crsNumarBifeLocal.nnetrimise,0)
lnTrimise = NVL(crsNumarBifeLocal.ntrimise,0)
lnErori = NVL(crsNumarBifeLocal.nerori,0)
lnDif = NVL(crsNumarBifeLocal.ndif,0)
USE IN (SELECT('crsNumarBifeLocal'))
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkNetrimise, m.lnNetrimise)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkTrimise, m.lnTrimise)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkErori, m.lnErori)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkPJ, m.lnPJ)
ELSE
SELECT SUM(IIF(!ISNULL(jtotctva) AND (ALLTRIM(NVL(nume_valuta,'RON')) <> 'RON' OR ABS(NVL(diferenta,0)) > 0.15), 1, 0)) as ndif, ;
SUM(IIF(ISNULL(jtotctva), 1, 0)) as nlipsa ;
FROM (m.lcCursor) INTO CURSOR crsNumarBifeLocal NOFILTER
lnDif = NVL(crsNumarBifeLocal.ndif,0)
lnLipsa = NVL(crsNumarBifeLocal.nlipsa,0)
USE IN (SELECT('crsNumarBifeLocal'))
IF m.lnActivePage = 2
This.SeteazaCaptionDiferente(This.pgfeFactura.page3.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page3.chkLipsaRegistru, m.lnLipsa)
ELSE
This.SeteazaCaptionDiferente(This.pgfeFactura.page2.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page2.chkLipsaRegistru, m.lnLipsa)
ENDIF
ENDIF
SELECT (m.lcCursor)
IF m.lnRec > 0 AND m.lnRec <= RECCOUNT()
GO m.lnRec
ENDIF
SELECT (m.lnSelect)
RETURN
ENDIF
* Pagina 1: fiecare bifa se numara independent pe filtrul de baza, indiferent de celelalte bife
IF m.lnActivePage = 1
lnNetrimise = 0
lnTrimise = 0
lnErori = 0
lnPJ = 0
IF !EMPTY(NVL(m.tcFiltruBaza1,''))
lcSql = "select count(case when " + m.tcDif1 + " then 1 end) as ndif" + ;
", count(case when " + m.tcNetrimise + " then 1 end) as nnetrimise" + ;
", count(case when " + m.tcTrimise + " then 1 end) as ntrimise" + ;
", count(case when " + m.tcErori + " then 1 end) as nerori" + ;
", count(case when " + m.tcPJ + " then 1 end) as npj" + ;
" from anaf_vefactura_emis where 1=1 " + m.tcFiltruBaza1
llSucces = goExecutor.oExecuta(m.lcSql, 'crsNumarDiferente')
IF m.llSucces
lnDif = NVL(crsNumarDiferente.ndif,0)
lnNetrimise = NVL(crsNumarDiferente.nnetrimise,0)
lnTrimise = NVL(crsNumarDiferente.ntrimise,0)
lnErori = NVL(crsNumarDiferente.nerori,0)
lnPJ = NVL(crsNumarDiferente.npj,0)
ENDIF
ENDIF
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkNetrimise, m.lnNetrimise)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkTrimise, m.lnTrimise)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkErori, m.lnErori)
This.SeteazaCaptionDiferente(This.pgfeFactura.page1.chkPJ, m.lnPJ)
RETURN
ENDIF
DO CASE
CASE m.lnActivePage = 2
lcView = 'anaf_vefactura_trimis'
lcFiltruBaza = m.tcFiltruBaza3
lcDif = m.tcDif3
llLipsa = .T.
CASE m.lnActivePage = 3
lcView = 'anaf_vefactura_primit'
lcFiltruBaza = m.tcFiltruBaza2
lcDif = m.tcDif2
llLipsa = .T.
OTHERWISE
RETURN
ENDCASE
* Numarul se reseteaza pe 0 (caption fara paranteza) cand filtrul e gol sau interogarea esueaza
IF !EMPTY(NVL(m.lcFiltruBaza,'')) AND !EMPTY(NVL(m.lcDif,''))
lcSql = "select count(case when " + m.lcDif + " then 1 end) as ndif" + ;
IIF(m.llLipsa, ", count(case when " + m.tcLipsa + " then 1 end) as nlipsa", "") + ;
" from " + m.lcView + " where 1=1 " + m.lcFiltruBaza
llSucces = goExecutor.oExecuta(m.lcSql, 'crsNumarDiferente')
IF m.llSucces
lnDif = NVL(crsNumarDiferente.ndif,0)
IF m.llLipsa
lnLipsa = NVL(crsNumarDiferente.nlipsa,0)
ENDIF
ENDIF
ENDIF
DO CASE
CASE m.lnActivePage = 2
This.SeteazaCaptionDiferente(This.pgfeFactura.page3.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page3.chkLipsaRegistru, m.lnLipsa)
CASE m.lnActivePage = 3
This.SeteazaCaptionDiferente(This.pgfeFactura.page2.chkDiferente, m.lnDif)
This.SeteazaCaptionDiferente(This.pgfeFactura.page2.chkLipsaRegistru, m.lnLipsa)
ENDCASE
ENDPROC
PROCEDURE refreshdetaliifacturi
Lparameters tcTip
* tcTip: EMISE/TRIMISE/PRIMITE
@@ -6119,6 +6283,13 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE SeteazaCaptionDiferente
LPARAMETERS toCheck, tnNumar
LOCAL lcBaza
lcBaza = IIF(EMPTY(NVL(toCheck.Tag,'')), toCheck.Caption, toCheck.Tag)
toCheck.Caption = ALLTRIM(lcBaza) + IIF(NVL(tnNumar,0) > 0, ' (' + ALLTRIM(STR(tnNumar)) + ')', '')
ENDPROC
PROCEDURE Show
LPARAMETERS nStyle
DODEFAULT(nStyle)
@@ -6165,6 +6336,8 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
this.pgfeFactura.page2.grdFacturiPrimite.HeaderHeight = 35
this.pgfeFactura.page3.grdFacturiTrimise.HeaderHeight = 35
*!* numerele de pe bife apar de la deschidere, numarate local din cursorul deja adus
This.NumaraDiferente()
ENDPROC
@@ -8884,6 +9057,7 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
*m: importmodifica
*m: listarenir
*m: modificanote
*m: numaradiferenteimport
*m: scrienote
*p: lprimite
*p: nidborderou
@@ -9098,12 +9272,12 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
BackStyle = 1, ;
Caption = "Cu diferente Reg. TVA", ;
Height = 18, ;
Left = 180, ;
Left = 190, ;
Name = "chkDiferente", ;
Style = 0, ;
Top = 35, ;
Value = .F., ;
Width = 159
Width = 191
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'chkDistribuieDiscount' AS _checkbox WITH ;
@@ -9136,7 +9310,7 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
Style = 0, ;
Top = 35, ;
Value = .F., ;
Width = 159
Width = 174
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'chkTVAIncasare' AS _checkbox WITH ;
@@ -11531,7 +11705,7 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE do_cauta
Local lcCond, lcDif, lcLipsa
Local lcCond, lcDif, lcLipsa, lcFiltruBaza
lcFiltru = '' && filtru facturi primite
* DACA FILTRUL NU CONTINE DATA_ACT, SELECTEZ DOAR INREGISTRARILE DIN LUNA CURENTA PANA LA ZI
@@ -11547,6 +11721,14 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
lcFiltru = m.lcFiltru + [ and ((data_act >= to_date('] + m.lcData1 + [','ddmmyyyy') and data_act < to_date('] + m.lcData2 + [','ddmmyyyy')) or (data_act is null and data_raspuns >= to_date('] + m.lcData1 + [','ddmmyyyy')))]
ENDIF
* Filtre buton cautare
IF LEN(THISFORM.filtru_pretty)>0
lcFiltru = m.lcFiltru + " and (" + ALLTRIM(THISFORM.filtru_pretty) + ")"
ENDIF
* Filtrul de baza (fara chkDiferente/chkLipsaRegistru), pentru numarul independent din caption
lcFiltruBaza = m.lcFiltru
* Bifele Diferente / Lipsa din registrul de TVA
lcLipsa = [(jtotctva is null)]
lcDif = [(jtotctva is not null and (NVL(nume_valuta,'RON') <> 'RON' or ABS(decode(creditnote,0,1,-1) * NVL(total_cu_tva,0.00) - (NVL(jtotctva,0.00) - NVL(jtva_ti,0.00))) > 0.15))]
@@ -11561,11 +11743,6 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
lcFiltru = m.lcFiltru + [ and (] + m.lcCond + [)]
ENDIF
* Filtre buton cautare
IF LEN(THISFORM.filtru_pretty)>0
lcFiltru = m.lcFiltru + " and (" + ALLTRIM(THISFORM.filtru_pretty) + ")"
ENDIF
If Empty(m.lcFiltru)
aMessagebox("Alegeti un criteriu!",0+48,"Atentie")
Return
@@ -11584,6 +11761,8 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
ENDIF
This.NumaraDiferenteImport(m.lcFiltruBaza, m.lcDif, m.lcLipsa)
Return m.lcFiltru
ENDPROC
@@ -12988,6 +13167,10 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
this.grdFacturi.SetAll("DynamicForeColor","IIF(creditnote = 1, RGB(225,0,0), RGB(0,0,0))", "Column")
this.gridextra1.setup()
this.gridextra2.setup()
* Caption de baza pentru bifele Diferente/Lipsa, refolosit de NumaraDiferenteImport
This.chkDiferente.Tag = This.chkDiferente.Caption
This.chkLipsaRegistru.Tag = This.chkLipsaRegistru.Caption
ENDPROC
PROCEDURE KeyPress
@@ -13179,6 +13362,51 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE NumaraDiferenteImport
LPARAMETERS tcFiltruBaza, tcDif, tcLipsa
LOCAL lcView, lcSql, llSucces, lnDif, lnLipsa, lnSelect, lnRec
lnDif = 0
lnLipsa = 0
*!* fara nicio bifa, cursorul afisat e chiar setul de baza: numaram local, fara interogare
IF EMPTY(This.chkDiferente.Value) AND EMPTY(This.chkLipsaRegistru.Value) AND USED('crsFacturi')
lnSelect = SELECT()
lnRec = RECNO('crsFacturi')
SELECT SUM(IIF(!ISNULL(jtotctva) AND (ALLTRIM(NVL(nume_valuta,'RON')) <> 'RON' OR ABS(NVL(diferenta,0)) > 0.15), 1, 0)) as ndif, ;
SUM(IIF(ISNULL(jtotctva), 1, 0)) as nlipsa ;
FROM crsFacturi INTO CURSOR crsNumarBifeLocal NOFILTER
lnDif = NVL(crsNumarBifeLocal.ndif,0)
lnLipsa = NVL(crsNumarBifeLocal.nlipsa,0)
USE IN (SELECT('crsNumarBifeLocal'))
This.chkDiferente.Caption = ALLTRIM(IIF(EMPTY(NVL(This.chkDiferente.Tag,'')), This.chkDiferente.Caption, This.chkDiferente.Tag)) + IIF(m.lnDif > 0, ' (' + ALLTRIM(STR(m.lnDif)) + ')', '')
This.chkLipsaRegistru.Caption = ALLTRIM(IIF(EMPTY(NVL(This.chkLipsaRegistru.Tag,'')), This.chkLipsaRegistru.Caption, This.chkLipsaRegistru.Tag)) + IIF(m.lnLipsa > 0, ' (' + ALLTRIM(STR(m.lnLipsa)) + ')', '')
SELECT crsFacturi
IF m.lnRec > 0 AND m.lnRec <= RECCOUNT()
GO m.lnRec
ENDIF
SELECT (m.lnSelect)
RETURN
ENDIF
lcView = IIF(This.lPrimite, 'anaf_vefactura_primit', 'anaf_vefactura_trimis')
* Numarul se reseteaza pe 0 (caption fara paranteza) cand filtrul e gol sau interogarea esueaza
IF !EMPTY(NVL(m.tcFiltruBaza,'')) AND !EMPTY(NVL(m.tcDif,''))
lcSql = "select count(case when " + m.tcDif + " then 1 end) as ndif" + ;
", count(case when " + m.tcLipsa + " then 1 end) as nlipsa" + ;
" from " + m.lcView + " where 1=1 " + m.tcFiltruBaza
llSucces = goExecutor.oExecuta(m.lcSql, 'crsNumarDiferenteImport')
IF m.llSucces
lnDif = NVL(crsNumarDiferenteImport.ndif,0)
lnLipsa = NVL(crsNumarDiferenteImport.nlipsa,0)
ENDIF
ENDIF
This.chkDiferente.Caption = ALLTRIM(IIF(EMPTY(NVL(This.chkDiferente.Tag,'')), This.chkDiferente.Caption, This.chkDiferente.Tag)) + IIF(m.lnDif > 0, ' (' + ALLTRIM(STR(m.lnDif)) + ')', '')
This.chkLipsaRegistru.Caption = ALLTRIM(IIF(EMPTY(NVL(This.chkLipsaRegistru.Tag,'')), This.chkLipsaRegistru.Caption, This.chkLipsaRegistru.Tag)) + IIF(m.lnLipsa > 0, ' (' + ALLTRIM(STR(m.lnLipsa)) + ')', '')
ENDPROC
PROCEDURE scrienote
ENDPROC
@@ -13194,6 +13422,8 @@ DEFINE CLASS frm_import_efactura AS _frmbase OF "_frm_base.vcx"
Thisform.CompleteazaFactura() && cap factura
Thisform.actualizeaza_grid2()
Thisform.CompleteazaDetaliiFactura() && detalii factura
*!* numerele de pe bife apar de la deschidere, numarate local din cursorul deja adus
This.NumaraDiferenteImport()
ENDPROC

View File

@@ -1131,8 +1131,10 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="Clb_serie" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Ed_tx_explicatie" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="cb_explicatie_saft" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="ck_pret_cu_tva" UniqueID="" Timestamp="" />
*<DefinedPropArrayMethod>
*m: do_aplica_mod_pret
*m: do_calculeaza_adaos
*m: do_calculeaza_discount
*m: do_calculeaza_pretctva
@@ -1155,7 +1157,7 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
BorderStyle = 1
Caption = "Form"
DoCreate = .T.
Height = 450
Height = 500
larata = .T.
lcuadaos = .T.
lmodpretctva = .F.
@@ -1284,6 +1286,16 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
_lbbase1.Top = 6
*< END OBJECT: ClassLib="lb_tx.vcx" BaseClass="container" />
ADD OBJECT 'ck_pret_cu_tva' AS _checkbox WITH ;
Alignment = 0, ;
Caption = "Pret cu TVA inclus", ;
ControlSource = "poArticol.preturi_cu_tva", ;
Left = 6, ;
Name = "ck_pret_cu_tva", ;
TabIndex = 24, ;
Top = 464
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT 'clb_articol' AS clb_tx_simplu WITH ;
Left = 6, ;
Name = "clb_articol", ;
@@ -1792,6 +1804,51 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
_lbbase1.Top = 6
*< END OBJECT: ClassLib="lb_tx.vcx" BaseClass="container" />
PROCEDURE do_aplica_mod_pret
Lparameters lnTip && 1 = sume in lei, 2 = sume in valuta
If Inlist(poDate.tip,1,5,10,22,23,25,29,41) && documente pe baza de lista de preturi (1/5 factura lei si valuta, 10 factura fiscala in valuta, 22 aviz clienti, 23/25/41 transfer subunitati, 29 aviz clienti debitori): pretul e editabil oricum, pe restul doar daca e 0
If poArticol.preturi_cu_tva = 0
Thisform.lmodpretftva = .T.
Thisform.clb_pretftva.do_activeaza(lnTip)
Else
Thisform.lmodpretctva = .T.
Thisform.clb_pretctva.do_activeaza(lnTip)
Endif
Else
If Type('Thisform.clb_procent_adaos') = 'O'
Thisform.clb_procent_adaos.Visible = .F.
Endif
Thisform.lcuadaos = .F.
If poArticol.preturi_cu_tva = 0 And ;
((poArticol.pretftva = 0 And lnTip = 1) Or (poArticol.pretftva_val = 0 And lnTip = 2))
Thisform.lmodpretftva = .T.
Thisform.clb_pretftva.do_activeaza(lnTip)
Else
If poArticol.preturi_cu_tva = 1 And ;
((poArticol.pretctva = 0 And lnTip = 1) Or (poArticol.pretctva_val = 0 And lnTip = 2))
Thisform.lmodpretctva = .T.
Thisform.clb_pretctva.do_activeaza(lnTip)
Endif
Endif
Endif
If poArticol.preturi_cu_tva = 0
Thisform.clb_discount_unitar.do_activeaza(lnTip)
Thisform.clb_totalfdiscount.lb_explicatii.Caption = []
Thisform.clb_totalcdiscount.lb_explicatii.Caption = []
Thisform.clb_pret_diminuat.lb_explicatii.Caption = [(2) - (5)]
Else
Thisform.clb_discountctva.do_activeaza(lnTip)
Thisform.clb_totalfdiscount.lb_explicatii.Caption = [(1) * (4)]
Thisform.clb_totalcdiscount.lb_explicatii.Caption = [(1) * ( (4) - (7) )]
With Thisform.clb_pret_diminuat
.lb_explicatie.Caption = [Pret unitar diminuat cu TVA]
.lb_explicatii.Caption = [(4) - (7)]
Endwith
Endif
Thisform.ck_pret_cu_tva.Enabled = (Thisform.lmodpretftva Or Thisform.lmodpretctva)
ENDPROC
PROCEDURE do_calculeaza_adaos
Lparameters tnValoare,tnTip
If Thisform.lcuadaos
@@ -2364,54 +2421,7 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
*!* *!* modificare v 2.0.46 ^
*!* modificare v 2.0.74 ^
*!* modificare v 2.0.4
*!* If Iif(Type('poArticol.modificabil')<>'U',poArticol.modificabil,0) = 1
*!* modificare v 2.0.30 : am adaugat 41
*!* modificare v 2.0.44 : am adaugat 42
*!* If Inlist(poDate.tip,1,3,5,21,22,23,25,28,29,41,42)
If Inlist(poDate.tip,1,5,10,22,23,25,29,41) && modificare v 2.0.56 : am adaugat 10
*!* modificare v 2.0.4 ^
If poArticol.preturi_cu_tva = 0
Thisform.lmodpretftva = .T.
Thisform.clb_pretftva.do_activeaza(lnTip)
Else
Thisform.lmodpretctva = .T.
*!* modificare v 2.0.4
*!* Thisform.RemoveObject('clb_procent_adaos')
*!* thisform.lcuadaos = .F.
*!* modificare v 2.0.4 ^
Thisform.clb_pretctva.do_activeaza(lnTip)
Endif
Else
Thisform.clb_procent_adaos.Visible = .F.
Thisform.lcuadaos = .F.
If poArticol.preturi_cu_tva = 0 And ;
((poArticol.pretftva = 0 And lnTip = 1) Or (poArticol.pretftva_val = 0 And lnTip = 2))
Thisform.lmodpretftva = .T.
Thisform.clb_pretftva.do_activeaza(lnTip)
Else
If poArticol.preturi_cu_tva = 1 And ;
((poArticol.pretctva = 0 And lnTip = 1) Or (poArticol.pretctva_val = 0 And lnTip = 2))
Thisform.lmodpretctva = .T.
Thisform.clb_pretctva.do_activeaza(lnTip)
Endif
Endif
Endif
If poArticol.preturi_cu_tva = 0
Thisform.clb_discount_unitar.do_activeaza(lnTip)
Thisform.clb_totalfdiscount.lb_explicatii.Caption = []
Thisform.clb_totalcdiscount.lb_explicatii.Caption = []
Thisform.clb_pret_diminuat.lb_explicatii.Caption = [(2) - (5)]
Else
Thisform.clb_discountctva.do_activeaza(lnTip)
Thisform.clb_totalfdiscount.lb_explicatii.Caption = [(1) * (4)]
Thisform.clb_totalcdiscount.lb_explicatii.Caption = [(1) * ( (4) - (7) )]
With Thisform.clb_pret_diminuat
.lb_explicatie.Caption = [Pret unitar diminuat cu TVA]
.lb_explicatii.Caption = [(4) - (7)]
Endwith
Endif
Thisform.do_aplica_mod_pret(lnTip)
*!* modificare v 2.0.19
*!* If (poDate.tip=2 And pnTipFacturare=3) Or INLIST(poDate.tip,4,23)
@@ -2570,6 +2580,19 @@ DEFINE CLASS frm_articol_factura AS _frmbase OF "_frm_base.vcx"
Thisform.UpdateExplicatieSaft()
ENDPROC
PROCEDURE ck_pret_cu_tva.InteractiveChange
Local lnTip
poArticol.preturi_cu_tva = This.Value
lnTip = Iif(poArticol.tip_valuta = 0, 1, 2)
If This.Value = 1
Thisform.do_calculeaza_pretftva(Iif(lnTip = 1, poArticol.pretctva, poArticol.pretctva_val), lnTip)
Else
Thisform.do_calculeaza_pretctva(Iif(lnTip = 1, poArticol.pretftva, poArticol.pretftva_val), lnTip)
Endif
Thisform.do_aplica_mod_pret(lnTip)
Thisform.do_calculeaza_totaluri()
ENDPROC
PROCEDURE clb_cantitate.Text_simplu1.InteractiveChange
lcval=This.ControlSource
&lcval=This.Value
@@ -3146,7 +3169,7 @@ DEFINE CLASS frm_articol_gest_factura AS frm_articol_factura OF "ofacturare.vcx"
*<PropValue>
cgridsortlist = grd_gestiuni
DoCreate = .T.
Height = 510
Height = 546
lretur = .F.
Name = "frm_articol_gest_factura"
Width = 835
@@ -3398,6 +3421,9 @@ DEFINE CLASS frm_articol_gest_factura AS frm_articol_factura OF "ofacturare.vcx"
Cb_contract._cbbase1.Top = 3
Cb_contract._cbbase1.Width = 274
Cb_contract._lbbase1.Name = "_lbbase1"
ck_pret_cu_tva.Left = 13
ck_pret_cu_tva.Name = "ck_pret_cu_tva"
ck_pret_cu_tva.Top = 510
*</PropValue>
ADD OBJECT 'Cb_tx_articol' AS cb_tx_cautare WITH ;
@@ -11048,6 +11074,7 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="grd_contracte.cNumar_contract.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="grd_contracte.cCodbare.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="grd_contracte.cCodbare.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="But_modifica1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="But_sterge1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="lb_total_mod" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Gridextra1" UniqueID="" Timestamp="" />
@@ -11162,6 +11189,16 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
Gridsort1.Top = 36
*</PropValue>
ADD OBJECT 'But_modifica1' AS but_modifica WITH ;
Anchor = 9, ;
caction = do_modifica, ;
Left = 773, ;
Name = "But_modifica1", ;
TabIndex = 13, ;
Top = 61, ;
Visible = .T.
*< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" />
ADD OBJECT 'But_renunt1' AS but_renunt WITH ;
Anchor = 8, ;
Height = 27, ;
@@ -13161,12 +13198,15 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE do_alege_stoc
Lparameters tnIdArticol,tnCantitate,tcNumeArticol,tlImplicit,tnPret,tnDiscount,toGrid, tlRetur
Lparameters tnIdArticol,tnCantitate,tcNumeArticol,tlImplicit,tnPret,tnDiscount,toGrid, tlRetur, tnIdTempExclus
* llImplicit => vezi thisform.do_adauga
* tnPret => doar pentru retururi : e pretul de vanzare fara TVA
* toGrid => gridul din care vine articolul
* tlRetur => factura normala cu articol retur (nu factura de retur tip 8,9). se comporta la fel ca factura de retur. se selecteaza din RUL, dar nu stiu factura din care fac retur
* tnIdTempExclus => id_temp-ul liniei modificate, exclus din cantitatea deja retinuta pe factura (0 la adaugare)
If Type('tnIdTempExclus') <> 'N'
tnIdTempExclus = 0
Endif
Private pnIdArticol
Local llReturn,lofrmadarticol,lcSql, llFacturareFaraStoc
llFactuareFaraStoc = .F.
@@ -13232,7 +13272,7 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
* Arat cantitatile din stoc - cantitatile deja pe factura curenta
Select Iif(poDate.tip=41,-1,1)*Sum(cantitate) As cantitate,id_articol,id_gestiune,pret_achizitie,serie,lot,Cont, ;
id_part_rez,id_lucrare_rez,pretv_orig,pretd,id_valuta_d ;
FROM crsfactura Where id_articol = pnIdArticol ;
FROM crsfactura Where id_articol = pnIdArticol And id_temp <> tnIdTempExclus ;
GROUP By id_articol,id_gestiune,pret_achizitie,serie,lot,Cont,id_part_rez,id_lucrare_rez,pretv_orig,pretd,id_valuta_d ;
INTO CURSOR crsFacturaArticoleTemp
@@ -13275,6 +13315,12 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
SELECT (m.lcCursor)
Go Top
If tnIdTempExclus > 0
Locate For id_gestiune = poArticol.id_gestiune And Pret = poArticol.pret_achizitie And Cont = poArticol.Cont And Nvl(serie,'') = Nvl(poArticol.serie,'') And Nvl(lot,'') = Nvl(poArticol.lot,'') And Nvl(id_part_rez,0) = Nvl(poArticol.id_part_rez,0) And Nvl(id_lucrare_rez,0) = Nvl(poArticol.id_lucrare_rez,0) And pretv = poArticol.pretv_orig And pretd = poArticol.pretd And Nvl(id_valuta,0) = Nvl(poArticol.id_valuta_d,0)
If !Found()
Go Top
Endif
Endif
Do Case
Case Reccount(lcCursor) = 0
amessagebox("Articolul "+Alltrim(tcNumeArticol)+" nu mai este pe stoc!",0+48,"Atentie")
@@ -13697,6 +13743,176 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
*!* modificare v 2.0.67 ^
ENDPROC
PROCEDURE do_modifica
If Reccount('crsfactura')>0
Private poArticol, pnProcentDiscountMem
Local lnRecno, ofrmadarticol
Select crsfactura
lnRecno = Recno()
Scatter Name poArticol MEMO
AddProperty(poArticol,'preturi_cu_tva',poArticol.cu_tva)
AddProperty(poArticol,'discount_unitar',poArticol.discountftva)
AddProperty(poArticol,'discount_unitar_ctva',poArticol.discountctva)
AddProperty(poArticol,'pretftva_val',poArticol.vpretftva)
AddProperty(poArticol,'pretctva_val',poArticol.vpretctva)
AddProperty(poArticol,'discount_unitar_val',poArticol.vdiscountftva)
AddProperty(poArticol,'discount_unitar_ctva_val',poArticol.vdiscountctva)
Removeproperty(poArticol,'cu_tva')
Removeproperty(poArticol,'discountftva')
Removeproperty(poArticol,'discountctva')
Removeproperty(poArticol,'vpretftva')
Removeproperty(poArticol,'vpretctva')
Removeproperty(poArticol,'vdiscountftva')
Removeproperty(poArticol,'vdiscountctva')
AddProperty(poArticol,'tva',poArticol.pretctva - poArticol.pretftva)
AddProperty(poArticol,'tva_val',poArticol.pretctva_val - poArticol.pretftva_val)
pnProcentDiscountMem = 0
If Nvl(gnMemProcDisc, 0) = 1
pnProcentDiscountMem = Thisform.nproc_disc_mem
Endif
* plafonul de cantitate = stocul disponibil reconstituit din cursorul sursa; fara randul in cursor ramane cantitatea liniei
Local lnCantitateMax, lcCursorStoc, lcAliasCrt, lnRecnoStoc, lnCantitateVeche, lnIdTempLinie, lnDeltaCantitate, lnTotalCantitate
lnCantitateMax = poArticol.cantitate
lcCursorStoc = Iif(poArticol.opt_facturare = 0, [crsarticole], [crsarticole1])
If Used(lcCursorStoc)
lcAliasCrt = Alias()
Select (lcCursorStoc)
lnRecnoStoc = Recno()
Locate For id_c = poArticol.id_c
If Found()
Do Case
Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip, 4, 21, 28, 42, 47) && adaugarea scade stocul; lista e cea validata la plafon (fara 3 si 25): 23 transfer subunitati, 4 din avize, 21/28/42/47 catre clienti
lnCantitateMax = cantitate + poArticol.cantitate
Case Inlist(poDate.tip, 8, 9, 24) && adaugarea creste stocul: 8/9 retur factura in lei si in valuta, 24 aviz de retur
lnCantitateMax = cantitate - poArticol.cantitate
Endcase
Endif
Try
Go lnRecnoStoc
Catch
Go Top
Endtry
Select (lcAliasCrt)
Endif
gnButon = 2
lnCantitateVeche = poArticol.cantitate
lnIdTempLinie = poArticol.id_temp
Do Case
Case (poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45) && 45 = ROARESTAURANT
ofrmadarticol = Createobject("frm_articol_factura", lnCantitateMax, .F.)
ofrmadarticol.Show(1)
Release ofrmadarticol
Otherwise
Thisform.do_alege_stoc(poArticol.id_articol, lnCantitateMax, poArticol.denumire, .F., poArticol.pretftva, poArticol.discount_unitar, Thisform.grd_factura, .F., lnIdTempLinie)
Endcase
If gnButon = 1
Select crsfactura
Try
Go lnRecno
Catch
Go Top
Endtry
If Used('crsartselectate')
lnTotalCantitate = poArticol.cantitate
Select crsartselectate
Go Top
poArticol.pret_achizitie = Pret
poArticol.serie = Nvl(serie, [])
poArticol.lot = Nvl(lot, [])
poArticol.id_gestiune = id_gestiune
poArticol.Cont = Alltrim(Cont)
poArticol.cantitate = cantitate
poArticol.pretv_orig = pretv
poArticol.id_lucrare_rez = id_lucrare_rez
poArticol.id_part_rez = id_part_rez
poArticol.pretd = pretd
poArticol.id_valuta_d = id_valuta
Select crsfactura
Endif
Gather Name poArticol Fields Like pret_achizitie, denumire, cantitate, id_articol, Id_Pol, Cont, id_gestiune, Proc_Tvav, ;
pretftva, valftva, valtva, valctva, valdiscountftva, valdiscounttva, valdiscountctva, Pretctva, ;
valdiminuatftva, valdiminuattva, valdiminuatctva, ;
vvalftva, vvaltva, vvalctva, vvaldiscountftva, vvaldiscounttva, vvaldiscountctva, ;
vvaldiminuatftva, vvaldiminuattva, vvaldiminuatctva, id_c, lot, serie, explicatie, ;
id_valuta, gestionabil, tip_valuta, id_jtva_coloana, taxcode, id_lucrare_rez, id_part_rez, pretv_orig, pretd, id_valuta_d, id_ctr, opt_facturare, nume_val MEMO
Replace cu_tva With poArticol.preturi_cu_tva, ;
discountftva With poArticol.discount_unitar, discountctva With poArticol.discount_unitar_ctva, ;
vpretftva With Nvl(poArticol.pretftva_val,0), vpretctva With Nvl(poArticol.pretctva_val,0), ;
vdiscountftva With Nvl(poArticol.discount_unitar_val,0), vdiscountctva With Nvl(poArticol.discount_unitar_ctva_val,0)
If Used('crsartselectate')
Select crsartselectate
Skip
Scan Rest
poArticol.pret_achizitie = Pret
poArticol.serie = Nvl(serie, [])
poArticol.lot = Nvl(lot, [])
poArticol.id_gestiune = id_gestiune
poArticol.Cont = Alltrim(Cont)
poArticol.cantitate = cantitate
poArticol.pretv_orig = pretv
poArticol.id_lucrare_rez = id_lucrare_rez
poArticol.id_part_rez = id_part_rez
poArticol.pretd = pretd
poArticol.id_valuta_d = id_valuta
Select crsfactura
Append Blank
Gather Name poArticol Fields Like pret_achizitie, denumire, cantitate, id_articol, Id_Pol, ;
Cont, id_gestiune, Proc_Tvav, pretftva, Pretctva, ;
id_c, lot, serie, explicatie, ;
id_valuta, gestionabil, tip_valuta, id_jtva_coloana, taxcode, id_lucrare_rez, id_part_rez, pretv_orig, pretd, id_valuta_d, nume_val, id_ctr, opt_facturare MEMO
Replace id_temp With Recno(), codmat With Nvl(poArticol.codmat, Space(50)), ;
codbare With Nvl(poArticol.codbare, Space(50)), ;
codmatf With Nvl(poArticol.codmatf, Space(50)), um With Nvl(poArticol.um, Space(50)), ;
Curs With Nvl(poArticol.Curs, 0), multiplicator With Nvl(poArticol.multiplicator, 1), ;
cu_tva With poArticol.preturi_cu_tva, ;
vpretftva With Nvl(poArticol.pretftva_val, 0), vpretctva With Nvl(poArticol.pretctva_val, 0), ;
discountftva With poArticol.discount_unitar, discountctva With poArticol.discount_unitar_ctva, ;
vdiscountftva With Nvl(poArticol.discount_unitar_val, 0), ;
vdiscountctva With Nvl(poArticol.discount_unitar_ctva_val, 0)
poArticol = calculeaza_totaluri(poArticol)
Gather Name poArticol Fields Like valftva, valtva, valctva, ;
valdiscountftva, valdiscounttva, valdiscountctva, ;
valdiminuatftva, valdiminuattva, valdiminuatctva, ;
vvalftva, vvaltva, vvalctva, ;
vvaldiscountftva, vvaldiscounttva, vvaldiscountctva, ;
vvaldiminuatftva, vvaldiminuattva, vvaldiminuatctva MEMO
Endscan
Use In crsartselectate
poArticol.cantitate = lnTotalCantitate
Select crsfactura
Endif
lnDeltaCantitate = poArticol.cantitate - lnCantitateVeche
If lnDeltaCantitate <> 0 And Used(lcCursorStoc)
lcAliasCrt = Alias()
Select (lcCursorStoc)
lnRecnoStoc = Recno()
Do Case
Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip, 4, 21, 28, 42, 47)
Replace cantitate With cantitate - lnDeltaCantitate For id_c = poArticol.id_c
Case Inlist(poDate.tip, 8, 9, 24)
Replace cantitate With cantitate + lnDeltaCantitate For id_c = poArticol.id_c
Endcase
Try
Go lnRecnoStoc
Catch
Go Top
Endtry
Select (lcAliasCrt)
Endif
If Nvl(gnMemProcDisc, 0) = 1
Thisform.nproc_disc_mem = pnProcentDiscountMem
Endif
Thisform.do_calculeaza_totaluri()
Thisform.grd_factura.Refresh()
Thisform.grd_factura.SetFocus()
Endif
Release poArticol, pnProcentDiscountMem
Endif
ENDPROC
PROCEDURE do_renunt
*!* modificare 19.01.2007
DODEFAULT()
@@ -14006,7 +14222,6 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
pnParametruAditional = 0
llReturn = .T.
lcListaIncasare = ''
SET STEP ON
llEproforma = (poDate.eProforma = 1)
If Inlist(poDate.ntip_incasare, 11, 2, 3) && 11 = CHITANTA, 2 = BON FISCAL, 3 = POS/Card
@@ -15513,6 +15728,10 @@ DEFINE CLASS frm_facturare_articole AS _frmbase OF "_frm_base.vcx"
*Nu sterge
ENDPROC
PROCEDURE grd_factura.DblClick
Thisform.do_modifica()
ENDPROC
PROCEDURE grd_factura.Init
*Nu sterge
ENDPROC

View File

@@ -150,7 +150,7 @@ DEFINE CLASS frm_borderou_facturi AS _frmbase OF "_frm_base.vcx"
ADD OBJECT 'Cmd_executa1' AS cmd_executa WITH ;
Anchor = 6, ;
Caption = "Marcheaz<61> \<trimis", ;
Caption = "Marcheaz<61> \<trimis", ;
ForeColor = 0,128,0, ;
Height = 27, ;
Left = 140, ;
@@ -1334,8 +1334,10 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="But_attach1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="But_listare1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="But_verifica1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="But_editare1" UniqueID="" Timestamp="" />
*<DefinedPropArrayMethod>
*m: do_editare_factura
*m: do_listare_cc
*m: do_listare_centr
*m: do_listare_document
@@ -1350,7 +1352,7 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
*<PropValue>
BorderStyle = 1
cbuton2 = but_listare1;but_listare2;But_listare3
cbuton3 = but_modifica1;but_modifica2
cbuton3 = but_modifica1;but_modifica2;But_editare1
cfiltru_initial =
cgridsortlist = grid_facturi,grid_detalii
DoCreate = .T.
@@ -1410,6 +1412,17 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
Visible = .F.
*< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" />
ADD OBJECT 'But_editare1' AS but_modifica WITH ;
Anchor = 12, ;
caction = do_editare_factura, ;
Caption = "", ;
Left = 650, ;
Name = "But_editare1", ;
TabIndex = 29, ;
ToolTipText = "Editare factura (articole, cantitati, preturi)", ;
Top = 341
*< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" />
ADD OBJECT 'But_listare1' AS but_listare WITH ;
Anchor = 8, ;
Left = 698, ;
@@ -3471,7 +3484,7 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
Anchor = 12, ;
AutoSize = .T., ;
BackStyle = 0, ;
Caption = "Total <20>n valuta", ;
Caption = "Total <20>n valuta", ;
FontSize = 10, ;
Height = 18, ;
Left = 311, ;
@@ -3711,6 +3724,150 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
This.do_cauta()
ENDPROC
PROCEDURE do_editare_factura
If !This.lactiv3
Return
Endif
If Reccount('crsfacturi') = 0
amessagebox("Nu exista inregistrari pentru editare!",0+48,"Atentie")
Return
Endif
If glLunaInchisa
Return
Endif
Local lnSters, llEProforma, lnIdSet, lnIdFactD, lnSucces, Omodif, llGasitRand
Private pnAn, pnLuna, lnCod, lnIdFact, lnIdVanzare
Store 0 To pnAn, pnLuna, lnCod, lnIdFact, lnIdSet, lnIdFactD, lnIdVanzare
Select crsfacturi
lnIdVanzare = id_vanzare
lnCod = cod
pnAn = Year(data_act)
pnLuna = Month(data_act)
lnSters = sters
lnIdFact = id_fact
llEProforma = (eproforma = 1)
If lnSters = 1
amessagebox("Acest document este deja sters!",0+48,"Atentie")
Return
Endif
If llEProforma
amessagebox("Proformele nu pot fi editate pe aceasta cale!",0+48,"Atentie")
Return
Endif
If (pnAn * 12) + pnLuna <> (gnAn * 12) + gnLuna
amessagebox('Nu puteti edita decat inregistrari din luna curenta!',0,'Atentie!')
Return
Endif
*** verificare restrictie editare documente cu referinte (incasari/plati)
If ReferinteDocumenteNota(pnAn, pnLuna, lnCod) && odocumente.prg
amessagebox("Documentul are referinte (incasari/plati). Nu poate fi editat.", 0+48,"Editare")
Return
Endif
*** verificare restrictie editare facturi trimise in eFactura
If EsteInEFactura(lnIdFact) && ofacturare_editare.prg
amessagebox("Documentul a fost trimis in eFactura. Nu poate fi editat.", 0+48,"Editare")
Return
Endif
If IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.) && ofacturare_editare.prg
If Reccount('actactan') = 0
amessagebox("Nu exista nota contabila pentru aceasta factura.",0+48,"Atentie")
Else
Select actactan
llGasitRand = .F.
If lnIdFact > 0
Locate For Nvl(id_fact, 0) = lnIdFact
llGasitRand = Found()
Endif
If !llGasitRand
*** rezerva: nota nu contine id_fact-ul din vanzari (avize, transferuri, documente vechi)
Go Top
lnIdFact = id_fact
Endif
lnIdSet = id_set
lnIdFactD = id_factd
Select a.*, Iif(Nvl(id_jtva_coloana,0)=0,0,1) As cu_Tva From tact a Into Cursor tact Readwrite
Select tact
Omodif = Createobject([frm_modific2024], lnIdSet)
Omodif.Show()
If buton = 1
If Thisform.do_deschide_tranzactie()
Select actactan
lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.)
If lnSucces > 0
If Used('actactan')
Use In actactan
Endif
Select tact
Replace id_jtva_coloana With Null, proc_tva With 0 For cu_Tva = 0
Select * From tact Into Cursor actactan Readwrite
Replace All id_util With gnIdUtil, sters With 0
If Used('rul_temp')
Use In rul_temp
Endif
Select * From trul Into Cursor RUL_TEMP Readwrite
Replace All id_util With gnIdUtil, sters With 0
If Used('rul_temp_obinv')
Use In rul_temp_obinv
Endif
Select * From trul_obinv Into Cursor RUL_TEMP_OBINV Readwrite
Replace All id_util With gnIdUtil, sters With 0
lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.)
Endif
If lnSucces > 0
lcSql = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,Null,] + Alltrim(Str(lnIdSet)) + [,] + ;
Alltrim(Str(lnCod)) + [,] + Alltrim(Str(lnIdFact)) + [,] + Alltrim(Str(lnIdFactD)) + [,?gnIdUtil); end;]
lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1)
Endif
If Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1))
If lnSucces > 0
Thisform.do_cauta()
Endif
Endif
Endif
Endif
Endif
If Used('actactan')
Use In actactan
Endif
If Used('tact')
Use In tact
Endif
If Used('rul_temp')
Use In rul_temp
Endif
If Used('trul')
Use In trul
Endif
If Used('rul_temp_obinv')
Use In rul_temp_obinv
Endif
If Used('trul_obinv')
Use In trul_obinv
Endif
Endif
Select crsfacturi
Locate For id_vanzare = lnIdVanzare
If !Found()
Go Top
Endif
ENDPROC
PROCEDURE do_listare
*!* 26.11.2019
*!* marius.mutu
@@ -4333,7 +4490,6 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
Select crsdetalii
Calculate Max(proc_tvav) To lnProcTvav
SET STEP ON
creeaza_facturacrs([crsfactura])
prelucreaza_facturacrs([crsdetalii], [crsfactura], lnProcTvav, lnDiscount, lnDiscountVal)
@@ -4382,7 +4538,6 @@ DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
PROCEDURE do_modifica
Local ofrmmodificare As "frm_modifica_factura"
Local lcSql, lnSucces
SET STEP ON
PRIVATE poRec, pneFactura
If Reccount('crsfacturi') > 0
Local lnRecno, lnNrInreg, lnNrInregMod
@@ -4990,7 +5145,7 @@ DEFINE CLASS frm_modifica_articol_factura AS frm_termin_renunt OF "_frm_child.vc
_shape2.Top = 0
_shape2.Width = 64
_shape2.ZOrderSet = 2
Lb_titlu_alb_b121.Caption = "Modific<69> explica<63>ie articol"
Lb_titlu_alb_b121.Caption = "Modific<69> explica<63>ie articol"
Lb_titlu_alb_b121.Name = "Lb_titlu_alb_b121"
Lb_titlu_alb_b121.TabIndex = 5
Lb_titlu_alb_b121.ZOrderSet = 3
@@ -5048,7 +5203,7 @@ DEFINE CLASS frm_modifica_articol_factura AS frm_termin_renunt OF "_frm_child.vc
_edbase1.Name = "_edbase1", ;
_edbase1.Top = 23, ;
_edbase1.Width = 325, ;
_lbbase1.Caption = "Explica<63>ie", ;
_lbbase1.Caption = "Explica<63>ie", ;
_lbbase1.Name = "_lbbase1"
*< END OBJECT: ClassLib="lb_tx.vcx" BaseClass="container" />
@@ -5282,7 +5437,7 @@ DEFINE CLASS frm_modifica_factura AS frm_termin_renunt OF "_frm_child.vcx"
Text_simplu1.Name = "Text_simplu1", ;
Text_simplu1.Top = 3, ;
Text_simplu1.Width = 177, ;
Lb_simplu1.Caption = "Data <20>i ora expedierii", ;
Lb_simplu1.Caption = "Data <20>i ora expedierii", ;
Lb_simplu1.Name = "Lb_simplu1"
*< END OBJECT: ClassLib="lb_tx.vcx" BaseClass="container" />
@@ -5332,7 +5487,7 @@ DEFINE CLASS frm_modifica_factura AS frm_termin_renunt OF "_frm_child.vcx"
Top = 128, ;
ZOrderSet = 9, ;
img_cautare.Name = "img_cautare", ;
clb_tx_cautare.Lb_simplu1.Caption = "Ma<4D>ina", ;
clb_tx_cautare.Lb_simplu1.Caption = "Ma<4D>ina", ;
clb_tx_cautare.Lb_simplu1.Name = "Lb_simplu1", ;
clb_tx_cautare.Name = "clb_tx_cautare", ;
clb_tx_cautare.Text_simplu1.Left = 133, ;
@@ -6822,7 +6977,7 @@ DEFINE CLASS frm_proforme AS _frmbase OF "_frm_base.vcx"
Anchor = 12, ;
AutoSize = .T., ;
BackStyle = 0, ;
Caption = "Total <20>n valuta", ;
Caption = "Total <20>n valuta", ;
FontSize = 10, ;
Height = 18, ;
Left = 311, ;
@@ -6854,7 +7009,7 @@ DEFINE CLASS frm_proforme AS _frmbase OF "_frm_base.vcx"
OPTION1.Top = 5, ;
OPTION1.Value = 1, ;
OPTION2.AutoSize = .T., ;
OPTION2.Caption = "<22>n valuta", ;
OPTION2.Caption = "<22>n valuta", ;
OPTION2.FontCharSet = 238, ;
OPTION2.FontSize = 10, ;
OPTION2.Left = 55, ;
@@ -6862,7 +7017,7 @@ DEFINE CLASS frm_proforme AS _frmbase OF "_frm_base.vcx"
OPTION2.Top = 5, ;
Option3.AutoSize = .T., ;
Option3.BackStyle = 0, ;
Option3.Caption = "<22>n RON", ;
Option3.Caption = "<22>n RON", ;
Option3.FontCharSet = 238, ;
Option3.FontSize = 10, ;
Option3.Height = 18, ;
@@ -6893,7 +7048,7 @@ DEFINE CLASS frm_proforme AS _frmbase OF "_frm_base.vcx"
OPTION1.Top = 5, ;
OPTION1.Value = 0, ;
OPTION2.AutoSize = .T., ;
OPTION2.Caption = "<22>terse", ;
OPTION2.Caption = "<22>terse", ;
OPTION2.FontCharSet = 238, ;
OPTION2.FontSize = 10, ;
OPTION2.ForeColor = 255,0,0, ;
@@ -6902,7 +7057,7 @@ DEFINE CLASS frm_proforme AS _frmbase OF "_frm_base.vcx"
OPTION2.Top = 5, ;
Option3.AutoSize = .T., ;
Option3.BackStyle = 0, ;
Option3.Caption = "Ne<4E>terse", ;
Option3.Caption = "Ne<4E>terse", ;
Option3.FontCharSet = 238, ;
Option3.FontSize = 10, ;
Option3.Height = 18, ;

View File

@@ -10199,7 +10199,8 @@ DEFINE CLASS import_nota AS frm_termin_renunt OF "_frm_child.vcx"
*!* Randul D, unic pe nota (doc_key gol, nr_doc 99999999): diferenta = baza documentelor
*!* care participa la pret - Suma(pret*cant) cu pretul incarcat. Cont dominant = contul de
*!* clasa 3 cu baza ABS maxima; fara clasa 3 -> clasa 2, cu contul fix 6588. Diferenta se
*!* scrie doar in lei. Antetul se mosteneste de la documentul principal.
*!* scrie doar in lei, fara TVA si fara cod de taxa SAFT. Antetul se mosteneste de la
*!* documentul principal.
Local lcSel, lnMinNrDoc, lnTotalLei, lnTotalVal, lnBazaParticipa
Local lcContDominant, lnBazaDominantaAbs, lcScd1, lnDiferentaLei, lnDiferentaVal, lcExplicatie
Local llGasitClasa3, loAntet
@@ -10310,7 +10311,7 @@ DEFINE CLASS import_nota AS frm_termin_renunt OF "_frm_child.vcx"
Replace partc With '', id_partc With 0, partd With '', id_partd With 0
Endif
Replace scd With lcScd1, scc With lcContDominant, suma With lnDiferentaLei, suma_val With 0, ;
explicatia With lcExplicatie, id_jtva_coloana With Null, ptva With 0, cu_tva With 0, ;
explicatia With lcExplicatie, id_jtva_coloana With Null, taxcode With 0, ptva With 0, cu_tva With 0, ;
in_valuta With 0, participa_valuta With .F., nume_val With '', id_valuta With 0, curs With 0
Select (lcSel)

View File

@@ -6628,6 +6628,33 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="pgfArticole.PAGE2.grdRulajeObinv.cvaloarecTVA.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE2.grdRulajeObinv.cvaloarevTVA.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE2.grdRulajeObinv.cvaloarevTVA.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cDenumireArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cDenumireArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cCodmatArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cCodmatArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cLotArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cLotArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cCantitateArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cCantitateArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cPretArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cPretArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cPretCuTvaArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cPretCuTvaArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cDiscountUnitarArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cDiscountUnitarArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cGestiuneArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cGestiuneArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cValutaArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cValutaArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cExplicatieArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cExplicatieArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE2.grdRulajeObinv.cvaloarevcTVA.cvaloarevcTVA" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="pgfArticole.PAGE2.grdRulajeObinv.cvaloarevcTVA.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Grid1" UniqueID="" Timestamp="" />
@@ -6720,6 +6747,8 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="Grid1.Column43.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Grid1.Column43.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Grid1.Column43._combobox1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Grid1.Column44.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Grid1.Column44.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Command1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Gridextra1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Command2" UniqueID="" Timestamp="" />
@@ -6762,6 +6791,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
*m: grid_focus_prima_coloana
*m: resize_grid1
*m: salveazaxml
*m: sincronizeaza_nnir
*m: updateexplicatiesaft
*m: updateexplicatiesaftrul
*m: valideaza_data
@@ -6771,17 +6801,21 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
*p: ccontrol
*p: cpaymentcode
*p: fel_compensare
*p: larearticolevanzari
*p: lavertizatexigibilizare
*p: leditare
*p: lmodificare
*p: lnotanoua
*p: lverificare
*p: lvizualizare
*p: nidvanzare
*p: nid_set
*p: nnnirvechi
*p: noldsuma && Valoarea la intrarea in campul "Suma"
*p: nprimadata
*p: nsuma && Total suma inregistrari
*p: ntaxcode
*p: ntipvanzare
*p: obackupxml
*p: oldvalue
*p: oset
@@ -6801,6 +6835,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
DoCreate = .T.
FontCharSet = 238
Height = 508
larearticolevanzari = .F.
lavertizatexigibilizare = .F.
leditare = .F.
lmodificare = .F.
@@ -6808,11 +6843,14 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
lverificare = .F.
lvizualizare = .F.
Name = "frm_modific2024"
nidvanzare = 0
nid_set = 0
nnnirvechi = 0
noldsuma = 0
nprimadata = 0
nsuma = 0
ntaxcode = 0
ntipvanzare = 0
obackupxml = NULL
oldvalue =
oset = NULL
@@ -7143,7 +7181,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
ADD OBJECT 'Grid1' AS grid WITH ;
Anchor = 10, ;
BackColor = 244,250,255, ;
ColumnCount = 43, ;
ColumnCount = 44, ;
DeleteMark = .F., ;
FontCharSet = 238, ;
FontSize = 10, ;
@@ -7185,7 +7223,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column2.Width = 71, ;
Column3.Alignment = 0, ;
Column3.BackColor = 244,250,255, ;
Column3.ColumnOrder = 15, ;
Column3.ColumnOrder = 16, ;
Column3.ControlSource = "fdoc", ;
Column3.FontCharSet = 238, ;
Column3.FontName = "Arial", ;
@@ -7215,7 +7253,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column5.Width = 53, ;
Column6.Alignment = 0, ;
Column6.BackColor = 244,250,255, ;
Column6.ColumnOrder = 7, ;
Column6.ColumnOrder = 8, ;
Column6.ControlSource = "partd", ;
Column6.FontCharSet = 238, ;
Column6.FontName = "Arial", ;
@@ -7225,7 +7263,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column6.Width = 114, ;
Column7.Alignment = 1, ;
Column7.BackColor = 244,250,255, ;
Column7.ColumnOrder = 10, ;
Column7.ColumnOrder = 11, ;
Column7.ControlSource = "scd", ;
Column7.FontCharSet = 238, ;
Column7.FontName = "Arial", ;
@@ -7235,7 +7273,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column7.Width = 57, ;
Column8.Alignment = 1, ;
Column8.BackColor = 244,250,255, ;
Column8.ColumnOrder = 12, ;
Column8.ColumnOrder = 13, ;
Column8.ControlSource = "scc", ;
Column8.FontCharSet = 238, ;
Column8.FontName = "Arial", ;
@@ -7245,7 +7283,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column8.Width = 62, ;
Column9.Alignment = 1, ;
Column9.BackColor = 244,250,255, ;
Column9.ColumnOrder = 14, ;
Column9.ColumnOrder = 15, ;
Column9.ControlSource = "suma", ;
Column9.DynamicForeColor = "IIF(SUMA>=0, RGB(0,0,0), RGB(255,0,0))", ;
Column9.FontCharSet = 238, ;
@@ -7258,7 +7296,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column9.Width = 93, ;
Column10.Alignment = 0, ;
Column10.BackColor = 244,250,255, ;
Column10.ColumnOrder = 8, ;
Column10.ColumnOrder = 9, ;
Column10.ControlSource = "partc", ;
Column10.FontCharSet = 238, ;
Column10.FontName = "Arial", ;
@@ -7268,7 +7306,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column10.Width = 100, ;
Column11.Alignment = 0, ;
Column11.BackColor = 244,250,255, ;
Column11.ColumnOrder = 9, ;
Column11.ColumnOrder = 10, ;
Column11.ControlSource = "explicatia", ;
Column11.FontCharSet = 238, ;
Column11.FontName = "Arial", ;
@@ -7277,7 +7315,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column11.ReadOnly = .F., ;
Column11.Width = 77, ;
Column12.BackColor = 244,250,255, ;
Column12.ColumnOrder = 37, ;
Column12.ColumnOrder = 38, ;
Column12.ControlSource = "cod", ;
Column12.FontCharSet = 238, ;
Column12.FontName = "Arial", ;
@@ -7286,7 +7324,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column12.ReadOnly = .T., ;
Column12.Width = 52, ;
Column13.BackColor = 244,250,255, ;
Column13.ColumnOrder = 16, ;
Column13.ColumnOrder = 17, ;
Column13.ControlSource = "pereched", ;
Column13.FontCharSet = 238, ;
Column13.FontName = "Arial", ;
@@ -7295,7 +7333,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column13.ReadOnly = .F., ;
Column13.Width = 106, ;
Column14.BackColor = 244,250,255, ;
Column14.ColumnOrder = 31, ;
Column14.ColumnOrder = 32, ;
Column14.ControlSource = "explicatia4", ;
Column14.FontCharSet = 238, ;
Column14.FontName = "Arial", ;
@@ -7304,7 +7342,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column14.ReadOnly = .F., ;
Column14.Width = 120, ;
Column15.BackColor = 244,250,255, ;
Column15.ColumnOrder = 24, ;
Column15.ColumnOrder = 25, ;
Column15.ControlSource = "nrord", ;
Column15.FontCharSet = 238, ;
Column15.FontName = "Arial", ;
@@ -7312,7 +7350,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column15.Name = "Column15", ;
Column15.ReadOnly = .F., ;
Column16.BackColor = 244,250,255, ;
Column16.ColumnOrder = 26, ;
Column16.ColumnOrder = 27, ;
Column16.ControlSource = "nresp", ;
Column16.FontCharSet = 238, ;
Column16.FontName = "Arial", ;
@@ -7322,7 +7360,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column16.Name = "Column16", ;
Column16.ReadOnly = .F., ;
Column17.BackColor = 244,250,255, ;
Column17.ColumnOrder = 27, ;
Column17.ColumnOrder = 28, ;
Column17.ControlSource = "dst_chlt", ;
Column17.FontCharSet = 238, ;
Column17.FontName = "Arial", ;
@@ -7332,7 +7370,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column17.Name = "Column17", ;
Column17.ReadOnly = .F., ;
Column18.BackColor = 244,250,255, ;
Column18.ColumnOrder = 32, ;
Column18.ColumnOrder = 33, ;
Column18.ControlSource = "explicatia5", ;
Column18.FontCharSet = 238, ;
Column18.FontName = "Arial", ;
@@ -7341,7 +7379,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column18.ReadOnly = .F., ;
Column18.Width = 119, ;
Column19.BackColor = 244,250,255, ;
Column19.ColumnOrder = 23, ;
Column19.ColumnOrder = 24, ;
Column19.ControlSource = "datascad", ;
Column19.FontCharSet = 238, ;
Column19.FontName = "Arial", ;
@@ -7351,7 +7389,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column19.Visible = .T., ;
Column19.Width = 87, ;
Column20.BackColor = 244,250,255, ;
Column20.ColumnOrder = 28, ;
Column20.ColumnOrder = 29, ;
Column20.ControlSource = "suma_val", ;
Column20.FontCharSet = 238, ;
Column20.FontName = "Arial", ;
@@ -7361,7 +7399,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column20.ReadOnly = .F., ;
Column20.Width = 89, ;
Column21.BackColor = 244,250,255, ;
Column21.ColumnOrder = 30, ;
Column21.ColumnOrder = 31, ;
Column21.ControlSource = "curs", ;
Column21.FontCharSet = 238, ;
Column21.FontName = "Arial", ;
@@ -7371,7 +7409,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column21.ReadOnly = .F., ;
Column21.Width = 72, ;
Column22.BackColor = 244,250,255, ;
Column22.ColumnOrder = 33, ;
Column22.ColumnOrder = 34, ;
Column22.ControlSource = "gestin", ;
Column22.FontCharSet = 238, ;
Column22.FontName = "Arial", ;
@@ -7380,7 +7418,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column22.ReadOnly = .F., ;
Column22.Width = 116, ;
Column23.BackColor = 244,250,255, ;
Column23.ColumnOrder = 11, ;
Column23.ColumnOrder = 12, ;
Column23.ControlSource = "ascd", ;
Column23.FontCharSet = 238, ;
Column23.FontName = "Arial", ;
@@ -7389,7 +7427,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column23.ReadOnly = .F., ;
Column23.Width = 46, ;
Column24.BackColor = 244,250,255, ;
Column24.ColumnOrder = 13, ;
Column24.ColumnOrder = 14, ;
Column24.ControlSource = "ascc", ;
Column24.FontCharSet = 238, ;
Column24.FontName = "Arial", ;
@@ -7398,7 +7436,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column24.ReadOnly = .F., ;
Column24.Width = 48, ;
Column25.BackColor = 244,250,255, ;
Column25.ColumnOrder = 38, ;
Column25.ColumnOrder = 39, ;
Column25.ControlSource = "id_set", ;
Column25.FontCharSet = 238, ;
Column25.FontName = "Arial", ;
@@ -7407,7 +7445,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column25.ReadOnly = .T., ;
Column25.Width = 71, ;
Column26.BackColor = 244,250,255, ;
Column26.ColumnOrder = 19, ;
Column26.ColumnOrder = 20, ;
Column26.ControlSource = "proc_tva", ;
Column26.FontCharSet = 238, ;
Column26.FontName = "Arial", ;
@@ -7416,7 +7454,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column26.ReadOnly = .T., ;
Column26.Width = 54, ;
Column27.BackColor = 244,250,255, ;
Column27.ColumnOrder = 17, ;
Column27.ColumnOrder = 18, ;
Column27.ControlSource = "perechec", ;
Column27.FontCharSet = 238, ;
Column27.FontName = "Arial", ;
@@ -7425,7 +7463,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column27.ReadOnly = .F., ;
Column27.Width = 104, ;
Column28.BackColor = 244,250,255, ;
Column28.ColumnOrder = 35, ;
Column28.ColumnOrder = 36, ;
Column28.ControlSource = "sectie", ;
Column28.FontCharSet = 238, ;
Column28.FontName = "Arial", ;
@@ -7434,7 +7472,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column28.ReadOnly = .F., ;
Column28.Width = 88, ;
Column29.BackColor = 244,250,255, ;
Column29.ColumnOrder = 29, ;
Column29.ColumnOrder = 30, ;
Column29.ControlSource = "nume_val", ;
Column29.FontCharSet = 238, ;
Column29.FontName = "Arial", ;
@@ -7443,7 +7481,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column29.ReadOnly = .F., ;
Column29.Width = 79, ;
Column30.BackColor = 244,250,255, ;
Column30.ColumnOrder = 39, ;
Column30.ColumnOrder = 40, ;
Column30.ControlSource = "id_partd", ;
Column30.FontCharSet = 238, ;
Column30.FontName = "Arial", ;
@@ -7452,7 +7490,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column30.ReadOnly = .T., ;
Column30.Width = 55, ;
Column31.BackColor = 244,250,255, ;
Column31.ColumnOrder = 40, ;
Column31.ColumnOrder = 41, ;
Column31.ControlSource = "id_partc", ;
Column31.FontCharSet = 238, ;
Column31.FontName = "Arial", ;
@@ -7461,7 +7499,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column31.ReadOnly = .T., ;
Column31.Width = 55, ;
Column32.BackColor = 244,250,255, ;
Column32.ColumnOrder = 34, ;
Column32.ColumnOrder = 35, ;
Column32.ControlSource = "gestout", ;
Column32.FontCharSet = 238, ;
Column32.FontName = "Arial", ;
@@ -7470,7 +7508,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column32.ReadOnly = .F., ;
Column32.Width = 92, ;
Column33.BackColor = 244,250,255, ;
Column33.ColumnOrder = 36, ;
Column33.ColumnOrder = 37, ;
Column33.ControlSource = "sucursala", ;
Column33.FontCharSet = 238, ;
Column33.FontName = "Arial", ;
@@ -7479,7 +7517,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column33.ReadOnly = .F., ;
Column33.Width = 121, ;
Column34.BackColor = 244,250,255, ;
Column34.ColumnOrder = 25, ;
Column34.ColumnOrder = 26, ;
Column34.ControlSource = "contract", ;
Column34.FontCharSet = 238, ;
Column34.FontName = "Arial", ;
@@ -7488,7 +7526,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column34.ReadOnly = .T., ;
Column34.Width = 65, ;
Column35.BackColor = 244,250,255, ;
Column35.ColumnOrder = 20, ;
Column35.ColumnOrder = 21, ;
Column35.ControlSource = "explicatie_tva", ;
Column35.FontCharSet = 238, ;
Column35.FontName = "Arial", ;
@@ -7497,7 +7535,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column35.ReadOnly = .F., ;
Column35.Width = 136, ;
Column36.BackColor = 244,250,255, ;
Column36.ColumnOrder = 18, ;
Column36.ColumnOrder = 19, ;
Column36.ControlSource = "cu_tva", ;
Column36.FontCharSet = 238, ;
Column36.FontName = "Arial", ;
@@ -7517,7 +7555,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column37.ReadOnly = .F., ;
Column37.Width = 58, ;
Column38.BackColor = 244,250,255, ;
Column38.ColumnOrder = 41, ;
Column38.ColumnOrder = 42, ;
Column38.ControlSource = "id_fact", ;
Column38.FontCharSet = 238, ;
Column38.FontName = "Arial", ;
@@ -7526,7 +7564,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column38.ReadOnly = .T., ;
Column38.Width = 94, ;
Column39.BackColor = 244,250,255, ;
Column39.ColumnOrder = 42, ;
Column39.ColumnOrder = 43, ;
Column39.ControlSource = "id_factd", ;
Column39.FontCharSet = 238, ;
Column39.FontName = "Arial", ;
@@ -7535,7 +7573,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column39.ReadOnly = .T., ;
Column39.Width = 75, ;
Column40.BackColor = 244,250,255, ;
Column40.ColumnOrder = 43, ;
Column40.ColumnOrder = 44, ;
Column40.ControlSource = "id_factc", ;
Column40.FontCharSet = 238, ;
Column40.FontName = "Arial", ;
@@ -7555,7 +7593,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column41.Width = 22, ;
Column42.BackColor = 244,250,255, ;
Column42.Bound = .F., ;
Column42.ColumnOrder = 21, ;
Column42.ColumnOrder = 22, ;
Column42.ControlSource = "Iif(Seek(tAct.taxcode,'saft_taxtable','taxcode'),saft_taxtable.taxname,'')", ;
Column42.CurrentControl = "_combobox1", ;
Column42.FontCharSet = 238, ;
@@ -7566,7 +7604,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column42.Width = 184, ;
Column43.BackColor = 244,250,255, ;
Column43.Bound = .F., ;
Column43.ColumnOrder = 22, ;
Column43.ColumnOrder = 23, ;
Column43.ControlSource = "Iif(Seek(tAct.paymentcode,'saft_mecanisme_plati','mcode'),saft_mecanisme_plati.paymentname,'')", ;
Column43.CurrentControl = "_combobox1", ;
Column43.FontCharSet = 238, ;
@@ -7574,7 +7612,17 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Column43.Name = "Column43", ;
Column43.ReadOnly = .F., ;
Column43.Sparse = .F., ;
Column43.Width = 146
Column43.Width = 146, ;
Column44.Alignment = 1, ;
Column44.BackColor = 244,250,255, ;
Column44.ColumnOrder = 7, ;
Column44.ControlSource = "nnir", ;
Column44.FontCharSet = 238, ;
Column44.FontName = "Arial", ;
Column44.FontSize = 10, ;
Column44.Name = "Column44", ;
Column44.ReadOnly = .F., ;
Column44.Width = 60
*< END OBJECT: BaseClass="grid" />
ADD OBJECT 'Grid1.cAles._CHECKBOX1' AS _checkbox WITH ;
@@ -8442,6 +8490,29 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
SelectedBackColor = 49,106,197
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'Grid1.Column44.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Nr. NIR", ;
FontCharSet = 238, ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1"
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'Grid1.Column44.Text1' AS textbox WITH ;
Alignment = 1, ;
BackColor = 244,250,255, ;
BorderStyle = 0, ;
FontCharSet = 238, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .F., ;
SelectedBackColor = 49,106,197
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'Grid1.Column5.Header5' AS header WITH ;
Alignment = 2, ;
Caption = "Nr.Doc.", ;
@@ -8592,6 +8663,7 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
Height = 142, ;
Left = 5, ;
Name = "pgfArticole", ;
PageCount = 3, ;
Top = 361, ;
Width = 764, ;
ZOrderSet = 0, ;
@@ -8600,7 +8672,10 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
PAGE1.Name = "PAGE1", ;
PAGE2.Caption = "Rulaje obiecte inventar in folosinta (8039)", ;
PAGE2.ForeColor = 0,128,64, ;
PAGE2.Name = "PAGE2"
PAGE2.Name = "PAGE2", ;
PAGE3.Caption = "Articole factura", ;
PAGE3.ForeColor = 128,0,128, ;
PAGE3.Name = "PAGE3"
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="pageframe" />
ADD OBJECT 'pgfArticole.PAGE1._grdfooter1' AS _grdfooter WITH ;
@@ -12179,6 +12254,374 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura' AS _grdrow WITH ;
Anchor = 15, ;
ColumnCount = 13, ;
DeleteMark = .F., ;
FontSize = 10, ;
GridLineColor = 128,128,128, ;
HeaderHeight = 35, ;
Height = 107, ;
Left = 0, ;
Name = "grdArticoleFactura", ;
ReadOnly = .T., ;
RecordSource = "tvd", ;
RowHeight = 19, ;
TabIndex = 4, ;
Tag = "RESIZABLE", ;
Top = 0, ;
Width = 759, ;
ZOrderSet = 1, ;
Column1.ControlSource = "tvd.denumire", ;
Column1.FontName = "Arial", ;
Column1.FontSize = 10, ;
Column1.Name = "cDenumireArt", ;
Column1.Width = 170, ;
Column2.ControlSource = "tvd.codmat", ;
Column2.FontName = "Arial", ;
Column2.FontSize = 10, ;
Column2.Name = "cCodmatArt", ;
Column2.Width = 90, ;
Column3.ControlSource = "tvd.serie", ;
Column3.FontName = "Arial", ;
Column3.FontSize = 10, ;
Column3.Name = "cSerieArt", ;
Column3.Width = 70, ;
Column4.ControlSource = "tvd.lot", ;
Column4.FontName = "Arial", ;
Column4.FontSize = 10, ;
Column4.Name = "cLotArt", ;
Column4.Width = 60, ;
Column5.ControlSource = "tvd.cantitate", ;
Column5.FontName = "Arial", ;
Column5.FontSize = 10, ;
Column5.Format = "R", ;
Column5.InputMask = (get_mask(12,gnPCANT)), ;
Column5.Name = "cCantitateArt", ;
Column5.Width = 70, ;
Column6.ControlSource = "tvd.pret", ;
Column6.FontName = "Arial", ;
Column6.FontSize = 10, ;
Column6.Format = "R", ;
Column6.InputMask = (get_mask(12,gnPPRET)), ;
Column6.Name = "cPretArt", ;
Column6.Width = 70, ;
Column7.ControlSource = "tvd.pret_cu_tva", ;
Column7.FontName = "Arial", ;
Column7.FontSize = 10, ;
Column7.Format = "R", ;
Column7.InputMask = (get_mask(12,gnPPRET)), ;
Column7.Name = "cPretCuTvaArt", ;
Column7.Width = 80, ;
Column8.ControlSource = "tvd.proc_tvav", ;
Column8.FontName = "Arial", ;
Column8.FontSize = 10, ;
Column8.Format = "R", ;
Column8.InputMask = "9.99", ;
Column8.Name = "cProcTvavArt", ;
Column8.Width = 55, ;
Column9.ControlSource = "tvd.discount_unitar", ;
Column9.FontName = "Arial", ;
Column9.FontSize = 10, ;
Column9.Format = "R", ;
Column9.InputMask = (get_mask(12,gnPPRET)), ;
Column9.Name = "cDiscountUnitarArt", ;
Column9.Width = 90, ;
Column10.ControlSource = "tvd.nume_gestiune", ;
Column10.FontName = "Arial", ;
Column10.FontSize = 10, ;
Column10.Name = "cGestiuneArt", ;
Column10.Width = 90, ;
Column11.ControlSource = "tvd.nume_val", ;
Column11.FontName = "Arial", ;
Column11.FontSize = 10, ;
Column11.Name = "cValutaArt", ;
Column11.Width = 60, ;
Column12.ControlSource = "tvd.explicatie", ;
Column12.FontName = "Arial", ;
Column12.FontSize = 10, ;
Column12.Name = "cExplicatieArt", ;
Column12.Width = 150, ;
Column13.ControlSource = "tvd.taxcode", ;
Column13.FontName = "Arial", ;
Column13.FontSize = 10, ;
Column13.Name = "cTaxcodeArt", ;
Column13.Width = 60
*< END OBJECT: ClassLib="_grd_base.vcx" BaseClass="grid" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cCantitateArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Cantitate", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cCantitateArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cCodmatArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Cod material", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cCodmatArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cDenumireArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Articol", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cDenumireArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cDiscountUnitarArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Discount unitar", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cDiscountUnitarArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cExplicatieArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Explicatie", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cExplicatieArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cGestiuneArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Gestiune", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cGestiuneArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cLotArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Lot", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cLotArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cPretArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Pret", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cPretArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cPretCuTvaArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Pret cu TVA", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cPretCuTvaArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "TVA %", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Serie", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Taxcode", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cValutaArt.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Valuta", ;
FontName = "Arial", ;
FontSize = 10, ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura.cValutaArt.Text1' AS textbox WITH ;
BackColor = 225,225,225, ;
BorderStyle = 0, ;
FontName = "Arial", ;
FontSize = 10, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T., ;
SelectedBackColor = 100,185,255
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT 'txtSuma' AS _textbox WITH ;
Alignment = 3, ;
Anchor = 8, ;
@@ -13027,13 +13470,16 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE do_modifica_explicatie_tva
LOCAL lnCotaFiltru
If tact.cu_tva = 1
*!* modificare ROACONT v 2.4.4
*!* filtreaza explicatiile dupa cota TVA a liniei curente; proc_tva e in forma 1.19, cota 0/gol = fara filtru
lnCotaFiltru = Round((Nvl(tact.proc_tva,0) - 1) * 100, 2)
If TYPE('tact.tipnota') = 'N' AND tact.tipnota = 1
*!* explicatii TVA exigibile din JC ( 1 ), JV ( 3 ) sau toate ( 5 )
locauta = caut_explicatie_tva(Nvl(tact.id_jtva_coloana,-1),,,iif(tact.scc=[4428],1,iif(tact.scd=[4428],3,5)))
locauta = caut_explicatie_tva(Nvl(tact.id_jtva_coloana,-1),,,iif(tact.scc=[4428],1,iif(tact.scd=[4428],3,5)),lnCotaFiltru)
Else
locauta = caut_explicatie_tva(Nvl(tact.id_jtva_coloana,-1))
locauta = caut_explicatie_tva(Nvl(tact.id_jtva_coloana,-1),,,,lnCotaFiltru)
Endif
*!* locauta = caut_explicatie_tva(Nvl(tact.id_jtva_coloana,-1))
*!* modificare ROACONT v 2.4.4 ^
@@ -13613,6 +14059,9 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
This.grid1.Anchor = 11
This.but_renunt1.Anchor = 8
If This.nid_set = 90101
This.grid1.Column44.ReadOnly = .T.
Endif
ENDPROC
PROCEDURE Load
@@ -13623,6 +14072,16 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
If !Used('saft_mecanisme_plati')
update_saft_mecanisme_plati()
ENDIF
*!* cursorul tvd, gol - din functia comuna daca ofacturare_editare.prg e incarcat
If !Used('tvd')
IF "OFACTURARE_EDITARE" $ Upper(Set("Procedure"))
CreeazaCursorTvdGol()
ELSE
*!* structura se repeta: in ROACONT/ROAGEST functia comuna nu e incarcata
CREATE CURSOR tvd (id_vanzare I, id_vanzare_det I, id_articol I, cantitate N(12,3), pret N(14,4), pret_cu_tva N(14,4), proc_tvav N(6,4), discount_unitar N(14,4), id_gestiune I, cont C(20), id_valuta I, id_jtva_coloana I, serie C(20), explicatie C(60), taxcode I, lot C(20), sters I, denumire C(100), codmat C(30), nume_gestiune C(60), nume_val C(20))
ENDIF
ENDIF
ENDPROC
PROCEDURE Resize
@@ -13683,6 +14142,19 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
this.gridextra1.setup()
LOCAL lcPrefFile, lcPrefFileContents, lcKey, lcPrefs
LOCAL ARRAY laNnirPrefs(1)
lcPrefFile = This.gridextra1.GetUserApplicationDataPath() + This.gridextra1.GridPreferenceFile
lcPrefFileContents = ""
IF FILE(m.lcPrefFile)
lcPrefFileContents = FILETOSTR(m.lcPrefFile)
ENDIF
lcKey = SYS(1272, This.grid1) + "("
lcPrefs = STREXTRACT(m.lcPrefFileContents, m.lcKey, ")", 1, 1)
*!* pozitioneaza coloana la prima deschidere, cat timp preferintele salvate nu o acopera
IF EMPTY(m.lcPrefs) OR ALINES(laNnirPrefs, m.lcPrefs, 7, ",") < This.grid1.ColumnCount * 2
This.grid1.Column44.ColumnOrder = 7
ENDIF
this.grid1.SetAll("dynamicbackcolor", "IIF(ALES, RGB(255,255,225), RGB(255,255,255))", "Column")
This.CalculeazaTotal()
*!* 24.05.2011 ^
@@ -13697,6 +14169,27 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
This.Grid1.HeaderHeight = 37
this.pgfArticole.page1.grdRulaje.HeaderHeight = 37
this.pgfArticole.page2.grdRulajeObinv.HeaderHeight = 37
* pagina de articole factura (VANZARI/VANZARI_DETALII) - apare doar cand ofacturare_editare.prg
* e incarcat (doar ROAFACTURARE - ROACONT/ROAGEST nu-l inregistreaza) si documentul are rand in vanzari
This.lAreArticoleVanzari = .F.
This.nIdVanzare = 0
This.nTipVanzare = 0
IF "OFACTURARE_EDITARE" $ Upper(Set("Procedure")) AND Reccount('tact') > 0
IncarcaVanzareDinNota('tact')
IF Reccount('tvanz') = 1
This.lAreArticoleVanzari = .T.
This.nIdVanzare = tvanz.id_vanzare
This.nTipVanzare = tvanz.tip
ENDIF
ENDIF
IF This.lAreArticoleVanzari
IncarcaArticoleFactura(This.nIdVanzare)
This.pgfArticole.PageCount = 3
ELSE
This.pgfArticole.PageCount = 2
ENDIF
This.grid1.column42.visible = m.gl406 && saft taxa
This.grid1.column43.visible = m.gl406 && saft plata
@@ -13717,6 +14210,37 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
ENDPROC
PROCEDURE sincronizeaza_nnir
*!* propaga NNIR-ul modificat pe toate liniile notei si pe rulajele asociate
LPARAMETERS tnNnirVechi, tnNnirNou
LOCAL lcSelect, lnRecno
IF NVL(m.tnNnirVechi, 0) = NVL(m.tnNnirNou, 0)
RETURN
ENDIF
lcSelect = SELECT()
lnRecno = RECNO('tact')
UPDATE tact SET nnir = m.tnNnirNou WHERE NVL(nnir, 0) = m.tnNnirVechi
IF USED('trul')
UPDATE trul SET nnir = m.tnNnirNou WHERE NVL(nnir, 0) = m.tnNnirVechi
IF _TALLY > 0
Thisform.pgfArticole.page1.grdRulaje.Refresh()
ENDIF
ENDIF
IF USED('trul_obinv')
UPDATE trul_obinv SET nnir = m.tnNnirNou WHERE NVL(nnir, 0) = m.tnNnirVechi
IF _TALLY > 0
Thisform.pgfArticole.page2.grdRulajeObinv.Refresh()
ENDIF
ENDIF
SELECT tact
IF BETWEEN(m.lnRecno, 1, RECCOUNT('tact'))
GO m.lnRecno
ELSE
GO TOP
ENDIF
SELECT (m.lcSelect)
ENDPROC
PROCEDURE updateexplicatiesaft
* Daca nu este activata SAFT 406 nu fac nimic
IF !m.gl406
@@ -14201,6 +14725,10 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
.Column35.ReadOnly = .T. && cod
.Column25.ReadOnly = .T. && id_set
ENDWITH
*!* pastreaza blocarea NNIR pentru notele de inventar (id_set = 90101)
IF Thisform.nid_set = 90101
This.Column44.ReadOnly = .T.
ENDIF
*!* 10.08.2011 ^
*!* pot selecta inregistrari din alte sucursale pentru operatiile de copiere, adaugare care
This.cAles.ReadOnly = .F.
@@ -14674,6 +15202,19 @@ DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"
thisform.cPaymentCode = ALLTRIM(tAct.paymentcode)
ENDPROC
PROCEDURE Grid1.Column44.Text1.LostFocus
Local lnNnirNou, lnNnirVechi
lnNnirVechi = thisform.nnnirvechi
lnNnirNou = NVL(tAct.nnir, 0)
Thisform.sincronizeaza_nnir(m.lnNnirVechi, m.lnNnirNou)
Thisform.nnnirvechi = m.lnNnirNou
Thisform.Grid1.Refresh()
ENDPROC
PROCEDURE Grid1.Column44.Text1.When
Thisform.nnnirvechi = NVL(tAct.nnir, 0)
ENDPROC
PROCEDURE Grid1.Column6.Text1.InteractiveChange
ADDPROPERTY(this, 'lInteractiveChange')
LOCAL lnIdPart

View File

@@ -25,7 +25,7 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx"
*<PropValue>
ccursor = ccrsbnr
clink = https://www.bnr.ro/nbrfxrates.xml
clink = https://curs.bnr.ro/nbrfxrates.xml
ctempfile = C:\temp\temp.xml
ddata = {}
Height = 17

View File

@@ -3063,6 +3063,31 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
*< OBJECTDATA: ObjPath="_grdbase1.cDataOraV.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cUtilV.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cUtilV.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataOravAnaf.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataOravAnaf.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cTvaIncasare.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cTvaIncasare.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cTvaIncasare._checkbox1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cSplitTva.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cSplitTva.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cSplitTva._checkbox1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cInactiv.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cInactiv.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cInactiv._checkbox1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInceputScpTva.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInceputScpTva.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataSfarsitScpTva.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataSfarsitScpTva.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataAnulImpScpTva.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataAnulImpScpTva.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInceputTvaInc.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInceputTvaInc.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataSfarsitTvaInc.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataSfarsitTvaInc.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInactivare.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataInactivare.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataReactivare.Header1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="_grdbase1.cDataReactivare.Text1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Gridextra1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="lblInfo" UniqueID="" Timestamp="" />
@@ -3112,7 +3137,7 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
ADD OBJECT '_grdbase1' AS _grdbase WITH ;
Anchor = 15, ;
ColumnCount = 16, ;
ColumnCount = 27, ;
DeleteMark = .F., ;
HeaderHeight = 32, ;
Height = 190, ;
@@ -3157,19 +3182,19 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Column6.ControlSource = "codpostal", ;
Column6.Name = "cCodPostal", ;
Column6.ReadOnly = .T., ;
Column6.Visible = .T., ;
Column6.Visible = .F., ;
Column6.Width = 75, ;
Column7.ColumnOrder = 11, ;
Column7.ControlSource = "telefon", ;
Column7.Name = "cTelefon", ;
Column7.ReadOnly = .T., ;
Column7.Visible = .T., ;
Column7.Visible = .F., ;
Column7.Width = 75, ;
Column8.ColumnOrder = 12, ;
Column8.ControlSource = "fax", ;
Column8.Name = "cFax", ;
Column8.ReadOnly = .T., ;
Column8.Visible = .T., ;
Column8.Visible = .F., ;
Column8.Width = 75, ;
Column9.ColumnOrder = 6, ;
Column9.ControlSource = "platitortvavies", ;
@@ -3177,7 +3202,7 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Column9.Name = "cPlatitorTVAVies", ;
Column9.ReadOnly = .T., ;
Column9.Sparse = .F., ;
Column9.Visible = .T., ;
Column9.Visible = .F., ;
Column9.Width = 54, ;
Column10.ColumnOrder = 5, ;
Column10.ControlSource = "datatvamfin", ;
@@ -3210,7 +3235,57 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Column16.ControlSource = "utilv", ;
Column16.Name = "cUtilV", ;
Column16.ReadOnly = .T., ;
Column16.Width = 114
Column16.Width = 114, ;
Column17.ControlSource = "dataorav_anaf", ;
Column17.Name = "cDataOravAnaf", ;
Column17.ReadOnly = .T., ;
Column17.Width = 85, ;
Column18.ControlSource = "tvaincasare", ;
Column18.CurrentControl = "_checkbox1", ;
Column18.Name = "cTvaIncasare", ;
Column18.ReadOnly = .T., ;
Column18.Sparse = .F., ;
Column18.Width = 54, ;
Column19.ControlSource = "splittva", ;
Column19.CurrentControl = "_checkbox1", ;
Column19.Name = "cSplitTva", ;
Column19.ReadOnly = .T., ;
Column19.Sparse = .F., ;
Column19.Width = 54, ;
Column20.ControlSource = "inactiv", ;
Column20.CurrentControl = "_checkbox1", ;
Column20.Name = "cInactiv", ;
Column20.ReadOnly = .T., ;
Column20.Sparse = .F., ;
Column20.Width = 54, ;
Column21.ControlSource = "data_inceput_scptva", ;
Column21.Name = "cDataInceputScpTva", ;
Column21.ReadOnly = .T., ;
Column21.Width = 85, ;
Column22.ControlSource = "data_sfarsit_scptva", ;
Column22.Name = "cDataSfarsitScpTva", ;
Column22.ReadOnly = .T., ;
Column22.Width = 85, ;
Column23.ControlSource = "data_anul_imp_scptva", ;
Column23.Name = "cDataAnulImpScpTva", ;
Column23.ReadOnly = .T., ;
Column23.Width = 85, ;
Column24.ControlSource = "data_inceput_tvainc", ;
Column24.Name = "cDataInceputTvaInc", ;
Column24.ReadOnly = .T., ;
Column24.Width = 85, ;
Column25.ControlSource = "data_sfarsit_tvainc", ;
Column25.Name = "cDataSfarsitTvaInc", ;
Column25.ReadOnly = .T., ;
Column25.Width = 85, ;
Column26.ControlSource = "data_inactivare", ;
Column26.Name = "cDataInactivare", ;
Column26.ReadOnly = .T., ;
Column26.Width = 85, ;
Column27.ControlSource = "data_reactivare", ;
Column27.Name = "cDataReactivare", ;
Column27.ReadOnly = .T., ;
Column27.Width = 85
*< END OBJECT: ClassLib="_grd_base.vcx" BaseClass="grid" />
ADD OBJECT '_grdbase1.cAdresa.Header1' AS header WITH ;
@@ -3261,6 +3336,70 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Visible = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataAnulImpScpTva.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Anulare scutire TVA", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataAnulImpScpTva.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataInactivare.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Data inactivare", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataInactivare.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataInceputScpTva.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Inceput scutire TVA", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataInceputScpTva.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataInceputTvaInc.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Inceput TVA incasare", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataInceputTvaInc.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataOra.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Creat la", ;
@@ -3289,6 +3428,69 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Name = "Text1"
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataOravAnaf.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Data ANAF", ;
Name = "Header1"
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataOravAnaf.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataReactivare.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Data reactivare", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataReactivare.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataSfarsitScpTva.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Sfarsit scutire TVA", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataSfarsitScpTva.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataSfarsitTvaInc.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Sfarsit TVA incasare", ;
Name = "Header1", ;
WordWrap = .T.
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cDataSfarsitTvaInc.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1", ;
ReadOnly = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cDataTVAMfin.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Data TVA MFIN", ;
@@ -3337,6 +3539,29 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Visible = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cInactiv._checkbox1' AS _checkbox WITH ;
Alignment = 2, ;
Caption = "", ;
Left = 19, ;
Name = "_checkbox1", ;
ReadOnly = .T., ;
Top = 96
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT '_grdbase1.cInactiv.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Inactiv", ;
Name = "Header1"
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cInactiv.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1"
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cJudet.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Judet", ;
@@ -3418,6 +3643,29 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Visible = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cSplitTva._checkbox1' AS _checkbox WITH ;
Alignment = 2, ;
Caption = "", ;
Left = 19, ;
Name = "_checkbox1", ;
ReadOnly = .T., ;
Top = 120
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT '_grdbase1.cSplitTva.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Split TVA", ;
Name = "Header1"
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cSplitTva.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1"
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cStare.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Stare", ;
@@ -3448,6 +3696,29 @@ DEFINE CLASS frm_verificare_parteneri_istoric AS _frmbase OF "_frm_base.vcx"
Visible = .T.
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cTvaIncasare._checkbox1' AS _checkbox WITH ;
Alignment = 2, ;
Caption = "", ;
Left = 19, ;
Name = "_checkbox1", ;
ReadOnly = .T., ;
Top = 144
*< END OBJECT: ClassLib="_baza.vcx" BaseClass="checkbox" />
ADD OBJECT '_grdbase1.cTvaIncasare.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "TVA incasare", ;
Name = "Header1"
*< END OBJECT: BaseClass="header" />
ADD OBJECT '_grdbase1.cTvaIncasare.Text1' AS textbox WITH ;
BackColor = 255,255,255, ;
BorderStyle = 0, ;
ForeColor = 0,0,0, ;
Margin = 0, ;
Name = "Text1"
*< END OBJECT: BaseClass="textbox" />
ADD OBJECT '_grdbase1.cUtil.Header1' AS header WITH ;
Alignment = 2, ;
Caption = "Creat de", ;

View File

@@ -0,0 +1,17 @@
# Capcana: coloana noua intr-un grid existent ajunge la coada (preferinte GridExtras)
`GridExtras` (`COMUN\utile\GridExtras\gridextras.vc2:1051`, `restoregridpreferences` /
`savegridpreferences`) salveaza **per utilizator** latimea si ordinea coloanelor fiecarui grid,
in `%APPDATA%\...\gridprefs.tmp`, sub cheia `SYS(1272, grid)` (ex. `frm_modific2024.grid1`).
Salvarea se face live, la `columnmoved`/`columnresize`, nu la iesirea din formular.
Consecinta: `ColumnOrder` setat in clasa e neutralizat la runtime pentru orice utilizator care a
deschis deja formularul inainte de livrare - `gridextra1.setup()` restaureaza ordinea veche, iar
coloana nou adaugata (care nu exista in preferinte) ajunge ultima.
Solutie: repozitionare la runtime, in `Show()`, **dupa** `gridextra1.setup()`, aplicata o singura
data - cat timp preferintele salvate nu acopera toate coloanele (implementat pe
`frm_modific2024`, `COMUN\clase\omodificari.vc2`, coloana `nnir`).
La testare: pozitia coloanei nu e o asertiune stabila intre masini. Se asertesteaza tare
`ControlSource` si `ReadOnly`; `ColumnOrder` ramane informativ.

View File

@@ -5,6 +5,16 @@ Actualizarea automata a aplicatiilor si a bazei ruleaza din jobul `CONTAFIN_ORAC
**UpdateScripts** (umple `UPD_DATABASE`) -> **UpdateDatabaseSqlPlus** (aplica scripturile pe scheme).
O etapa esuata le opreste pe toate urmatoarele.
## Scriptul de diagnostic
`COMUN\utile\diag_actualizare.ps1 -Alias <ALIAS_TNS>` ruleaza tot lantul de mai jos si scoate un
verdict (unde a ramas rularea, care e scriptul candidat, unde e eroarea). Strict read-only; `-Disc`
adauga verificarea spatiului pe discurile serverului (singura parte care scrie ceva — un `.ps1`
temporar in `DMPDIR`). Foloseste-l intai; sectiunile de mai jos explica ce citeste si de ce.
Cand cauza e spatiul (tablespace plin, audit/loguri Oracle care umplu discul), continua cu
`depanare-spatiu-oracle.md` si `COMUN\utile\diag_spatiu.ps1`.
## Unde te uiti, in ordine
| Ce | Unde |
@@ -52,6 +62,31 @@ Fisierul se poate citi si fara acces la desktopul serverului, prin `UTL_FILE` pe
`DMPDIR` (`fopen(...,'R',32767)` + `get_line` in bucla; tine ultimele N linii intr-un tablou —
partea utila e la sfarsit).
### Caz: nu orice esec de script e o problema de SQL (SIGMA, 03.08.2026)
`ff_2026_07_29_02_COMUN_TVA11.SQL` a picat pe `MARCU` cu `ORA-01653: unable to extend table
SYS.INFO ... in tablespace SYSTEM` (din `SYS.PINFO`/`SYS.AUTH_PACK`, recursiv). Tablespace-ul
`SYSTEM` era plin: autoextensibil, dar cu `maxbytes` atins la 600 MB, ~2 MB liberi. **Orice**
script ar fi picat identic — `AUTH_PACK` scrie in `SYS.INFO` la fiecare conectare. Cand eroarea nu
priveste obiectele scriptului, verifica intai spatiul.
Ce a contat, pentru data viitoare:
- **`maxbytes` mic nu e o limita XE.** Cele 11 GB ale XE sunt pe *date utilizator*; un plafon mic pe
`SYSTEM.DBF` e o setare de instalare. Se ridica din `contafin_oracle` (are `ALTER DATABASE`):
`alter database datafile '<cale>\SYSTEM.DBF' autoextend on next 50M maxsize 2000M;`
- **Spatiul pe discul serverului se verifica fara RDP**, cu `sys.ExecuteScriptOS` (vezi mai jos) —
`Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3"`, iesire in `DMPDIR`, citita cu `UTL_FILE`.
Job asincron, dar raspunde in cateva secunde.
- **`SYS.INFO` e tabel ROA, nu obiect de dictionar** (log de login scris de `PINFO`, ~7 randuri per
conectare, +16-17k randuri/luna, nimic din baza nu-l citeste). Se poate goli, **dar numai ca
`SYSDBA`**: privilegiile `ANY` (`DROP ANY TABLE`, `DELETE ANY TABLE`) nu se aplica pe obiectele
din schema `SYS` cat timp `O7_DICTIONARY_ACCESSIBILITY=FALSE`, deci din `contafin_oracle` iese
`ORA-01031`.
- Restul lui `SYSTEM` era dictionar Oracle (`IDL_UB1$`, `SOURCE$`, `IDL_UB2$`, `ARGUMENT$` ~207 MB) —
de neatins fara export/import. `AUD$`/`FGA_LOG$` erau goale. Recyclebin-ul si bloat-ul de scheduler
stateau in `ROA`/`SYSAUX`, nu in `SYSTEM`.
## Descarcarea (UpdateApp)
Cu `server_info.POWERSHELLDOWNLOAD = '1'`, `PACK_UTILS.DownloadFileOS` scrie un `.ps1` cu `curl` in
@@ -98,6 +133,31 @@ end;
/
```
## Emailuri: log de actualizare vs buletin informativ
Sunt **doua emailuri diferite, trimise de doua masini diferite** — se confunda usor.
| | Log de actualizare | Buletin informativ |
|---|---|---|
| Cine trimite | baza de date, `PACK_UPDATE.EmailLog` (`UTL_SMTP` direct catre `EMAIL_SMTP:EMAIL_PORT`, `AUTH LOGIN`) | **serverul de update** (ASP.NET); baza doar face un GET pe `optiuni.UPD_URL_BULETININF` (cu `|CUSTOMERID|`) prin `PACK_UTILS.URL2Clob`, din `UpdateApp` |
| Destinatari | `server_info.EMAIL_TO` + `EMAIL_CC` | configurati pe serverul de update, **nu** in `server_info` (ex. `office@romfast.ro`) |
| Subiect / continut | `Actualizare ROA dd.mm.yyyy hh24:mi:ss`; liniile din `UPD_LOG`, text simplu separat cu TAB | compus de serverul de update |
| In `UPD_LOG` | erorile SMTP: `EROARE: utl_smpt ERROR CODE ...` | raspunsul HTTP, verbatim (ex. `ERR-1-BULETIN INFORMATIV NU S-A TRIMIS. MOTIVUL: Error: 1429`) |
Detalii care conteaza la depanare:
- **`EMAIL_CC` nu produce un antet `Cc:`.** Codul il concateneaza cu virgula la `EMAIL_TO` si trimite
`RCPT TO` pentru toti; antetul e un singur `To: <toti>`. Deci un email primit *in Cc* nu vine de la
`EmailLog`.
- **`EMAIL_FROM` e per server de client** (`roaupdate-<client>@romfast.ro`) si difera de contul
autentificat, care e acelasi peste tot (`EMAIL_USERNAME = roaupdate@romfast.ro`). Expeditorul e
singurul indiciu din email despre serverul care l-a trimis. Daca `EMAIL_FROM` lipseste, se compune
din `UTL_INADDR.get_host_name`.
- **Un buletin esuat nu opreste nimic**: raspunsul `ERR-1-...` e text normal, se scrie in `UPD_LOG` si
actualizarea merge mai departe. Doar exceptiile HTTP ajung ca `ERR: <url> ...`.
- **Un SMTP picat, in schimb, opreste tot** — `EmailLog` ridica `ORA-20000` care mascheaza eroarea
reala (vezi „Capcane" mai sus). E singurul loc din lantul de email care are voie sa arunce.
## Configurare (CONTAFIN_ORACLE)
- `server_info`: `POWERSHELLDOWNLOAD`, `POWERSHELLPATH`, `POWERSHELLTIMEOUT`, `CURLPATH`,
@@ -110,7 +170,7 @@ end;
Tunel SSH pe 1521 + alias TNS pe `127.0.0.1` in `D:\ROA\instantclient_19_18\tnsnames.ora`
(ex. `ROA_ROMCONSTRUCT`), utilizator `contafin_oracle`. Vezi `oracle_export.md` pentru client si
capcana de encoding; parolele stau in `docs/local/` al proiectului, neversionat.
capcana de encoding; parolele stau in `COMUN\docs\local\oracle.md` (neversionat in git).
Serverele de client pot fi Oracle 10g: unele coloane din `dba_scheduler_*` lipsesc
(`dba_scheduler_running_jobs.last_start_date`) — foloseste `dba_scheduler_job_run_details`.

View File

@@ -0,0 +1,122 @@
# Depanare spatiu Oracle la clienti
```powershell
powershell -File COMUN\utile\diag_spatiu.ps1 -Alias <ALIAS_TNS> [-Disc] [-SysPassword <parola>] [-Top 30]
```
Strict read-only in afara lui `-Disc` (singura parte care scrie: un `.ps1` temporar in `DMPDIR`,
lansat cu `sys.ExecuteScriptOS` si sters la final). Actiunile de curatare sunt doar **sugerate**,
niciodata executate. 8 sectiuni: conexiune/versiune (CDB-PDB), tablespace + top segmente, audit,
alert log/trace/ADR, archivelog/FRA, disc server, alti mancatori de spatiu, verdict.
Pentru actualizarea blocata de spatiu, punctul de plecare e `depanare-pack-update.md`.
## Jobul automat `DIAGSPATIU_ZILNIC` (SVN r17969)
Echivalentul in baza al scriptului de mai sus, rulat zilnic la 06:00 de la fiecare client:
`co_2026_08_03_02` (tabela `DIAG_SPATIU_LOG`, istoric purjat la 90 zile), `co_2026_08_03_03`
(`PACK_DIAG_SPATIU`), `co_2026_08_03_04` (jobul), `sys_2026_08_03_05` (granturi). Praguri identice
cu `diag_spatiu.ps1`; **email doar la prag depasit**, tacere completa altfel. Sursa de referinta:
`COMUN\docs\PACK_DIAG_SPATIU.pck`.
Sectiunile informative (recyclebin, UNDO, TEMP, istoric statistici/scheduler, top segmente, audit
SYS, disc) se scriu doar cand exista deja o alerta — dau context, nu alerteaza singure.
`co_2026_08_06_08_DIAG_SPATIU_PACK` + `sys_2026_08_06_07_DIAG_SPATIU_GRANT3` (06.08.2026) scriu la
top segmente si **tabela/coloana din care provine segmentul** (`DetaliuSegment`: `DBA_LOBS`,
`DBA_LOB_PARTITIONS`, `DBA_INDEXES`; segmentele temporare se marcheaza ca atare) — fara asta un
`SYS_LOB0000630560C00017$$` de 4 GB in email nu spune nimic, iar serverul clientului nu e accesibil
direct. Atentie: pentru `LOB PARTITION`, `dba_segments.segment_name` e `lob_name`, nu
`lob_partition_name`.
Emailurile ajung pe `marius.mutu@romfast.ro`, cate un expeditor per client
(`roaupdate_<client>@romfast.ro`); citirea lor: `email-thunderbird.md`.
`co_2026_08_06_01_DIAG_SPATIU_PACK` (06.08.2026) corecteaza doua lucruri vazute pe primele rulari:
- **pragul absolut (2048 MB) nu se mai aplica tablespace-urilor al caror maxim e sub el** — orice
`UNDOTBS`/`SYSTEM` plafonat la 5002048 MB alerta zilnic, prin definitie; acolo ramane doar garda
relativa de 15%.
- **emailul contine tot logul rularii** (alertele intai, apoi toate randurile din `DIAG_SPATIU_LOG`,
cu `!` pe cele peste prag, sortate pe sectiune si valoare descrescator), nu doar un pointer catre
tabela. Corpul e plafonat la 30000 de caractere (`EmailDiagSpatiu` lucreaza pe `VARCHAR2(32000)`),
cu marcaj `... restul in DIAG_SPATIU_LOG` la depasire.
## Mecanisme reutilizabile (din investigatia pentru job)
- **`CONTAFIN_ORACLE.SERVER_INFO`** tine parolele `PASSWORD_SYS`/`PASSWORD_CONTAFIN_ORACLE`
(zip+base64, nu criptare), caile `SQLPLUSPATH`/`POWERSHELLPATH`/`DMPDIR`, cheile `EMAIL_*` si
cache-ul `VERSIUNE_<SCHEMA>`. Parola se citeste cu `PACK_UPDATE.GetSchemaParola('<SCHEMA>')`
(decodeaza doar pentru `SYS` si `CONTAFIN_ORACLE`; pentru schemele de firma intoarce
`'ROMFASTSOFT'` hardcodat).
- **Rulare ca `SYS` din PL/SQL**: scrii un `.sql` in `DMPDIR` cu `connect sys/<parola>@ROA as
sysdba` + `spool`, il lansezi cu `sys.UpdateSQLPLUS` si astepti fisierul de iesire; pentru OS,
`sys.ExecuteScriptOS` (PowerShell). Ambele sunt asincrone (job `dbms_scheduler` de tip
`executable`, auto-drop) — mecanismul folosit si de `PACK_UPDATE.UpdateDatabaseSqlPlus`. Fisierele
temporare au nume proprii, ca sa nu se bata cu `script_master.sql` al actualizarii.
- **`PACK_UPDATE.EmailLog` nu e reutilizabila** pentru alt continut: subiectul e hardcodat
("Actualizare ROA ...") si corpul vine din `UPD_LOG`. Pentru alte alerte, bloc `UTL_SMTP` propriu
care citeste aceleasi chei `EMAIL_*`.
- **Scripturile `sys_*`** se aplica automat, ca orice `co_`/`ff_`: prefixul e recunoscut in
`PACK_UPDATE.UpdateSchema*`, schema `SYS` se actualizeaza **prima**, iar `UpdateVersiune` isi
scrie randul in `CONTAFIN_ORACLE.versiune` (schema `SYS` n-are tabela proprie). Deci un `sys_`
livrat in aceeasi zi ruleaza inaintea scripturilor `co_` care depind de el.
## Ce umple spatiul, in ordinea frecventei
- **Tablespace cu `maxbytes` atins** — nu "disc plin", ci un plafon pus la instalare. Pe XE limita
de 11/12 GB e pe *date utilizator*, nu pe `SYSTEM`.
- **`SYSAUX`** — SQL Tuning Sets (`wri$_sqlset_*`), AWR, audit policies active pe un PDB nou.
- **Fisierele `.aud`** din `audit_file_dest` (`adump`) — zeci de mii, niciodata curatate; **nu se vad
din SQL**, doar cu `-Disc`.
- **Alert log / trace / incident** (`diagnostic_dest`) — se purja cu `adrci purge`.
- **FRA plina cu `log_mode=ARCHIVELOG`** → `ORA-00257`/`ORA-19809`; baza se blocheaza brusc, fara
eroare vizibila in aplicatie.
- Recyclebin, `UNDO` umflat, istoric statistici/scheduler, `TEMP`.
- **Tabele de log ale aplicatiei** care cresc nelimitat (tiparul `SYS.INFO` de pe SIGMA) — apar in
raportul de top segmente, numele difera per client.
## Cazuri
- **Rompetrol Energy** (XE 21c): `ORA-12954`, limita de 12 GB pe `dba_data_files` atinsa. `SYSAUX`
umflat la 7.8 GB din SQL Tuning Sets (~5 GB) + AWR + audit policies. `TRUNCATE wri$_sqlset_*` a
eliberat segmentele, dar `RESIZE` a picat cu `ORA-03297` (`SYSAUX` nu se shrink pe XE 21c) →
singura solutie a fost **recrearea PDB-ului**, 13.5 GB → 3 GB. Detalii:
`E:\proiecte\ROMFASTSQL\proxmox\lxc108-oracle\clienti\oracle-xe-21c\` (`README.md`,
`depanare-ora-12954-spatiu.md`).
- **ROA_CENTRAL** (`ORA-65114`, 02.08.2026): acelasi tipar, rezolvat prin curatenie tintita in loc
de recreare PDB; SQL-uri gata scrise in acelasi repo (`docs/curatenie-spatiu-oracle.sql`).
- **SIGMA** (03.08.2026): `SYSTEM` plafonat la 600 MB — vezi `depanare-pack-update.md`.
## Capcane
- **Segmentele `TEMPORARY` dintr-un tablespace permanent nu dispar intotdeauna la restart** (ACN,
06.08.2026: 1.3 GB ramasi si dupa repornirea serviciului). Daca `v$sort_usage` e gol, sunt orfane
si se curata fortat, ca `SYS`: `alter session set events 'immediate trace name DROP_SEGMENTS level
<ts#+1>'` (`ts#` din `v$tablespace`) — la ACN au disparut instantaneu, cu tot spatiul recuperat.
Daca nici asa nu pleaca, apartin unui DDL neterminat — cauta `SYS_JOURNAL%` (index online) sau
obiecte `INVALID/UNUSABLE` in schema respectiva.
- **`shrink space` pe un LOB cere ASSM**; pe un tablespace MSSM da `ORA-10635` (cazul `ROA` la ACN).
Echivalentul care merge: `alter table t move lob (col) store as (tablespace <ts>)` — reconstruieste
segmentul, tine tabela blocata cat dureaza si cere spatiu liber cat segmentul mutat.
- **Privilegiile `ANY` nu se aplica pe obiectele din schema `SYS`** cat timp
`O7_DICTIONARY_ACCESSIBILITY=FALSE` — orice curatare acolo cere `SYSDBA`.
- Parola `SYS` e de obicei cea generica (vezi `COMUN\docs\local\oracle.md`), dar **nu la toti
clientii** (ex. ROMCONSTRUCT) — cand nu merge, se ia cu `PACK_UPDATE.GetSchemaParola('SYS')`.
`-SysPassword` ramane optional: diagnosticul de baza merge complet fara el, doar sectiunile
SYSDBA se sar.
- **Rolurile nu se aplica in pachete cu drepturi de definitor**: un pachet care refera static
`dba_*`/`v$*` iese `INVALID` la clientul care are accesul doar prin rolul `DBA`, chiar daca
aceleasi interogari merg din SQL*Plus. De aceea granturile directe din `sys_2026_08_03_05`.
Lantul de actualizare **nu** se opreste in acest caz: `sqlplus` iese cu cod 0 la eroare de
compilare, deci se vede doar ca pachet invalid + job cazut.
- **Curatenia poate esua din lipsa de spatiu** (`DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL` a picat asa la
Rompetrol): intai ridici plafonul, apoi cureti.
- `RESIZE` pe datafile da `ORA-03297` daca extentele folosite nu sunt la coada fisierului — un
`DELETE` fara `MOVE`/`SHRINK` nu recupereaza MB.
- Dimensiunile reale ale fisierelor de pe disc nu se vad din SQL — `-Disc`, prin `ExecuteScriptOS`.
- **`-Disc` merge doar pe servere Windows** (`ExecuteScriptOS` lanseaza PowerShell). Pe Linux
expira curat dupa 60s, cu mesaj.
- **`MAX_PDB_STORAGE` se citeste doar de pe un alias care tinteste radacina CDB.** De pe un
serviciu de PDB (cazul obisnuit al aliasurilor din `tnsnames.ora`), `alter session set
container=CDB$ROOT` da `ORA-01031` — e nevoie de un alias separat spre radacina.

41
docs/email-thunderbird.md Normal file
View File

@@ -0,0 +1,41 @@
# Citirea emailurilor (Thunderbird Portable)
Conectorul Gmail din Claude vede **doar** `mmarius28@gmail.com`. Conturile de lucru
(`marius.mutu@romfast.ro` etc.) nu sunt acolo — se citesc local, din mbox-urile Thunderbird:
```
D:\UTIL\portable\PortableApps\ThunderbirdPortable\Data\profile\ImapMail\<cont>\INBOX
```
Conturi active (dupa `LastWriteTime`): `mail.romfast.ro` (~36 MB, contul principal) si
`mail.romfast-1.ro` (~108 MB). Restul (`seanet.ro`, `romfast-4.ro`, `imap.googlemail.com`, …)
sunt vechi de ani.
```powershell
powershell -File COMUN\utile\citeste_email.ps1 -Cauta 'Diagnostic spatiu' -Ultimele 10
powershell -File COMUN\utile\citeste_email.ps1 -Nr <linie> [-Linii 200]
```
Prima forma listeaza `Cont / Linie / Data / De_la / Subiect` (filtru `-Cauta` pe subiect **sau**
expeditor, `-Cont mail.romfast.ro` restrange la un cont); a doua tipareste mesajul care incepe la
linia respectiva, pana la urmatorul separator mbox.
## Capcane
- **Nu da `Grep`/ripgrep pe folder**: `INBOX.sbd\Sent` are ~2.5 GB si cautarea expira.
- **Numerotarea liniilor difera intre unelte** (`Select-String` vs `Get-Content` vs `StreamReader`)
— mbox-ul are linii cu `\r` singur. Foloseste numarul dat de `citeste_email.ps1`, pentru ca
`-Nr` citeste cu acelasi cititor; daca linia ceruta nu e inceput de mesaj, scriptul trece la
contul urmator (`-Nr` fara `-Cont` cauta in toate).
- Thunderbird tine fisierul deschis → citire doar cu `FileShare::ReadWrite` (scriptul o face).
- Mesajele sunt in ordine cronologica, **cel mai nou la sfarsitul fisierului**; separatorul e
`From - <data>`. Corpurile HTML/base64 se tipar brut — pentru ele ia doar `Content-Type` si
primele linii, nu tot mesajul.
## Emailuri automate ROA
| Expeditor | Ce e |
|---|---|
| `roaupdate_acn@`, `roaupdate-sigma@`, `roaupdate-clever@`, `roaupdate-automotive@` … | jobul `DIAGSPATIU_ZILNIC`, subiect `Diagnostic spatiu Oracle <BAZA> <data> <ora>`, cate un expeditor per client. Vezi `depanare-spatiu-oracle.md` |
Emailul vine **doar la prag depasit**; tacere = totul in regula.

View File

@@ -76,6 +76,21 @@ fals `roundtrip text1 != text2`. Ruleaza atunci cu lista rebazata:
- Metoda noua de clasa cere `*m: nume` in `*<DefinedPropArrayMethod>`; fara ea, prima salvare
din IDE o arunca tacut, iar refresh-ul urmator absoarbe pierderea in cache (si in .bak-uri).
Override-urile de metode de baza (Init, Show, hook-uri) nu au nevoie de `*m:`.
- **Proprietate noua de clasa cere identic `*p: nume` in `*<DefinedPropArrayMethod>`** — nu doar
valoarea in `*<PropValue>`. Fara `*p:`, valoarea se scrie in text, **trece fidelity-check-ul**
(fidelity compara doar text-sursa cu text-regenerat) si ajunge in binar ca text, dar VFP nu o
materializeaza pe obiect: `PEMSTATUS(o,'nume',5)` da `.F.` si orice acces cade cu eroarea 1734
"Property ... is not found". Dovedit in ambele sensuri pe o clasa de proba izolata (cu `*p:` ->
`.T.`, fara -> `.F.`).
- **FoxBin2Prg sorteaza alfabetic cu `_` DUPA literele obisnuite**, nu in ordine ASCII brut (unde
`'_' (0x5F) < 'v' (0x76)` pe litere mici). O intrare `*p:`/`*m:` scrisa de mana in ordine "ASCII
corecta" pica fidelity-check-ul; ordinea canonica se citeste din textul regenerat in
`<staging>\verify\*.vc2` (vezi punctul de mai jos despre pozitia metodelor noi — se aplica identic
proprietatilor).
- FoxBin2Prg NU pastreaza pozitia in text a unei metode noi: o regenereaza la pozitia
alfabetica din `*<DefinedPropArrayMethod>`. O metoda scrisa in alta parte a fisierului
face fidelity-check-ul sa pice. Sursa de adevar pentru relocare e textul regenerat din
`<staging>\verify\` - muta metoda unde apare acolo si reia write-back-ul.
- Salvarea din VFP IDE peste un binar scris de txt2vcx poate PIERDE si definitii `*m:` deja
existente, desi corpurile PROCEDURE raman (patit pe ROAGEST: `import_adauga_factura.recalc_tva`,
`import_nota.do_adauga/do_copie/do_reface`); simptom: crash la Createobject cu

View File

@@ -0,0 +1,53 @@
# Flux: modificare/stergere nota in Registrul Jurnal
Comportament CORECT (nu bug): la **modificarea** unei note din Registrul Jurnal, documentul
original nu se suprascrie. Se marcheaza `sters = 1` pe randurile vechi (`ACT`/`RUL`/`RUL_OBINV`),
apoi se scrie un document NOU cu alt `cod`, pastrand acelasi `id_fact`/`id_factd`. Ambele operatii
ruleaza intr-o tranzactie manuala unica (commit sau rollback pe amandoua).
## Unde
- `afisjurcom.do_modifica` - `COMUN\clase\comun.vc2:2222-2562`. Deschide tranzactia manuala
(`Thisform.do_deschide_tranzactie()`, linia 2448), apoi `oscrie_in_fisiere(2,...)` = STERGE
(linia 2451), apoi `oscrie_in_fisiere(0,...)` = SCRIE (linia 2479), apoi
`pack_contafin.finalizeaza_modificare_nota(...)` (2484-2486), apoi
`Thisform.do_inchide_tranzactie(...)` (linia 2535) - commit daca tot ce a rulat inainte a
reusit, rollback altfel.
- `do_deschide_tranzactie`/`do_inchide_tranzactie` (`_frmbase`, `COMUN\clase\_frm_base.vc2:252,279`;
varianta identica ca procedura globala in `COMUN\programe\oproceduri_rulaje.prg:287,303`):
`SQLSetProp(gnHandle,'Transactions',2)` la deschidere, `SQLCOMMIT`/`SQLROLLBACK` +
`SQLSetProp(...,'Transactions',1)` la inchidere.
- `oscrie_in_fisiere.prg` (`COMUN\programe\oscrie_in_fisiere.prg`): `tnScrie_Sterge` 0=scriere,
2=stergere. Apeleaza server-side `pack_contafin.init_scriere_act_rul_local` +
`final_scriere_act_rul_local` -> `finalizeaza_scriere_act_rul`, care ruleaza `SCRIE_IN_ACT`
(scriere) sau `STERGE_DIN_ACT` (stergere) din `PACK_CONTAFIN.pck`.
- `PACK_CONTAFIN.STERGE_DIN_ACT` (`COMUN\docs\PACK_CONTAFIN.pck:1815-1859`):
`UPDATE ACT SET STERS = 1 ... WHERE COD = tnCod` - marcheaza vechiul document, pe `cod`-ul vechi.
- `PACK_CONTAFIN.SCRIE_IN_ACT` (`PACK_CONTAFIN.pck:630-901`): `LN_COD := pack_contafin.GET_COD()`
(linia 648) aloca un `cod` nou; `UPDATE ACT_TEMP SET COD = LN_COD, ...` (linia 897) il scrie pe
noul document - `ID_FACT` nu e atins, ramane cel din documentul original.
- `PACK_CONTAFIN.finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`): aloca din nou
`lnCodNou := pack_contafin.get_cod()` si actualizeaza pe codul nou `vanzari`
(`pack_facturare.actualizeaza_vanzari`) si `atasamente_vanzari`. `nom_lucrari` se actualizeaza
DOAR pentru `id_set IN (31003,31004,31005,31011)` (repune `id_fact`), nu general. `gest_inventar`
NU se leaga de `cod`-ul nou - se identifica dupa `dataora_validat + an + luna` (cazul
`id_set = 90101`, note de inventariere).
## Atentie: nu e valabil la fel pentru stergerea simpla
`afisjurcom.do_sterge` (`comun.vc2:2565-2724`) ofera doua optiuni (`xmenu`, linia 2625):
- **Stergere document** (`lnOptiune = 1`): DOAR `OSCRIE_IN_FISIERE(2,...)` + `finalizeaza_stergere_nota`
- marcheaza `sters = 1`, NU se creeaza document nou.
- **Anulare document** (`lnOptiune = 2`): STERGE (linia 2698) + SCRIE (linia 2709, cu sumele puse pe
0) - creeaza si document nou, la fel ca la modificare - dar aici cele doua apeluri NU sunt
invelite intr-o tranzactie manuala comuna (nu apare `do_deschide_tranzactie`/
`do_inchide_tranzactie` in `do_sterge`); fiecare `OSCRIE_IN_FISIERE` isi gestioneaza singur
commit-ul (vezi `tlModificare`/`llManualTransactions` in `oscrie_in_fisiere.prg:111-165`).
## Implicatii practice
- Codul (`cod`) unui document din Registrul Jurnal NU e stabil dupa modificare/anulare - se schimba
la fiecare editare. Cod hardcodat sau retinut dintr-o executare anterioara devine invalid.
- Regasirea documentului editat se face dupa `id_fact` (sau alt marcaj stabil), niciodata dupa `cod`.
- Randurile `sters = 1` ramase in `ACT`/`RUL`/`RUL_OBINV` dupa o modificare sunt normale (istoric),
nu date corupte sau duplicate de curatat.

View File

@@ -10,11 +10,15 @@ PL/SQL Developer.
- Alias TNS: `ROA_CENTRAL``10.0.20.121:1521`, `SERVICE_NAME=ROA` (vezi `tnsnames.ora`).
- Schema/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
- **Schema de lucru pentru verificari: `MARIUSM_AUTO` pe `ROA_CENTRAL`** - nu `ACN` sau altele.
- **Parola nu e versionată** — local, în `D:\ROA\ROAGEST\docs\local\oracle.md` (ignorat de git).
- **Parola nu e versionată în git** — în `COMUN\docs\local\oracle.md` (ignorat de git, există în SVN).
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus sinonim `PUBLIC`.
Exportul de referință se face din `MARIUSM_AUTO`.
Înainte de a lua o sursă de acolo ca referință pentru o modificare, verifică că `MARIUSM_AUTO` are
toate scripturile aplicate — procedura e în `scripturi-migrare-db.md`, secțiunea
"Sursa de referință pentru DDL".
## Gotcha sqlplus pe Windows/PowerShell
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul

View File

@@ -4,6 +4,45 @@ Regula (valabila in toate proiectele ROA/VFP): un singur subagent care duce o mi
(iteratii de teste, investigatii, mai multe sarcini inlantuite) acumuleaza context urias —
calitate degradata, cost mare. Nu se lucreaza asa.
## REGULA ZERO: predarea contextului e OBLIGATORIE, nu optionala
Se aplica **identic sesiunii principale si oricarui subagent**. Nu e o recomandare de eficienta,
e o conditie de corectitudine: un context supraincarcat pierde tacut decizii deja luate si reia
investigatii deja platite.
**Declansatoare — la oricare dintre ele, predarea porneste imediat:**
1. contextul propriu a trecut de **~50% din fereastra** (orchestrator) sau de **~200-250k tokens**
(subagent);
2. harness-ul anunta compactare automata (`PreCompact`) — **prea tarziu ca sa mai amani, dar nu
prea tarziu ca sa scrii fisierul**; scrie handoff-ul inainte sa raspunzi orice altceva;
3. utilizatorul semnaleaza ca s-a atins limita;
4. s-a terminat un bloc de lucru — indiferent cat context a mai ramas.
**Procedura, in ordine, fara exceptii:**
1. **Opreste lucrul.** Nu incepe o sarcina noua, nu porni o rulare noua. Daca esti in mijlocul unei
editari, du-o pana la o stare **consistenta pe disc** (text si binare sincronizate) si atat.
2. **Scrie handoff-ul pe disc** (`docs\handoff_<subiect>.md`). Nu in mesaj, nu in raport — **pe
disc**. Un mesaj catre orchestrator se pierde; fisierul nu.
3. **Confirma in doua randuri** ce ai lasat in urma si daca ceva e intr-o stare periculoasa
(fisier editat fara write-back, tranzactie deschisa, proces ramas viu, date de test consumate).
4. **Opreste-te.** Blocul urmator il ia un agent proaspat. "Mai am putin" nu e motiv de amanare —
exact acolo se pierd lucrurile.
**Obligatia e a fiecaruia, nu doar a orchestratorului.** Un subagent care simte ca se apropie de
prag **anunta singur** si cere predarea; nu asteapta sa fie oprit. Un orchestrator care se apropie
de prag isi scrie propriul handoff si preda orchestrarea unei sesiuni noi — regula nu are portita
pentru "eu doar coordonez".
**Ce intra obligatoriu in handoff**: inventarul livrabilelor cu `fisier:linie`; ce e terminat si ce
nu; **daca write-back-ul e facut** pentru fiecare fisier atins; comanda exacta de rulare a testelor
si unde scriu logurile; ce s-a stabilit deja (ca sa nu se reia); ce e interzis; starea datelor de
test consumate; capcanele de mediu platite. Fara analize noi — doar stare.
Doua lectii platite scump, amandoua din aceeasi cauza — un agent tinut peste prag (`s5-nivel2`
533k, `s2d-modifica-gestiuni` 434k). Predarea e aproape gratuita: raportul e oricum deja scris.
## Cum se lucreaza
- Sesiunea principala (sau un agent primar) e ORCHESTRATOR: imparte planul pe sarcini
@@ -58,7 +97,9 @@ diagnostic, fixuri aplicate direct in loc de delegate.
care intoarce da/nu, nu continutul din care ai deduce singur.
- **Nu aplica fixuri direct** decat sub ~5 linii si doar daca ai deja contextul in sesiune.
- **Prag si pe orchestrator**: la ~50% din fereastra, scrie handoff-ul si reia orchestrarea
dintr-o sesiune noua. Handoff-ul e deja pe disc - exact pentru asta exista.
dintr-o sesiune noua. Handoff-ul e deja pe disc - exact pentru asta exista. Vezi **Regula zero**
de la inceputul fisierului: obligatia e aceeasi ca pentru subagenti, fara portita pentru
"eu doar coordonez".
## Model de lucru: backlog de story-uri mici, context mic per story

View File

@@ -0,0 +1,83 @@
# Publicarea scripturilor de baza de date catre clienti
Scriptul: `COMUN\utile\publicare_scripturi.ps1`. Inlocuieste pasii manuali din `tasks.exe`
(`D:\PROIECTE\fox\tasks`, formularul din `clase\generare_script.vcx`), care raman varianta de rezerva.
Cum se scrie un script de migrare: `scripturi-migrare-db.md`.
```powershell
powershell -File COMUN\utile\publicare_scripturi.ps1 -DryRun # ce ar face pe luna curenta
powershell -File COMUN\utile\publicare_scripturi.ps1 # luna curenta, tot fluxul
powershell -File COMUN\utile\publicare_scripturi.ps1 -Luna 2026-08 # alta luna
powershell -File COMUN\utile\publicare_scripturi.ps1 -Fisier a.sql,b.sql # doar scripturile date
```
Alte optiuni: `-DoarImport` (fara arhiva), `-DoarArhiva` (doar regenerare arhiva), `-Toate`
(republica si scripturile identice), `-FaraVerificareZip`, `-Settings`, `-ZipPath`, `-DirScripturi`,
`-Alias`, `-User`, `-Password`, `-SqlPlus`.
## Configurarea
Se citeste din `settings.ini`-ul lui `tasks.exe` (`D:\PROIECTE\fox\tasks\settings.ini`, schimbabil
cu `-Settings`), aceleasi chei pe care le foloseste formularul; orice parametru dat explicit bate
ini-ul.
| din ini | ce devine |
|---|---|
| `[connection] host_database` | nume de **DSN ODBC** — aliasul TNS e cheia `ServerName` a DSN-ului din registri (`CENTRAL``ROA_CENTRAL`) |
| `[connection] username_database` / `password_database` | utilizatorul Oracle |
| `[folder] script_folder` | directorul scripturilor, cu `\SCRIPTURI\``\SCRIPTURI_CLAR\` (+ `\<an>\<luna>\`) |
| `[folder] roa_output` | + `_UPDATE\` = directorul arhivelor |
| `[folder] sqlplus_exe` | clientul Oracle (si `TNS_ADMIN` = directorul lui) |
| `[script]` | prefixele valide (`CO_`, `FF_`, `RF_`, `SYS_`, `JCS_`) — prefix necunoscut = avertisment |
`sqlplus_exe` arata spre `instantclient_19_18`; `instantclient_11_2_0_2` (valoarea de dinainte) are
un `tnsnames.ora` vechi, cu `ROA_CENTRAL` pe `10.0.20.122` in loc de `.121`, deci conexiunea expira.
`settings.ini` e local (ignorat de SVN).
## Cei doi pasi
**1. Import** — fiecare `.sql` intra ca un rand in `CONTAFIN_ORACLE.UPD_DATABASE` de pe `ROA_CENTRAL`,
cu `SCRIPT_ORDER = 0` (randul contine scriptul intreg, nu instructiuni parsate), `SCRIPT_NAME` cu
MAJUSCULE si `.SQL`, `SCRIPT_TYPE` = ce urmeaza dupa `NN_`, `SCRIPT_CONTENT` = fisierul in clar.
`ID` vine din trigger, `DATAORA` din `SYSDATE` implicit, `SCRIPT_APPVER`/`SCRIPT_EXTRA_FILE` raman
goale. Daca `SCRIPT_NAME` exista deja, se face **update pe acelasi `id`** — asa se republica un
script corectat, pentru ca clientul face `MERGE ... on (a.id = b.id)`.
**2. Arhiva lunara** — in `Y:\ROAUPDATE\_UPDATE\` se scriu `database_YYYYMMDD_YYYYMMDD.zip` **si**
`databasen_...zip` (identice azi: `database_` era varianta criptata cu `wrap.exe`, nu se mai
foloseste). Fiecare contine XML-ul cu acelasi nume ca zip-ul (format `VFPData`/`crsxml`,
Windows-1252, CRLF, tab-uri, `script_content` gol) plus cate un `<STEM_MAJUSCULE>.sql` per script.
Indexii `roa_database.xml` / `roa_databasen.xml` listeaza arhivele existente si se schimba doar
cand apare o luna noua.
Continutul din arhiva se citeste **inapoi din baza**, nu de pe disc — deci arhiva contine exact ce
va primi clientul.
## Verificari facute automat
- fisier cu sfarsituri de linie LF: **refuzat** (parsarea pe client se face pe `CHR(13)+CHR(10)`);
- dupa import, continutul e citit inapoi din CLOB si comparat octet cu octet cu fisierul; la
diferenta se opreste inainte de arhiva;
- scripturile deja publicate cu acelasi continut se sar (`-Toate` forteaza republicarea);
- arhiva generata se citeste inapoi cu cititorul clientului (`pack_utils.decodebase64` +
`zip_util_pkg.get_file`) si se compara lungime + MD5 per fisier — o arhiva facuta din PowerShell
este citita corect de `zip_util_pkg`;
- fisierele inlocuite din `_UPDATE` se copiaza intai in `_UPDATE\_backup\<data_ora>\`.
`Y:\ROAUPDATE\_UPDATE\` e **live**: clientii descarca de acolo imediat ce fisierul e pus.
## Ce face clientul
`PACK_UPDATE.UpdateScripts` (`COMUN\docs\PACK_UPDATE.pck`) descarca indexul, apoi arhivele care
acopera perioada neaplicata, extrage XML-ul cu `zip_util_pkg.get_file`, face `MERGE` in
`UPD_DATABASE` pe `id`, apoi pentru fiecare rand cu `script_extra_file` pune continutul fisierului
in `script_content` — pentru `.sql` text clar, fara base64 (base64 e doar pentru instructiunile
parsate, alta ramura). Actualizare blocata: `depanare-pack-update.md`.
## Detalii de implementare
Continutul circula **hexazecimal** in ambele sensuri (`utl_i18n.raw_to_char` / `string_to_raw` cu
`WE8MSWIN1252`), pe bucati de 900 de octeti, in blocuri PL/SQL de cate 15 bucati. Motivul: baza e
`AL32UTF8`, fisierele sunt CP1252, iar comanda trimisa lui `sqlplus` ramane ASCII pur — nu depinde
de `NLS_LANG` si nu poate strica octetii >= 0x80. Consecinta utila: comparatia dintre fisier si
CLOB e exacta, nu pe lungime.

View File

@@ -12,13 +12,20 @@
handoff-uri/planuri de runda, `*.pre_runda*.bak`, `.bak`-urile din cache-ul text si artefactele
de test (`screenshots*`, `uisync*`, `.fxp`, `.err`, loguri). Sterge doar fisiere neurmarite de
git — cele tracked sunt sarite.
2. Comentarii in cod: minime, strict functionale, descriu comportamentul CURENT (ca si cum ar fi
scris asa de la inceput) — o linie de regula, 2-3 doar pentru metode cu contract nebanal
(parametri, cursor asteptat/lasat deschis, pozitionare la iesire). Istoricul modificarilor
sta DOAR in ANTETUL fisierului (niciodata inline) — la fel in `.prg` si in PL/SQL Oracle.
INTERZIS in comentariu: nume de agent ("claude"), referinte la propuneri/decizii/etape
(`docs/propuneri_*.md`, "M2", "T3", "dec.6", "runda27", "E7", "D-H2"), istoricul modificarii
("inlocuieste...", "nu mai depinde de...", "mutat din..."), date si autori pe cod nou.
2. Comentarii in cod SI in scripturile de migrare `.sql`: minime, strict functionale, descriu
comportamentul CURENT (ca si cum ar fi scris asa de la inceput). **Doar daca e cazul** — un
comentariu se scrie acolo unde explica o **ramura** sau un **filtru** care nu se citeste singur,
ca sa se inteleaga codul; unde codul e limpede, nu se comenteaza. O linie de regula, 2-3 doar
pentru metode cu contract nebanal (parametri, cursor asteptat/lasat deschis, pozitionare la
iesire), 4-5 in antetul unui script de migrare (ce e obiectul si ce contract are). Istoricul
modificarilor sta DOAR in ANTETUL fisierului (niciodata inline) — la fel in `.prg`, in `.sql`
si in PL/SQL Oracle.
INTERZIS in comentariu: nume de agent ("claude"), referinte la planuri, stories, propuneri,
decizii, etape sau erori (`docs/plan_*.md`, `docs/propuneri_*.md`, "#6", "S4", "M2", "T3",
"dec.6", "runda27", "E7", "D-H2"), trimiteri la rapoartele din `docs/` ("vezi raportul,
sectiunea ..."), justificarea alegerii facute (de ce numele acesta, de ce s-a respins varianta
cealalta), istoricul modificarii ("inlocuieste...", "nu mai depinde de...", "mutat din..."),
date si autori pe cod nou.
Comentarii vechi in stil jurnal nu se rescriu din oficiu — doar cand blocul e oricum atins
sau la cerere explicita.
Antet: o singura intrare CUMULATIVA per functionalitate (`*!* DD.MM.YYYY` / `*!* autor` /
@@ -46,6 +53,20 @@
se umple contextul. Misiuni lungi: subagenti proaspeti per sarcina (max ~200-250k
tokens/subagent), nu unul singur cu context acumulat; handoff compact pe disc:
`orchestrare-subagenti.md`.
**Verificarea a ce se intoarce** — pentru executie delegarea merge, pentru concluzii nu:
- **citeste contractul functiei apelate, nu-l presupune.** Un raport care descrie corect
structura codului poate gresi sensul: ex. `goExecutor.oExecute` intoarce succes/insucces
(`CT_SUCCES`/`CT_INSUCCES`), NU numarul de randuri — o garda `If lnSucces > 0` citita ca
"are randuri" a produs un bug inexistent, raportat ca blocant. Deschide functia.
- **fix ingust, nu supra-constructie.** Cand premisa se corecteaza, corectia se restrange:
mecanismele noi introduse "ca sa fie sigur" diverg de la codul-sablon si blocheaza
refolosirea lui in alta parte.
- **"zero cazuri in date" nu dovedeste nimic** pe scheme cu date de test; raspunsul vine din
cod. Si invers: o potrivire de cifre pe 1-2 documente nu e o regula.
- **cere raportul sa separe "testat" de "analizat static"**, si ce n-a putut fi acoperit. Un
agent care nu e intrebat explicit va prezenta amandoua la fel.
- **spune-i ca poate infirma briefingul.** Altfel implementeaza corectia ceruta chiar cand a
descoperit ca nu e nevoie de ea.
7. Conventii obligatorii, de citit cand atingi zona respectiva:
- editezi fisiere cu octeti cp1252 - `.vc2`/`.sc2`, dar si `.prg` (ex. `programe\ocautare.prg`,
unde `s`-urile cu virgula din `masina`/`si contul`/`transa` sunt octetul `0xBA`) ->
@@ -60,6 +81,8 @@
`0xBA` strica `a`/`t` cu caciula (`0xE3`, `0xFE`) din alte fisiere;
- adaugi/rearanjezi controale pe formulare sau coloane in grid -> `conventie_ux_formulare.md`;
- grid needitabil pe formular cu 2+ grid-uri -> `capcana_grid_controlsource.md`;
- adaugi o coloana intr-un grid deja livrat (ordinea din clasa e neutralizata de
preferintele salvate per utilizator) -> `capcana_grid_preferinte_utilizator.md`;
- `GO` pe un `Recno()` capturat/primit ca parametru -> `conventie_go_recno.md`;
- `ALTER TABLE` pe cursorul intors de `goExecutor.oExecute()` -> `conventie_goexecutor_alter_table.md`;
- testare UI / prin MCP -> `testare-ui-vfp.md`, `testare-vfp-mcp.md`;

View File

@@ -3,7 +3,8 @@
Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in
`DATABASE\SCRIPTURI_CLAR` de sub radacina suitei ROA (`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.
Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo. Publicarea catre clienti
(import in `UPD_DATABASE` + arhiva lunara): `publicare-scripturi-db.md`.
Reguli confirmate de Marius (24.07.2026):
@@ -15,6 +16,50 @@ Reguli confirmate de Marius (24.07.2026):
final (conventia existenta).
- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu functioneaza
— foloseste `begin pachet.procedura(...); end;`.
- **Niciun `;` la capat de linie intr-un comentariu `--` din interiorul unei instructiuni.** SQL*Plus
termina instructiunea acolo, chiar daca `;`-ul e in comentariu: restul `CREATE VIEW`-ului ajunge sa
fie interpretat linie cu linie ca si comenzi, cu zeci de `SP2-0734` si un `ORA-00936` derutant care
arata spre comentariu. Pus la sfarsit de fraza, `.` in loc de `;`. Comentariile de **dinaintea**
instructiunii nu sunt afectate.
- **Fiecare script se incheie cu `exec pack_migrare.UpdateVersiune('<nume_script>');` urmat de
`commit;`.** DDL-ul comite implicit, dar `UpdateVersiune` e DML: fara `commit` explicit, un script
se poate aplica fara ca versiunea sa se inregistreze, iar `VERSIUNE` ajunge sa minta despre ce s-a
aplicat.
- **Rularea manuala se face conectat pe schema tinta** (`CONTAFIN_ORACLE` pentru `co_`, schema firmei
pentru `ff_`), niciodata cu un user de lucru. DDL-ul neprefixat (`create or replace package ...`)
merge pe schema conexiunii: pe alt user iese `PLS-00304` si ramane un obiect orfan, iar pachetul
tinta ramane neschimbat. In acelasi script, DML-ul pe tabele cu sinonim public nimereste tabela
reala si pare ca totul a mers — verifica intotdeauna iesirea sqlplus si `all_objects`.
`PACK_UPDATE` face `CONNECT <schema>/<parola>@ROA` real per schema (`UpdateSchemaSQLPLUS`, parola
din `SERVER_INFO`), deci scriptul neprefixat e corect pentru livrare.
## Sursa de referinta pentru DDL: MARIUSM_AUTO, nu productia
Regula lui Marius (06.08.2026): **orice modificare de tabela, view, procedura, functie sau pachet se
scrie plecand de la sursa din schema de dezvoltare `MARIUSM_AUTO` (`ROA_CENTRAL`), niciodata de la
sursa citita dintr-o schema de client** (`VENDING`, `ACN`, ...). Schemele de client raman in urma:
pot avea scripturi neaplicate sau variante livrate separat (ex. pachetele `_10G_ROMCONSTRUCT`), iar o
modificare scrisa peste o sursa veche sterge corectii deja livrate.
Schemele de client raman utile doar pentru **masuratori pe date reale**, in citire.
### Verifica intai ca MARIUSM_AUTO e la zi
"Ultima versiune din dev" e ultima versiune doar daca toate scripturile din `SCRIPTURI_CLAR` chiar au
fost aplicate acolo. `pack_migrare.UpdateVersiune` inregistreaza fiecare script aplicat in tabela
`VERSIUNE` (`script_final` = numele fisierului, cu tot cu `.sql`), deci diferenta se vede direct:
```sql
select script_final, data_final from versiune order by data_script desc, seq_script desc;
```
```powershell
Get-ChildItem D:\ROA\DATABASE\SCRIPTURI_CLAR -Recurse -Filter *.sql |
Select-Object -ExpandProperty Name | Sort-Object
```
Daca lipsesc scripturi din `VERSIUNE`, **nu porni modificarea** pe sursa de acolo — semnaleaza-i lui
Marius ce nu e aplicat. Exportul sursei de referinta: `oracle_export.md`.
## Continutul unui script
@@ -23,21 +68,46 @@ Reguli confirmate de Marius (24.07.2026):
- **Fara `select` de raportare in script** — nu-l citeste nimeni la aplicare si poate da eroare.
Verificarile se fac inainte, separat, pe schema de lucru.
- **Idempotent**: rulat de doua ori nu mai schimba nimic (`merge`, `where <coloana> is null`).
- **Un pachet sta singur in scriptul lui**, fara alt DDL sau DML alaturi: modificarile de tabele si
curateniile de date merg in scripturi separate, cu numar propriu.
- **Comentarii strict necesare**, ca in cod: antet de 4-5 randuri (data + autor, ce e obiectul, ce
contract are), fara referinte la planuri, stories, propuneri, decizii sau erori, fara trimiteri la
rapoartele din `docs/`, fara justificarea alegerilor si fara istoricul modificarii. Regula completa
si lista de interdictii: `reguli_lucru.md`, punctul 2.
## Compatibilitate cu serverele clientilor
Serverul de dezvoltare e mai nou decat serverele clientilor, deci un script care trece local poate
pica la client si opri actualizarea. **ROMCONSTRUCT e singurul client ramas pe Oracle 10.2** — el da
masura pentru orice se pune in comune.
pica la client si opri actualizarea.
Constructii care merg pe dev si pica pe 10g:
Parcul de servere (03.08.2026): **un client pe Oracle 10.2** (ROMCONSTRUCT), cativa pe **XE 11 si
11g** standard, restul pe **XE 18/19/21 si 18/21**.
| Constructie | Ce iese pe 10g |
|---|---|
| identificator peste 30 de caractere (tabela, index, constrangere, coloana) | `ORA-00972` (12.2+ accepta 128) |
| `REGEXP_COUNT` (functie din 11g) | `ORA-00904` in SQL / `PLS-00201` in PL/SQL |
| `CONTINUE` (instructiune PL/SQL din 11g) | `PLS-00201: identificatorul 'CONTINUE' trebuie declarat` |
| `FORALL` cu campuri de record din colectie (`S(i).camp`) | `PLS-00436` / `PLS-00382` |
**Regula: orice script care ajunge in comune se scrie la nivelul Oracle 10.2 si trebuie sa ruleze pe
10.2 si pe 11.x.** Numitorul comun e 10.2 — nu se folosesc facilitati 11g si cu atat mai putin 12c+,
oricat de comod ar fi pe dev. Proba inainte de publicare se face pe serverul cel mai vechi
(ROMCONSTRUCT), nu pe dev.
Constructii care merg pe dev si pica mai jos:
| Constructie | Disponibila de la | Ce iese sub ea |
|---|---|---|
| identificator peste 30 de caractere (tabela, index, constrangere, coloana) | 12.2 | `ORA-00972` |
| `REGEXP_COUNT` | 11.1 | `ORA-00904` in SQL / `PLS-00201` in PL/SQL |
| `CONTINUE` (instructiune PL/SQL) | 11.1 | `PLS-00201: identificatorul 'CONTINUE' trebuie declarat` |
| `LISTAGG` | 11.2 | `ORA-00904` |
| `PIVOT` / `UNPIVOT` | 11.1 | eroare de sintaxa |
| trigger compus (`COMPOUND TRIGGER`) | 11.1 | eroare de compilare |
| `secventa.NEXTVAL` direct intr-o atribuire PL/SQL | 11.1 | `PLS-00357` (pe 10g: `select ... into` din `dual`) |
| `FETCH FIRST n ROWS`, `CROSS APPLY`, `LATERAL` | 12.1 | eroare de sintaxa (pe 10g/11g: `rownum`) |
| `IDENTITY`, `DEFAULT ON NULL`, coloane invizibile | 12.1 | eroare de sintaxa |
| `VALIDATE_CONVERSION`, `CAST ... DEFAULT ON CONVERSION ERROR` | 12.2 | `ORA-00904` |
| `FORALL` cu campuri de record din colectie (`S(i).camp`) | 11.1 | `PLS-00436` / `PLS-00382` |
Editiile **XE** adauga limite proprii, independent de sintaxa: XE 11.2 nu are partitionare, executie
paralela si nici masina virtuala Java in baza; XE 18/19/21 au setul de facilitati al editiei mari,
dar plafonate pe resurse (12 GB de date, 2 GB RAM, 2 fire de executie). Deci nimic care sa depinda de
partitionare sau de Java in baza, si nicio operatie care sa presupuna spatiu/memorie de server mare.
Plus, independent de versiune: **un obiect nu se poate referi la ceva creat de un script ulterior.**
Pe dev obiectul exista deja, deci pachetul compileaza; la client scriptele se aplica in ordine si

34
docs/scripturi-uzuale.md Normal file
View File

@@ -0,0 +1,34 @@
# Scripturi uzuale (sarcini repetitive)
**Regula: o sarcina care se repeta se pune intr-un script si de atunci se apeleaza scriptul.**
Nu reface lantul de pasi din memorie la fiecare sesiune si nu da unui subagent aceleasi instructiuni
a doua oara — daca a doua oara e nevoie de acelasi lucru, scrie scriptul.
| Cand | Ce rulezi | Ce face |
|---|---|---|
| inceput de sesiune, si dupa orice `svn update` | `roa_sync.bat` din radacina proiectului (→ `COMUN\scripts\roa_sync.ps1`) | `svn update``git_sync` (texte `.??2`) → commit `sync SVN r<rev>` → reconciliere cu `origin` (ff/rebase) → push conditionat → inchide branch-urile `claude/*` terminate |
| inainte de un commit | `COMUN\utile\curatenie.ps1` (`-DryRun` doar listeaza) | sterge artefactele de lucru netrackuite: patch-uri de review, `handoff*`/`runda*`/`propuneri_*`, backup-uri `*.pre_runda*.bak`, artefacte de test |
| la "commit / push" | `COMUN\utile\livrare.ps1 -Mesaj "..." [-Comun]` | `git_sync``curatenie` → verificari de livrare → status/diff pe ambele repo-uri → commit + push. `COMUN` doar cu `-Comun`; `push --force` nu exista |
| editare `.vcx`/`.scx` | `D:\ROA\UTIL\foxbin2prg\` : `git_sync.ps1`, `vfp_symbols.ps1`, `txt2vcx.ps1` | reimprospatare text in-arbore, index de simboluri, write-back cu fidelity-check |
| actualizare de baza de date blocata | `COMUN\utile\diag_actualizare.ps1 -Alias <TNS>` | `UPD_ISTORIC``UPD_LOG``script_master.log` → versiuni per schema → job → tablespace → verdict. Vezi `depanare-pack-update.md` |
| spatiu plin la un client | `COMUN\utile\diag_spatiu.ps1 -Alias <TNS> [-Disc] [-SysPassword]` | tablespace, audit, ADR, FRA, disc server, top segmente. Vezi `depanare-spatiu-oracle.md` |
| publicare scripturi de baza de date | `COMUN\utile\publicare_scripturi.ps1 [-Luna YYYY-MM] [-Fisier ...] [-DryRun]` | import in `UPD_DATABASE` → arhiva lunara `database[n]_*.zip` + indexi in `_UPDATE`, cu verificare octet cu octet. Vezi `publicare-scripturi-db.md` |
| teste UI VFP | harness din `COMUN\utile\Teste` | vezi `testare-ui-vfp.md` |
| citirea emailurilor de pe conturile romfast | `COMUN\utile\citeste_email.ps1 [-Cauta ...] [-Nr <linie>]` | listeaza/extrage mesaje din mbox-urile Thunderbird Portable (conectorul Gmail nu vede conturile romfast). Vezi `email-thunderbird.md` |
Documentatia **nu** se genereaza automat si nu exista niciun hook care s-o scrie — `livrare.ps1`
doar semnaleaza ce lipseste (changelog neatins, binar VFP fara textul lui sincronizat).
Candidati inca nescrisi: un helper pentru rulat SQL prin `sqlplus` (fisier ASCII + `@fisier.sql`,
refacut manual la fiecare interogare) si un wrapper care ruleaza `diag_spatiu.ps1` peste toti
clientii, cu un rezumat pe un rand per server.
Fluxul SVN ↔ git din spatele lui `roa_sync`: `fluxul_svn_git.md`.
**Mesaje de commit din PowerShell catre `git`/`svn` (exe native): niciodata `-m $mesaj`.**
PowerShell nu escapeaza ghilimele/backtick/`$` cand paseaza argumente catre un exe nativ - un
mesaj cu `"..."` sparge comanda. Solutie: scrie mesajul intr-un fisier temporar si foloseste
`git commit -F <fisier>` / `svn commit -F <fisier>`, cu textul **UTF-8 fara BOM**
(`[IO.File]::WriteAllText($cale, $mesaj, (New-Object Text.UTF8Encoding $false))` - `Out-File
-Encoding utf8` in PS 5.1 scrie BOM, care ajunge ca prim caracter in mesajul de commit) si
**LF, nu CRLF** (`svn commit -F` refuza fisiere cu linii mixte CRLF/LF: `E135000`).

View File

@@ -33,6 +33,56 @@ dialoguri modale), nu pe pasii fluxului testat.
5. `powershell -File vfp_ui_harness.ps1 -TestPrg <test.prg> -Steps @('pas0',...)`.
PNG-uri in `screenshots\step_<n>_<eticheta>.png`; log in `<test>_log.txt`.
## Dialoguri modale (`Show(1)`)
Doua situatii, cu solutii diferite:
**A. Testul instantiaza el dialogul**`WindowType = 0` inainte de `Show()` (pasul 3 de mai sus).
`Show()` revine imediat si conduci formularul pas cu pas. Prefera intotdeauna varianta asta.
**B. `Show(1)` e hardcodat in metoda aplicatiei** (ex. `frm_facturare_articole.do_adauga_articol` /
`do_modifica`): testul nu are referinta la dialog, deci nu poate seta `WindowType`, iar fluxul real
cere sa treaca prin buton. Se conduce dintr-un **Timer pe `_SCREEN`**, pregatit INAINTE de actiunea
care deschide dialogul:
1. `_SCREEN.AddObject('tmrDrv','Timer')`, `Interval = 200`,
`BINDEVENT(_SCREEN.tmrDrv, 'Timer', <obiect driver>, 'Executa')`, `Enabled = .T.`
2. `Show(1)` **chiar pompeaza mesaje Windows** cat e modal — timerul ticaie normal (masurat: 229
tick-uri in 46s). Bucla modala nu e oarba la evenimente externe.
3. **Detectia formularului: `_SCREEN.Forms(i)` / `_SCREEN.FormCount`**, potrivit pe `.Class`.
**`_SCREEN.ActiveForm` NU merge headless** — a ramas gol la toate cele 229 de tick-uri: depinde
de `WM_ACTIVATE`, care nu se declanseaza fara focus real, pe cand colectia `Forms` contine
formularul indiferent de activare.
4. **Referinta la controale**: `loForm.<nume>` merge normal; iterarea `loForm.Controls(i)` cu
potrivire pe `.Name` e alternativa robusta (utila si ca diagnostic, pentru ca listeaza ce EXISTA
cu adevarat). **Daca accesul da 1925 "Unknown member" pe un control care sigur e in clasa,
suspecteaza mediul de test, nu colectia**: o eroare in constructia unui obiect adaugat mai
devreme opreste adaugarea celor de dupa, iar formularul ramane incomplet fara sa se plange (caz
real: lipsa cursorului `saft_taxtable`, capcana j, a lasat instanta cu 21 de controale in loc de
25, iar controlul urmator din ordinea de adaugare "disparea"). Verifica intai `ControlCount` si
lista de nume.
5. **Inchiderea**: `do_termin()` (gateaza pe `inainte_de_do_termin()`, seteaza `gnButon = 1` si
elibereaza — `_frm_base.vc2:363-371`) sau `do_renunt()`. **Daca validarea respinge, `do_termin()`
nu seteaza `gnButon` si NU elibereaza formularul, deci `Show(1)` ramane blocat** — in testele
care asteapta o respingere de validare, iesi prin `do_renunt()`.
6. **Driverul se instrumenteaza obligatoriu**: log pe fiecare pas, `TRY/CATCH` cu
`ErrorNo`/`Message`/`LineNo`, iar steagul "am tratat dialogul" se seteaza **dupa** interactiunea
reusita, nu inainte. Altfel prima eroare e invizibila si blocheaza orice reincercare — simptomul
e tick-uri la nesfarsit pana la timeout, fara nicio urma in log.
**Regula de metoda, invatata scump**: mediul unei suite noi se mosteneste din suita care **TRECE**,
nu din una care esueaza. Un mediu copiat dintr-un test nevalidat a produs trei defecte succesive
(cursor `saft_taxtable` lipsa, mock `poArticol` incomplet, nume de variabila coliziv), fiecare
descoperit dupa cate o rulare, si toate aratau ca defecte de aplicatie sau ca "test agatat". Cand
doua suite au nevoie de acelasi mediu, **extrage-l intr-un singur loc** (cu grija la capcana l
pentru constructia obiectelor).
Doua non-dovezi, ca sa nu se piarda timp pe ele:
- `AMEMBERS(a, o)` **fara flagul 2** intoarce proprietati/metode, **nu** obiectele continute —
absenta unui control din acea lista nu inseamna ca lipseste din clasa.
- `==` pe doua obiecte da eroare **107** "Operator/operand type mismatch"; pentru identitate se
foloseste `COMPOBJ()`.
## Capcane / deblocari
a. **`SET SAFETY OFF` + `SET TALK OFF` inaintea primului `STRTOFILE`.** Cu SAFETY ON, scrierea
@@ -90,7 +140,10 @@ j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a surs
`saft_taxtable` real (nu doar mock pe `goExecutor` - `update_jtva_coloane` face
`USE saft_taxtable` direct pe alias). Fara ele, simptomul e dialog nativ Windows "Open" (cauta
`saft_taxtable.dbf`) care blocheaza headless la nesfarsit, fara linie noua in log si CPU 0% -
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`.
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`. Acelasi
simptom apare si FARA `gl406`: un control cu `RowSourceType=3` legat direct in clasa de un SQL
pe `saft_taxtable` (ex. combo pe explicatie SAFT) isi evalueaza `RowSource` la constructia
formularului indiferent de `gl406` sau de `Visible=.F.` - cursorul mock trebuie creat oricum.
k. **`LOCATE FOR camp == 'literal'` pe camp `C(n)` padded nu gaseste nimic** (`==` e exact) -
foloseste `ALLTRIM(camp) == 'literal'`.
l. **`CREATEOBJECT`/`ADDPROPERTY` se comporta gresit apelate DINTR-O PROCEDURA in acest runtime
@@ -115,3 +168,47 @@ o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending`
realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare, pe un efect pe care
resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar la schimbarea explicatiei)
- altfel testul pica fara sa fie ceva gresit in cod.
p. **Nu numi variabilele ca functii built-in VFP.** VFP e insensibil la litere mari/mici, iar la
coliziune **functia castiga**. Caz real: `LOCAL loCk` pentru referinta la un checkbox se ciocneste
cu `LOCK()``loCk.Value = 1` da eroarea **1924 "LOCK is not an object"**, iar `VARTYPE(loCk)`
evalueaza `LOCK()` si intoarce `'L'`, deci verificarile de tipul `VARTYPE(lo...) == 'O'` ies
**tacut false** si par sa spuna ca obiectul nu a fost gasit — masuratoarea e stricata, nu
rezultatul. Simptom de recunoscut: mesajul de eroare contine numele **cu majuscule** al unei
functii VFP, nu numele variabilei asa cum ai scris-o. Prefixeaza distinctiv (`loBifa`, `loCtrl`).
q. **`DO ... WITH` paseaza PRIN REFERINTA, iar variabila devine invizibila sub numele ei propriu in
procedura apelata.** Consecinta urata: orice `?variabila` din SQL passthrough de pe lantul
apelurilor respective nu se mai poate lega, si VFP deschide dialogul nativ **"View Parameter —
Enter the value for `<var>`"**, care blocheaza testul headless la infinit (fara log, fara
eroare). Dovedit pe date: o variabila globala era valida in programul principal la fiecare
checkpoint, dar `TYPE()` intorcea `'U'` (nedefinita) exact la intrarea in procedurile apelate cu
`DO proc WITH gnAn, gnLuna` — si valida in cele apelate fara `DO ... WITH` — corelatie exacta cu
**sintaxa apelului**, nu cu ce face procedura. Remediu: paranteze pe fiecare argument forteaza
pasarea prin valoare — `DO proc WITH (gnAn), (gnLuna)`.
r. **O suita care testeaza o clasa din `COMUN` poate incarca implicit copia ALTUI PRODUS**, daca
harnessul de mediu comun (ex. `test_init_env_auto.prg`) face `SET DEFAULT TO`/`SET PATH` pe
working copy-ul altui produs (ex. `D:\ROA\ROACONT\...`) inainte de `SET CLASSLIB TO <clasa>
ADDITIVE`: `Createobject` gaseste prima clasa cu acel nume pe `PATH`, care poate fi
`D:\ROA\ROACONT\COMUN\clase\<clasa>.vcx` in loc de fisierul editat sub test — silentios, fara
eroare. Simptom: testul trece curat, dar valideaza cod vechi/alt working copy; orice concluzie
trasa asa e nula. Remediu, dupa initializarea mediului comun: `RELEASE CLASSLIB <nume>` +
`SET CLASSLIB TO <cale completa a fisierului sub test> ADDITIVE` (`SET CLASSLIB ... ADDITIVE`
**singur**, fara `RELEASE` intai, da eroarea 24 "Alias name is already in use" si pastreaza
tacut copia veche). Verificare obligatorie dupa instantiere: `loForm.ClassLibrary` trebuie sa
arate calea completa asteptata.
s. **Dialoguri native care nu apar in log si nu sunt prinse de `ON ERROR`/mock-uri** (ex. "View
Parameter", "Open" pe fisier lipsa): nu se depaneaza orbeste, se ruleaza sub
`COMUN\utile\Teste\watchdog_vfp.ps1 -Script <test.prg> -AutoDismiss`. Lanseaza `vfp9.exe -A -T`,
polleaza ferestrele top-level ale procesului (identificate prin `Process.MainWindowHandle`, nu
dupa numele clasei — VFP foloseste clase `vfp9...` si pentru shell-ul principal si pentru
dialogurile proprii), captureaza PNG + textul fiecarui control copil (`WM_GETTEXT`) la orice
fereastra noua, si omoara procesul la iesire (`finally`, niciodata ramas viu). **Interzis strict:
input real** (`keybd_event`/`SetForegroundWindow`/`SendInput`/`mouse_event`) — masina e
partajata, un input injectat la nivel de sistem ajunge in orice fereastra are focus in acel
moment, nu neaparat in dialogul tintit (patit: un ESCAPE injectat a intrerupt sesiunea IDE a
utilizatorului, aflat in lucru in paralel). `-AutoDismiss` foloseste STRICT mesaje Windows
tintite pe handle (`BM_CLICK` pe buton Cancel/Anulare, altfel `WM_COMMAND IDCANCEL` ->
ESCAPE ca mesaj `WM_KEYDOWN`/`WM_KEYUP` -> `WM_CLOSE`); pe dialogurile proprii VFP owner-drawn
(butoane desenate, nu HWND-uri reale) dismiss-ul poate esua cinstit — captura PNG + dump text
raman oricum de incredere, indiferent de rezultatul dismiss-ului. Sterge intotdeauna `.fxp`-ul
vechi inainte de FIECARE rulare (watchdog-ul o face singur la lansare) — altfel VFP ruleaza
tacut codul compilat vechi si rulari "identice" dau rezultate diferite, fara nicio urma in log.

View File

@@ -0,0 +1,118 @@
# Tipurile de document din facturare (`VANZARI.TIP`) si seturile de contare (`ID_SET`)
Referinta pentru toata suita ROA: `PACK_FACTURARE` e in `COMUN`, iar `VANZARI.TIP` e citit de
view-urile `FACT_VFACTURI` / `FACT_VFACTURI2`, de gridul principal de listare si de retiparire.
**Surse** (nu presupuneri):
- perechile `(lnIdSet, tnTip)` — comentariul din antetul `PACK_FACTURARE` (`:80-125` in exportul
`all_source`), singurul loc care le documenteaza impreuna;
- eticheta afisata — `CASE a.tip` din coloana `EXPLICATIE` a celor doua view-uri, citit din sursa
live de pe `MARIUSM_AUTO` (06.08.2026);
- restul — cod, marcat ca atare.
`ID_SET` e setul de formule contabile (`XSETS.ID_SET`, ajunge in `ACT.ID_SET`), pus in variabila de
pachet `pack_facturare.nid_set` din `initializeaza_date_factura` (`:1864`). **Regula generala: setul
"cu scadere din gestiune" e cel de baza + 10.**
## Facturi
| `ID_SET` | cu scadere | `TIP` | Document | `EXPLICATIE` afisat |
|---|---|---|---|---|
| 25000 | 25010 | 1 | pe baza de lista de preturi | `POLITICA PRETURI` |
| 25001 | 25011 | 2 | pe baza de contracte | `CONTRACT` |
| 25002 | 25012 | 3 | pe baza de comenzi | `COMANDA` |
| 25003 | 25013 | 4 | pe baza de avize | `FACT. DIN AVIZ` |
| 25004 | 25014 | 5 | lista de preturi in valuta | `POLITICA PRETURI - INVOICE` |
| 25005 | 25015 | 6 | contract in valuta | `CONTRACT - VALUTA` |
| 25006 | — | 7 | credit note | `CREDIT NOTE` |
| 25007 | 25017 | 8 | retur factura in lei | `RETUR FACTURA IN LEI` |
| 25008 | 25018 | 9 | retur factura in valuta | `RETUR INVOICE` |
| 25009 | 25019 | 10 | factura fiscala in valuta | `POLITICA PRETURI - FACTURA VALUTA` |
| 25042 | 25052 | 43 | bon fiscal (ROARETAIL, colectate de la magazine) | `BONURI FISCALE MAGAZINE` |
| 25043 | — | 44 | factura hotel | `HOTEL` |
| 25044 | 25054 | 45 | factura restaurant | `RESTAURANT` |
| 25045 | 25055 | **46** | **nota de plata restaurant** | **nicio ramura** |
| 25047 | 25057 | 48 | factura marfa custodie **cu** descarcare K | `FACT. CUSTODIE CU DESCARCARE PE BAZA DE K` |
| 25048 | 25058 | 49 | factura marfa custodie **fara** descarcare K | `FACT. CUSTODIE FARA DESCARCARE PE BAZA DE K` |
| 25051 | 25061 | 52 | pe baza de contract, factura fiscala in valuta | `CONTRACT - FACTURA VALUTA` |
| 50100 | 25060 | 51 | factura ROAACNPRO | `COMERCIAL-FACTURARE` |
## Avize de expeditie
| `ID_SET` | cu scadere | `TIP` | Document | `EXPLICATIE` afisat |
|---|---|---|---|---|
| 25020 | 25030 | 21 | catre clienti, **din comanda** | `AVIZ PE BAZA DE COMANDA` |
| 25021 | 25031 | 22 | catre clienti, din lista de preturi | `AVIZ DIN POLITICA DE PRETURI` |
| 25022 | 25032 | 23 | transfer catre subunitati, din lista | `TRANSFER` |
| 25023 | 25033 | 24 | aviz de retur | `AVIZ DE RETUR` |
| 25024 | 25034 | 25 | transfer catre subunitati, **din comanda** | `TRANSFER PE BAZA DE COMANDA` |
| 25025 | 25035 | 26 | catre clienti, din contract | `AVIZ PE BAZA DE CONTRACT` |
| 25026 | 25036 | 27 | transfer catre subunitati, **pe baza de lucrare** | `TRANSFER PE BAZA DE LUCRARE` |
| 25027 | 25037 | 28 | catre clienti debitori, **din comanda** | `CLIENTI DEBITORI - COMANDA` |
| 25028 | 25038 | 29 | catre clienti debitori, din lista | `CLIENTI DEBITORI - POLITICA PRETURI` |
| 25029 | 25039 | 30 | transfer catre subunitati, pe baza de NIR | `AVIZ PE BAZA DE NIR` |
| 25040 | 25050 | 41 | retur transfer catre subunitati, lista de pret | `RETUR TRANSFER` |
| 25041 | 25051 | 42 | catre clienti **custodie, din comanda** | `CLIENTI IN CUSTODIE - COMANDA` |
| 25046 | 25056 | **47** | catre clienti **custodie, din comanda, pentru descarcare cu K** | `CLIENTI IN CUSTODIE - COMANDA (K)` |
| 25049 | 25059 | 50 | *in lucru* — retur de la clienti custodie | nicio ramura |
## Tipuri negative
Nu apar in comentariul din pachet; luate din `CASE`-ul `EXPLICATIE`. Vin din alte produse sau din
fluxuri valorice.
| `TIP` | `EXPLICATIE` afisat | Observatii |
|---|---|---|
| -1 | `MATERII PRIME SI MATERIALE` | |
| -2 | `PRODUSE` | |
| -3 | `MARFURI LA PRET DE ACHIZITIE` | |
| -4 | `MARFURI LA PRET DE VANZARE` | |
| -6 | `RETUR TRANSFER DIN GESTIUNE VALORICA` | ROAGEST; `ID_SET` 236/240/241/242 |
| -7 | `AVIZ DE RETUR - VALORIC` | |
| -8 | `FACTURA DE RETUR - VALORICA` | |
| -9 | `PROTOCOL CU TVA - AVIZ EXPEDITIE` | |
| -10 | `SPONSORIZARE - AVIZ EXPEDITIE` | |
| -11 | `MARFURI LA PRET DE ACHIZITIE *` | |
| -12 | `DEVIZE AUTO` | **ROAAUTO**, `factureaza_deviz` din `oproceduri_devize.prg` |
| -13 | `RETUR MARFA IN CUSTODIE` | |
## Seturile de tipuri folosite in cod (unde conteaza incadrarea)
| Set | Unde | Ce face |
|---|---|---|
| `{3, 21, 28, 42, 47}` | `initializeaza_date_factura` (`:1888-1894`) | populeaza `pack_facturare.nid_comanda` din `clistaid` |
| `+ {27}` | `scrie_avize_lucrare:5859` | suprascrie `nid_comanda` prin cursor pe `COMENZI` legat de `ID_LUCRARE` |
| `{3, 21, 27, 28, 42, 46}` | `ALTELE` in ambele view-uri | afiseaza **comanda** (`nr_comanda/data`) |
| `{4, 24, 8, 9}` | `ALTELE` in ambele view-uri | afiseaza **avizul** |
| `{23, 25, 27, 30, 41, -6}` | `CLIENT` in ambele view-uri | afiseaza gestiunea, nu partenerul |
| `{23, 25, 27, 30, 41}` si `-6` | `scrie_in_vanzari` (disc `:13530-13540`) | `lnIdGestiune` explicit, nu `min()` din detalii |
## Capcane confirmate
1. **`46` vs `47` in `ALTELE`.** Lista din view contine `46` (nota de plata restaurant, document
care n-are comanda) si **nu contine** `47` (aviz custodie din comanda, care are). Pachetul
populeaza `nid_comanda` pentru `47`, nu pentru `46`. `CASE`-ul `EXPLICATIE` din acelasi view are
ramura pentru `47` si **nu** are pentru `46` — deci cele doua `CASE`-uri din acelasi view se
contrazic pe aceste doua cifre. Decizia lui Marius (06.08.2026): **se adauga `47`, `46` ramane
asa cum a fost scris.**
2. **Efect vizibil pe `46`, azi**: ramura fiind luata fara ca documentul sa aiba comanda,
`f.nr_comanda || '/' || to_char(f.data_comanda, ...)` da un **`/`** singur in coloana "Altele",
nu gol. Nu s-a observat pe date pentru ca niciun client verificat nu foloseste modulul de
restaurant (0 documente `tip=46` si pe `MARIUSM_AUTO`, si pe `VENDING`).
3. **`ID_SET` 25051 apare de doua ori** in comentariul din pachet: ca set "cu scadere" pentru
`tip=42` si ca set de baza pentru `tip=52`. Coliziune in documentatie, neverificata pe
`XSETS` — de lamurit inainte de a te baza pe ea.
4. **`tip=51`**: comentariul spune "factura ROAACNPRO", eticheta afisata e `COMERCIAL-FACTURARE`.
Acelasi lucru, doua denumiri; eticheta din view e cea confirmata de constantele VFP curente
(`ofacturare_comun.vc2:3654,3657`).
5. **`tip=50`** e marcat "in lucru" in comentariu si n-are ramura de eticheta — de tratat ca
neterminat, nu ca tip valid.
6. **Comentariul nu e cod.** E singura documentare a perechilor `(ID_SET, TIP)`, dar poate fi ramas
in urma. Inainte de a te baza pe o linie din el pentru o modificare, confirm-o pe cod
(`initializeaza_date_factura`, `CASE`-urile din view-uri) sau pe `XSETS`.
## Legaturi
- `scripturi-migrare-db.md` — sursa de referinta pentru DDL e `MARIUSM_AUTO`, nu o schema de client.
- `conventie_null_vfp.md``TIP_INCASARE` si celelalte coloane `0` vs `NULL` din view-uri.

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -5,20 +5,47 @@ Poate folosesti exact datele de la anaf descarcate pentru verificarea codurilor
Vreau ca verificarile de coduri fiscale din D406, D394, Registrele de TVA sa foloseasca direct ANAF, si sa actualizeze cache-ul istoricul din baza de date (ISTORIC_CODURI_FISCALE)
2. ROACONT - Borderou eFactura, checkbox-urile diferente fata de Registrele de TVA sa aiba in caption si numarul de inregistrari cu diferente, astfel incat utilizatorul sa stie daca este cazul sa filtreze pentru afisarea facturilor cu diferente
DONE 2. ROACONT - Borderou eFactura, checkbox-urile diferente fata de Registrele de TVA sa aiba in caption si numarul de inregistrari cu diferente, astfel incat utilizatorul sa stie daca este cazul sa filtreze pentru afisarea facturilor cu diferente
3. ROACONT - modificare nota, explicatia tva sa filtreze dupa procent tva din tabel, ca sa arate o selectie mai mica de explicatii tva. vezi cum ai facut la explicatia tva din ointroduceri.vcx > import_nota.
DONE 3. ROACONT - modificare nota, explicatia tva sa filtreze dupa procent tva din tabel, ca sa arate o selectie mai mica de explicatii tva. vezi cum ai facut la explicatia tva din ointroduceri.vcx > import_nota.
4. ROACONT - overificari.vcx > formularul istoric coduri fiscale are coloane care nu mai au relavanta sau nu mai sunt completate din tabel. in tabelul contafin_oracle.istoric_coduri_fiscale, campul regcom are spatii si nu se afiseaza in formularul istoric. verifica
DONE 4. ROACONT - overificari.vcx > formularul istoric coduri fiscale are coloane care nu mai au relavanta sau nu mai sunt completate din tabel. in tabelul contafin_oracle.istoric_coduri_fiscale, campul regcom are spatii si nu se afiseaza in formularul istoric. verifica
5. ROACONT - VERIFICARE cod fiscal, label-ul de sub grid-ul cu rezultate si detalii F4 sa contina si status "TVA Incasare"
DONE 5. ROACONT - VERIFICARE cod fiscal, label-ul de sub grid-ul cu rezultate si detalii F4 sa contina si status "TVA Incasare"
6. ROAFACTURARE - EDITARE FACTURA EMISA ANTERIOR, CARE NU A FOST TRIMISA INCA IN EFACTURA (anaf_efactura.id_fact). punctul critic este ca notele contabile si eventual rulajele generate se genereaza complicat la emiterea facturii prin pack_facturare, iar editarea este o simpla editare, si nu sincronizeaza si notele contabile si rulajele. si sunt diverse tipuri de facturi sau de avize (pe baza de lista de preturi, pe baza de comanda, pe baza de contract, pe baza de aviz) si fiecare genereaza note contabile sau rulaje si articole de vanzare (vanzari si vanzari_detalii)
7. ROAFACTURARE - TVA unitar si valoarea TVA pe o linie de articol este calculata si nu salvata in vanzari si vanzari_detalii. din aceasta cauza, daca o factura are valoare totala 99.99 lei, dar utilizatorul doreste 100.00 lei total cu tva (pentru ca politica de preturi are bifat preturi fara TVA si se porneste calculul incepand de la pretul fara TVA al articolului) tva-ul se calculeaza rotunjit si nu se poate edita, ca sa dea factura fix 100.00 lei. implicatiile calculului TVA in loc de salvare sunt foarte mari si adanci in program, la introducerea facturii, listarea facturii initiale, relistarea facturii
Sau de fapt este posibil sa poata utilizatorul sa modifice "preturi_cu_tva" la nivel de fiecare articol, la introducerea facturii si ulterior la editare factura, tocmai pentru ca utilizatorul doreste sa ajusteze tva-ul total pentru ca are restrictie sa dea facturii o valoare totala rotunjita, si se poate ajusta exact din pretul cu tva individual. pret_cu_tva se salveaza in vanzari_detalii pe fiecare articol.
8. ROAFACTURARE - in pack_facturare am salvat in vanzari valori totale denormalizat (fara tva, tva, cu tva, numarul avizului/comanda/contract etc.) ca sa nu le calculez in view din vanzari_detalii pentru ca view-ul de facturi este foarte complex, cu functii si expresii si nu era optimizabil si acceseaza total tabelele vanzari si vanzari_detalii. folosesc un view pe modelul original, si un view cu valorile totale din vanzari. doar ca am observat un bug, la facturile din avize, nu se salveaza corect in vanzari avizul sau numarul/data/suma chitantei daca factura este achitata numerar. trebuie depanat. schema de verificare productie este VENDING@ROA_VENDING
DONE 8. ROAFACTURARE - in pack_facturare am salvat in vanzari valori totale denormalizat (fara tva, tva, cu tva, numarul avizului/comanda/contract etc.) ca sa nu le calculez in view din vanzari_detalii pentru ca view-ul de facturi este foarte complex, cu functii si expresii si nu era optimizabil si acceseaza total tabelele vanzari si vanzari_detalii. folosesc un view pe modelul original, si un view cu valorile totale din vanzari. doar ca am observat un bug, la facturile din avize, nu se salveaza corect in vanzari avizul sau numarul/data/suma chitantei daca factura este achitata numerar. trebuie depanat. schema de verificare productie este VENDING@ROA_VENDING
9. ROAGEST - MODIFICARE REGISTRU JURNAL - SA SE POATA MODIFICA SI "NNIR" in notele contabile si sincronizat in rulajele asociate. nu exista coloana NNIR in formularul de editare.
DONE 9. ROAGEST - MODIFICARE REGISTRU JURNAL - SA SE POATA MODIFICA SI "NNIR" in notele contabile si sincronizat in rulajele asociate. nu exista coloana NNIR in formularul de editare.
10. ROAFACTURARE - Integrare pagina contracte si rapoarte contracte in ROAFACTURARE, similar COMENZI in ROAFACTURARE - facturare pe baza de comenzi/contracte. trebuie comasate si drepturile pe obiectele din roacontracte cu obiectele noi din ROAFACTURARE.
10. ROAFACTURARE - Integrare pagina contracte si rapoarte contracte in ROAFACTURARE, similar COMENZI in ROAFACTURARE - facturare pe baza de comenzi/contracte. trebuie comasate si drepturile pe obiectele din roacontracte cu obiectele noi din ROAFACTURARE.
11. ROAFACTURARE - Integrare politici de preturi in ROAFACTURARE - sunt numai editari de liste de preturi, note contabile, nomenclator articole, drepturi pe liste de preturi, care toate se folosesc numai in programul ROAFACTURARE
12. ROAFACTURARE - sa pot sa folosesc direct nomenclatorul de articole pe post de lista de preturi, sa nu mai definesc liste de preturi, note contabile asociate. Acum am un echivalent (lista de articole din stoc ca o lista de preturi virtuala)
Ca sa vand un articol, trebuie sa il introduc in nomenclatorul de articole obligatoriu. Acum trebuie sa il introduc si intr-o lista de preturi, ca sa am valuta, nota contabila de vanzare si daca are pret_cu_tva sau nu, procentul de tva vanzare, si bineinteles, pretul.
Am vazut la SAGA (alt ERP popular) ca in nomenclatorul de articole au cateva coloane de multe preturi, probabil pentru mai multe liste de preturi (todos-articole-preturi-saga.png)
Ideea este sa se poata face configurarea mult mai repede, eficient, dintr-un singur loc, ca sa se poata face factura mai rapid. Acum este nevoie de mult suport tehnic/instructaj si configurari pana se ajunge la facturare, si daca apare un articol diferit (ex: vanzare auto, in loc de marfa in mod normal), trebuie creata o politica noua de preturi, ca sa ii spun ce nota contabila de vanzare (4111 = 7xx) sa aiba aiba articolul respectiv.
13. ROAFACTURARE - FORMULARUL DE FACTURARE SA INCLUDA SI FORMULARUL DATE_FACTURA/DATE_AVIZ ETC. SI SA NU MAI INCARCE DE PE SERVER TOATE ARTICOLELE DIN TOATE POLITICELE DE PRETURI - INTRUCAT ESTE POSIBIL SA FIE SI MII DE ARTICOLE SI DUREAZA MULT SA LE ADUCA DE PE SERVER. AM INCEPUT DEJA MAI DEMULT UN FORMULAR UNIFICAT frm_facturare_articole2, DAR ERA MULT DE INTEGRAT DIN FORMULARUL VECHI.
FRONTEND SIMILAR PE CARE IL DORESC ESTE IN ROAACPRO > FACTURA, SAU IN IMPORTUL DE EFACTURA, IN CARE AM INTEGRAT DATELE FACTURI, DOAR CA FACTURAREA DIN ROAFACTURARE ESTE MAI COMPLEXA - ESTE FOLOSITA SI PENTRU POLITICI DE PRETURI SI PENTRU CONTRACT/COMANDA/AVIZ/RETUR ETC.
INTERESUL MEU ESTE SA SIMPLIFIC INTERFATA, SA FIE MAI EFICIENTA, SA NU FIE 2 FORMULARE PENTRU FACTURA, SA FAC MAI RAPID.
14. ROACONT - efactura se salveaza xml detaliat si xml zip efactura si ocupa mult spatiu. vreau sa stiu cand nu mai este nevoie de xml detaliat si daca se poate curata tabelul ca sa nu mai ocupe spatiu, cel putin pentru facturi mai vechi. este important zip pentru ca este factura originala anaf.
15. ROACONT - ce locuri din program mai folosesc frm_modific2007 in loc de frm_modific2024. trebuie migrat la formularul mai nou.
16. ROAFACTURARE - in date_factura/date_aviz etc, la finalizare se verifica cursul valutar necesar pentru politicile de preturi care se factureaza. la revenire din formularul de curs valutar, focusul revine inainte de numar document, cred ca pe TIP DOCUMENT, si la iesire din serie se regenereaza numar act, ceea ce este periculos daca utilizatorul l-a schimbat si se modifica automat.
17. ROAFACTURARE - daca o nota contabile de vanzare nu are configurat tip de venit/cheltuiala, si nici articolele din lista de preturi, si nici nu se completeaza tip venit/cheltuiala la facturare, la finalizarea facturii apare o eroare oracle ORA ca id_venchelt nu are voie sa fie null. eroarea nu este user friendly si nu se poate recupera usor, pentru ca trebuie sa se dea renunt la toata factura si sa se reia tot porcesul, cu completarea tip venit cheltuiala. si nici nu stiu de ce este obligatoriu tip venit/cheltuiala.
18. ROAFACTURARE - EMITERE FACTURA DIN PROFORMA
19. ROAFACTURARE - EDITARE PROFORMA

View File

@@ -197,6 +197,9 @@ Procedure ANAF_StarePartener
Addproperty(loOut, "dSfarsitScpTVA", Iif(Pemstatus(loRezANAF, 'dSfarsitScpTVA', 5), Nvl(loRezANAF.dSfarsitScpTVA, {}), {}))
Addproperty(loOut, "dAnulareScpTVA", Iif(Pemstatus(loRezANAF, 'dAnulareScpTVA', 5), Nvl(loRezANAF.dAnulareScpTVA, {}), {}))
Addproperty(loOut, "cMesajScpTVA", Iif(Pemstatus(loRezANAF, 'cMesajScpTVA', 5), Alltrim(Nvl(loRezANAF.cMesajScpTVA, '')), ''))
Addproperty(loOut, "lTvaIncasareANAF", Iif(Pemstatus(loRezANAF, 'lTvaIncasare', 5), Nvl(loRezANAF.lTvaIncasare, .F.), .F.))
Addproperty(loOut, "dInceputTvaInc", Iif(Pemstatus(loRezANAF, 'dInceputTvaInc', 5), Nvl(loRezANAF.dInceputTvaInc, {}), {}))
Addproperty(loOut, "dSfarsitTvaInc", Iif(Pemstatus(loRezANAF, 'dSfarsitTvaInc', 5), Nvl(loRezANAF.dSfarsitTvaInc, {}), {}))
Addproperty(loOut, "dData", m.ldData)
Addproperty(loOut, "cSursa", Iif(Pemstatus(loRezANAF, 'cSursa', 5), loRezANAF.cSursa, 'ANAF'))
Addproperty(loOut, "dDataSursa", Iif(Pemstatus(loRezANAF, 'dDataSursa', 5), Nvl(loRezANAF.dDataSursa, {}), {}))
@@ -233,6 +236,9 @@ Procedure ANAF_CitesteDinIstoric
Addproperty(loRez, "dSfarsitScpTVA", Nvl(data_sfarsit_ScpTVA, {}))
Addproperty(loRez, "dAnulareScpTVA", Nvl(data_anul_imp_ScpTVA, {}))
Addproperty(loRez, "cMesajScpTVA", Nvl(mesaj_ScpTVA, ""))
Addproperty(loRez, "lTvaIncasare", Nvl(statusTvaIncasare, .F.))
Addproperty(loRez, "dInceputTvaInc", Nvl(dataInceputTvaInc, {}))
Addproperty(loRez, "dSfarsitTvaInc", Nvl(dataSfarsitTvaInc, {}))
Addproperty(loRez, "cSursa", m.tcSursa)
Addproperty(loRez, "dDataSursa", Nvl(data_sursa, {}))
Endif
@@ -844,7 +850,7 @@ DEFINE CLASS anaf_verif_cautare AS Custom
PROCEDURE TextStare
Lparameters toStare, tcPerioada
Return Iif(toStare.lPlatitorANAF, 'Platitor TVA', 'Neplatitor TVA') + Nvl(m.tcPerioada, '') + Iif(toStare.lInactivANAF, ', Inactiv', '')
Return Iif(toStare.lPlatitorANAF, 'Platitor TVA', 'Neplatitor TVA') + Nvl(m.tcPerioada, '') + Iif(toStare.lInactivANAF, ', Inactiv', '') + Iif(toStare.lTvaIncasareANAF, ', TVA la incasare', '')
ENDPROC
PROCEDURE SufixPerioadaTVA
@@ -913,6 +919,11 @@ DEFINE CLASS anaf_verif_cautare AS Custom
If !Empty(toStare.cMesajScpTVA)
lcTxt = m.lcTxt + 'Mesaj ANAF: ' + Alltrim(toStare.cMesajScpTVA) + Chr(13)
Endif
If toStare.lTvaIncasareANAF
lcTxt = m.lcTxt + 'TVA la incasare' + ;
Iif(!Empty(toStare.dInceputTvaInc), ' din ' + Dtoc(toStare.dInceputTvaInc), '') + ;
Iif(!Empty(toStare.dSfarsitTvaInc), ' pana la ' + Dtoc(toStare.dSfarsitTvaInc), '') + Chr(13)
Endif
If !Empty(m.lcTxt)
lcTxt = m.lcTxt + Chr(13)
Endif
@@ -3161,7 +3172,7 @@ Endproc && caut_politici_curente_util
************************************** SFARSIT: caut_politici_curente_util **************************************
***************************************** INCEPUT:caut_explicatie_tva *******************************************
Function caut_explicatie_tva
Parameters tnIdJtva, tnPornire, tlDesktop, tlTipEx
Parameters tnIdJtva, tnPornire, tlDesktop, tlTipEx, tnCotaTva
*!* tlTipEx = 0 - toate
*!* = 1 - doar TVA exigibil din JC
*!* = 2 - doar TVA neexigibil din JC
@@ -3207,6 +3218,10 @@ Function caut_explicatie_tva
lcFiltruOriginal = [id_jtva_coloana in (select id_tva from vjtva_coloane where ] + ;
[id_jtva_ex is not null)]
Endcase
*** filtru suplimentar pe cota TVA a liniei curente; fara procent (0/gol) se pastreaza lista completa
If Vartype(tnCotaTva) = 'N' And tnCotaTva > 0
lcFiltruOriginal = lcFiltruOriginal + [ and cota_tva = ] + Alltrim(Str(tnCotaTva, 10, 2))
Endif
*!* *!* If tnIdJtva > 0
*!* *!* lcFiltruOriginal = [jc * 4 + jv * 2 + decode(afisat,0,0,1) in ] + ;
*!* *!* [(select jc * 4 + jv * 2 + decode(afisat,0,0,1) from ] + gcS + [.vjtva_coloane ] + ;

View File

@@ -0,0 +1,296 @@
*** ofacturare_editare
*!* 08.08.2026
*!* marius.mutu
*!* helpere comune pentru editarea unei facturi emise: garda eFactura, cursoarele notei si ale rulajelor,
*!* randul de vanzare corespunzator notei si liniile de articole pentru pagina de articole factura
*!* parametru: id_fact
*!* verifica daca factura cu id_fact dat a fost deja trimisa in eFactura (anaf_efactura)
FUNCTION EsteInEFactura
LPARAMETERS tnIdFact
LOCAL lcSql, lnEFactura, llSucces
lnEFactura = 0
lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + Alltrim(Str(Nvl(m.tnIdFact,0)))
llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @lnEFactura)
RETURN (Nvl(m.lnEFactura,0) > 0)
ENDFUNC && EsteInEFactura
*!* parametri: cod, an, luna, arata si randurile sterse (implicit .F.)
*!* incarca cursoarele notei (tact) si ale rulajelor (trul, trul_obinv), cu recalculul de
*!* valoare/valtva/valoarev/valtvav pe randurile goale; raman deschise READWRITE pe seama apelantului
*!* pe eroare Oracle intoarce .F. si inchide ce a deschis pana atunci
FUNCTION IncarcaCursoareModificareNota
LPARAMETERS tnCod, tnAn, tnLuna, tlAratasterse
LOCAL lcConditieSters, lcSql, lcCursor, lnSucces
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
lcConditieSters = IIF(m.tlAratasterse, [ ], [ STERS = 0 AND ])
lcSql = [select * from vact_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_act]
lcCursor = [v_act]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
RETURN .F.
ENDIF
SELECT * FROM v_act INTO CURSOR actactan
SELECT .F. AS ales, T.*, CAST(0 AS N(2)) AS tipnota FROM actactan T INTO CURSOR tact READWRITE
USE IN v_act
IF lnSucces > 0
lcSql = [select * from vrul_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_rul]
lcCursor = [v_rul]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
RETURN .F.
ENDIF
IF lnSucces > 0
UPDATE v_rul SET valoare = ROUND(IIF(cant<>0, cant, cante)*pret,m.gnPC) WHERE EMPTY(NVL(valoare,0))
UPDATE v_rul SET valtva = ROUND(IIF(cant<>0, cant, cante)*pret * (IIF(!EMPTY(NVL(proc_tva,0)), proc_tva, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtva,0))
UPDATE v_rul SET valoarev = ROUND(IIF(cant<>0, cant, cante)*pretv,m.gnPC) WHERE EMPTY(NVL(valoarev,0))
UPDATE v_rul SET valtvav = ROUND(IIF(cant<>0, cant, cante)*pretv * (IIF(!EMPTY(NVL(proc_tvav,0)), proc_tvav, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtvav,0))
SELECT *, ;
valoare + valtva AS valoarectva, ;
valoarev + valtvav AS valoarevctva ;
FROM v_rul ;
INTO CURSOR RUL_TEMP READWRITE
SELECT * FROM RUL_TEMP INTO CURSOR trul READWRITE
USE IN v_rul
lcSql = [select * from vrul_obinv_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_rul_obinv]
lcCursor = [v_rul_obinv]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
RETURN .F.
ENDIF
ENDIF
IF lnSucces > 0
UPDATE v_rul_obinv SET valoare = ROUND(IIF(cant<>0, cant, cante)*pret,m.gnPC) WHERE EMPTY(NVL(valoare,0))
UPDATE v_rul_obinv SET valtva = ROUND(IIF(cant<>0, cant, cante)*pret * (IIF(!EMPTY(NVL(proc_tva,0)), proc_tva, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtva,0))
UPDATE v_rul_obinv SET valoarev = ROUND(IIF(cant<>0, cant, cante)*pretv,m.gnPC) WHERE EMPTY(NVL(valoarev,0))
UPDATE v_rul_obinv SET valtvav = ROUND(IIF(cant<>0, cant, cante)*pretv * (IIF(!EMPTY(NVL(proc_tvav,0)), proc_tvav, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtvav,0))
SELECT *, ;
valoare + valtva AS valoarectva, ;
valoarev + valtvav AS valoarevctva ;
FROM v_rul_obinv ;
INTO CURSOR RUL_TEMP_OBINV READWRITE
SELECT * FROM RUL_TEMP_OBINV INTO CURSOR trul_obinv READWRITE
USE IN v_rul_obinv
ENDIF
ENDIF
RETURN .T.
ENDFUNC && IncarcaCursoareModificareNota
*!* creeaza cursorul tvanz gol (structura VANZARI redusa) - fallback la eroare Oracle sau cod/data lipsa
FUNCTION CreeazaCursorTvanzGol
IF Used('tvanz')
Use In tvanz
ENDIF
CREATE CURSOR tvanz (id_vanzare I, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2))
ENDFUNC && CreeazaCursorTvanzGol
*!* parametri: cod, nract, serie_act, dataact (din cursorul notei, ex. tact)
*!* incarca in tvanz randul din VANZARI al notei; cod singur nu e unic, de aceea filtrul cere tot setul
*!* tvanz ramane deschis READWRITE, cu 0 randuri daca nu s-a gasit sau la eroare Oracle
FUNCTION IncarcaVanzareNota
LPARAMETERS tnCod, tnNract, tcSerieAct, tdDataAct
LOCAL lcSql, lnSucces, lcSerieAct
IF Used('v_vanz')
Use In v_vanz
ENDIF
IF Empty(m.tnCod) OR Empty(m.tdDataAct)
CreeazaCursorTvanzGol()
RETURN .T.
ENDIF
lcSerieAct = Alltrim(Nvl(m.tcSerieAct,""))
lcSql = [select id_vanzare, tip, discount, total_fara_tva, total_tva, total_cu_tva from vanzari where cod = ] + Transform(m.tnCod) + ;
[ and Nvl(numar_act,-1) = ] + Transform(Nvl(m.tnNract,-1)) + ;
[ and Nvl(serie_act,'') = '] + m.lcSerieAct + [' and trunc(data_act) = to_date('] + Dtoc(m.tdDataAct,1) + [','YYYYMMDD') and sters = 0]
lnSucces = goExecutor.oExecute(lcSql,[v_vanz])
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
CreeazaCursorTvanzGol()
RETURN .T.
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
SELECT * FROM v_vanz INTO CURSOR tvanz READWRITE
USE IN v_vanz
RETURN .T.
ENDFUNC && IncarcaVanzareNota
*!* parametru: alias cu randurile notei (tact), cu campurile cod/nract/serie_act/dataact/sters
*!* incearca toate combinatiile distincte (cod, nract, serie_act, dataact) din alias (sters=0) pana
*!* gaseste un rand in VANZARI; lasa workarea si pozitia curenta neschimbate, .F. cu tvanz gol daca nu gaseste
FUNCTION IncarcaVanzareDinNota
LPARAMETERS tcAliasAct
LOCAL lnAreaOrigine, lnRecnoOrigine, llGasit
lnAreaOrigine = Select()
llGasit = .F.
IF Empty(m.tcAliasAct) OR !Used(m.tcAliasAct) OR Reccount(m.tcAliasAct) = 0
CreeazaCursorTvanzGol()
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN .F.
ENDIF
lnRecnoOrigine = Recno(m.tcAliasAct)
IF Used('tmp_triplete_pozvanz')
Use In tmp_triplete_pozvanz
ENDIF
*!* cod se ia tot din cursor, nu de pe randul curent - acesta poate fi la EOF dupa CalculeazaTotal
SELECT DISTINCT cod, nract, serie_act, dataact FROM (m.tcAliasAct) WHERE sters = 0 INTO CURSOR tmp_triplete_pozvanz READWRITE
SELECT tmp_triplete_pozvanz
SCAN
IncarcaVanzareNota(cod, nract, serie_act, dataact)
IF Reccount('tvanz') = 1
llGasit = .T.
EXIT
ENDIF
ENDSCAN
IF Used('tmp_triplete_pozvanz')
Use In tmp_triplete_pozvanz
ENDIF
IF !m.llGasit
CreeazaCursorTvanzGol()
ENDIF
IF Used(m.tcAliasAct)
IF m.lnRecnoOrigine > 0 AND m.lnRecnoOrigine <= Reccount(m.tcAliasAct)
Go (m.lnRecnoOrigine) In (m.tcAliasAct)
ELSE
*!* pozitia initiala era EOF (Recno() peste Reccount()) - se restaureaza tot la EOF
Go Bottom In (m.tcAliasAct)
Skip In (m.tcAliasAct)
ENDIF
ENDIF
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN m.llGasit
ENDFUNC && IncarcaVanzareDinNota
*!* creeaza cursorul tvd gol, cu structura view-ului VVANZARI_ARTICOLE
FUNCTION CreeazaCursorTvdGol
IF Used('tvd')
Use In tvd
ENDIF
CREATE CURSOR tvd (id_vanzare I, id_vanzare_det I, id_articol I, cantitate N(12,3), pret N(14,4), pret_cu_tva N(14,4), proc_tvav N(6,4), ;
discount_unitar N(14,4), id_gestiune I, cont C(20), id_valuta I, id_jtva_coloana I, serie C(20), explicatie C(60), ;
taxcode I, lot C(20), sters I, denumire C(100), codmat C(30), nume_gestiune C(60), nume_val C(20))
ENDFUNC && CreeazaCursorTvdGol
*!* parametru: id_vanzare
*!* incarca in tvd liniile active (sters=0) ale vanzarii, din VVANZARI_ARTICOLE
*!* tvd ramane deschis READWRITE, cu 0 randuri la eroare Oracle
FUNCTION IncarcaArticoleFactura
LPARAMETERS tnIdVanzare
LOCAL lcSql, lnSucces
IF Used('v_vd')
Use In v_vd
ENDIF
lcSql = [select * from vvanzari_articole where id_vanzare = ] + Transform(Nvl(m.tnIdVanzare,0)) + [ and sters = 0 order by id_vanzare_det]
lnSucces = goExecutor.oExecute(lcSql,[v_vd])
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
CreeazaCursorTvdGol()
RETURN .T.
ENDIF
IF Used('tvd')
Use In tvd
ENDIF
SELECT * FROM v_vd INTO CURSOR tvd READWRITE
USE IN v_vd
RETURN .T.
ENDFUNC && IncarcaArticoleFactura

View File

@@ -4618,7 +4618,9 @@ Procedure verificare_parteneri_istoric
Endif
Text To lcSql Noshow
select id, dataora, id_util, dataorav, id_utilv, cod_fiscal, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, stare, platitortvavies, util, utilv
select id, dataora, id_util, dataorav, id_utilv, cod_fiscal, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, stare, platitortvavies,
dataorav_anaf, tvaincasare, splittva, inactiv, data_inceput_scptva, data_sfarsit_scptva, data_anul_imp_scptva, data_inceput_tvainc, data_sfarsit_tvainc, data_inactivare, data_reactivare,
util, utilv
from vistoric_coduri_fiscale
where cod_fiscal = ?pcCodFiscal
Endtext

View File

@@ -1741,6 +1741,9 @@ Function ANAF_VerdictDinCursor
Addproperty(loResult, "dSfarsitScpTVA", Nvl(data_sfarsit_ScpTVA, {}))
Addproperty(loResult, "dAnulareScpTVA", Nvl(data_anul_imp_ScpTVA, {}))
Addproperty(loResult, "cMesajScpTVA", Nvl(mesaj_ScpTVA, ""))
Addproperty(loResult, "lTvaIncasare", Nvl(tvaincasare, .F.))
Addproperty(loResult, "dInceputTvaInc", Nvl(dataInceputTvaInc, {}))
Addproperty(loResult, "dSfarsitTvaInc", Nvl(dataSfarsitTvaInc, {}))
Else
If m.lnReccountTemp = 1 And Empty(denumire) And Nvl(cui, 0) = m.tnCuiCautat
tlNegasit = .T.
@@ -2669,10 +2672,10 @@ Define Class VerificareANAF As Custom
lnRecnoInit = Recno()
Scan For cui <> 0 And Left(Nvl(sursa, ''), 5) <> 'CACHE'
pcCodFiscal = Transform(cui)
pcFirma = Nvl(firma, '')
pcAdresa = Nvl(adresa, '')
pcJudet = Nvl(judet, '')
pcRegCom = Nvl(nrRegCom, '')
pcFirma = Alltrim(Nvl(firma, ''))
pcAdresa = Alltrim(Nvl(adresa, ''))
pcJudet = Alltrim(Nvl(judet, ''))
pcRegCom = Alltrim(Nvl(nrRegCom, ''))
pcCodPostal = ''
pcTelefon = ''
pcFax = ''

View File

@@ -371,7 +371,7 @@ Define Class ExportEFactura As Custom
lcTextAditional = m.lcTextAditional + Iif(!Empty(m.lcTextAditional), ' # ', '') + "Taxare inversa"
ENDIF
IF !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0
IF loDate.in_valuta = 1 AND !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0
lcTextAditional = m.lcTextAditional + Iif(!Empty(m.lcTextAditional), ' # ', '') + "Curs: " + ALLTRIM(STR(loDate.curs, 10,4)) + " RON/" + STRTRAN(ALLTRIM(Nvl(loDate.cValuta, '')),'EURO', 'EUR',1,1,1)
ENDIF

View File

@@ -2434,7 +2434,7 @@ DEFINE CLASS gridutils AS form
PROCEDURE copytoexcel
*!* LPARAMETERS tcXLSFile, tcSheet, tvWorkArea, tcExcelFieldList, tcTableFieldList, tcTableForExpr
#DEFINE ALPHANUMERICCHR "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz1234567890"
LOCAL lnCounter, loColumn, lcXLSFile, lcSheetName, lcAliasWas, lcGridAlias, ;
LOCAL lnCounter, lnOrder, laOrder, loColumn, lcXLSFile, lcSheetName, lcAliasWas, lcGridAlias, ;
lcExcelFieldList, lcTableFieldList, lcTableForExpression, loHeaderObject, ;
lcFileName, lcAction, lcPath, loExcelApp, loWorkBook, lcKeyName
m.lcXLSFile = "C:\" + SYS(2015) + ".xls"
@@ -2445,8 +2445,15 @@ DEFINE CLASS gridutils AS form
*!* m.lcTableForExpression = FILTER(this.gridobject.recordsource)
m.lcSheetName = "Sheet1"
STORE "" TO m.lcExcelFieldList, m.lcTableFieldList
*!* coloanele se exporta in ordinea de afisare din grid (ColumnOrder), nu in ordinea de creare
DIMENSION laOrder[MAX(THIS.gridobject.COLUMNCOUNT, 1), 2]
FOR m.lnCounter = 1 TO THIS.gridobject.COLUMNCOUNT
m.loColumn = THIS.gridobject.COLUMNS(m.lnCounter)
laOrder[m.lnCounter, 1] = THIS.gridobject.COLUMNS(m.lnCounter).COLUMNORDER
laOrder[m.lnCounter, 2] = m.lnCounter
ENDFOR
=ASORT(laOrder)
FOR m.lnOrder = 1 TO THIS.gridobject.COLUMNCOUNT
m.loColumn = THIS.gridobject.COLUMNS(laOrder[m.lnOrder, 2])
IF m.loColumn.VISIBLE AND m.loColumn.WIDTH > 0
m.loHeaderObject = m.loColumn.CONTROLS(1)
m.lcExcelFieldList = m.lcExcelFieldList + IIF(!EMPTY(m.lcExcelFieldList), ',', '') ;

View File

@@ -245,11 +245,11 @@ TRY
DO CreeazaIntrodc WITH 'introdc'
DO CreeazaIntrodc WITH 'introdc_sablon'
INSERT INTO introdc_sablon (scd, scc, cu_tva, ordine, id_set, participa_valuta, tip_rand, ;
id_jtva_coloana, ptva, explicatie_tva) ;
VALUES ('371', '401', 1, 1, 1, .T., 'B', 208, 21, 'ACH. INT. 21%')
id_jtva_coloana, ptva, explicatie_tva, taxcode) ;
VALUES ('371', '401', 1, 1, 1, .T., 'B', 208, 21, 'ACH. INT. 21%', 301204)
INSERT INTO introdc_sablon (scd, scc, cu_tva, ordine, id_set, participa_valuta, tip_rand, ;
id_jtva_coloana, ptva, explicatie_tva) ;
VALUES ('4426', '401', 1, 2, 1, .T., 'T', 209, 21, 'TVA ACH. INT. 21%')
id_jtva_coloana, ptva, explicatie_tva, taxcode) ;
VALUES ('4426', '401', 1, 2, 1, .T., 'T', 209, 21, 'TVA ACH. INT. 21%', 301204)
GO TOP IN introdc_sablon
DO CreeazaRulTemp
@@ -735,6 +735,34 @@ PROCEDURE VerificaRandD
lcMsg = 'FAIL ' + tcLabel + '-randD: nu exista rand tip_rand=D in introdc dupa sincronizeaza() (diferenta asteptata=' + TRANSFORM(lnSumaAsteptata) + ')'
ENDIF
DO R7Log WITH lcMsg
DO VerificaTaxCodeRandD WITH tcLabel
SELECT (lnSel)
ENDPROC
PROCEDURE VerificaTaxCodeRandD
*-- randul D (diferenta 6xx) nu are cod de taxa SAFT; randurile de baza si TVA il pastreaza.
LPARAMETERS tcLabel
LOCAL lnSel, lcMsg, lnTaxD, lnFaraTax
lnSel = SELECT()
SELECT introdc
LOCATE FOR tip_rand == 'D'
IF !FOUND()
DO R7Log WITH 'FAIL ' + tcLabel + '-randD-taxcode: nu exista rand tip_rand=D'
SELECT (lnSel)
RETURN
ENDIF
lnTaxD = NVL(taxcode, 0)
lnFaraTax = 0
SCAN FOR INLIST(tip_rand, 'B', 'S', 'T', 'G') AND EMPTY(NVL(taxcode, 0))
lnFaraTax = lnFaraTax + 1
ENDSCAN
IF EMPTY(lnTaxD) AND lnFaraTax = 0
lcMsg = 'PASS ' + tcLabel + '-randD-taxcode: randul D are taxcode gol, iar randurile B/S/T/G il pastreaza'
ELSE
lcMsg = 'FAIL ' + tcLabel + '-randD-taxcode: taxcode pe randul D=' + TRANSFORM(lnTaxD) + ;
' (astept 0), randuri B/S/T/G fara taxcode=' + TRANSFORM(lnFaraTax) + ' (astept 0)'
ENDIF
DO R7Log WITH lcMsg
SELECT (lnSel)
ENDPROC

View File

@@ -0,0 +1,72 @@
* test_incarca_articole_view.prg
* Smoke test izolat pentru IncarcaArticoleFactura pe vvanzari_articole (runda 2), inainte de a atinge omodificari.vc2.
* Regresie: id_vanzare=1050 (cod=1140888) -> 4 randuri, id_vanzare=1047 (cod=1140885) -> 2 randuri,
* coincide cu baza din rec_view_articole_vanzare.md. Verifica si coloana noua tvd.id_vanzare.
* Nu atinge Oracle in scriere. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_incarca_articole_view_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
DO verifica WITH 1050, 'cod=1140888', lcLog, 4
DO verifica WITH 1047, 'cod=1140885', lcLog, 2
*!* cursorul gol - structura cu 21 de campuri, inclusiv id_vanzare (nou)
CreeazaCursorTvdGol()
STRTOFILE('--- CreeazaCursorTvdGol ---' + CHR(13) + CHR(10) + ;
' Fcount(tvd) = ' + TRANSFORM(FCOUNT('tvd')) + ' (asteptat 21)' + CHR(13) + CHR(10) + ;
' are id_vanzare: ' + TRANSFORM(TYPE('tvd.id_vanzare') <> 'U') + CHR(13) + CHR(10) + ;
' ' + IIF(FCOUNT('tvd') == 21, 'PASS', 'FAIL') + CHR(13) + CHR(10), lcLog, 1)
IF Used('tvd')
Use In tvd
ENDIF
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
PROCEDURE verifica
LPARAMETERS tnIdVanzare, tcEticheta, tcLog, tnLiniiAsteptate
LOCAL lnLinii, lnIdVanzareCol
IncarcaArticoleFactura(tnIdVanzare)
lnLinii = Reccount('tvd')
lnIdVanzareCol = -1
IF lnLinii > 0
SELECT tvd
GO TOP
lnIdVanzareCol = tvd.id_vanzare
ENDIF
STRTOFILE('--- id_vanzare=' + TRANSFORM(tnIdVanzare) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' Reccount(tvd) = ' + TRANSFORM(lnLinii) + ' (asteptat ' + TRANSFORM(tnLiniiAsteptate) + ')' + CHR(13) + CHR(10) + ;
' tvd.id_vanzare pe primul rand = ' + TRANSFORM(lnIdVanzareCol) + ' (asteptat ' + TRANSFORM(tnIdVanzare) + ')' + CHR(13) + CHR(10) + ;
' ' + IIF(lnLinii == tnLiniiAsteptate AND (lnLinii == 0 OR lnIdVanzareCol == tnIdVanzare), 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
IF Used('tvd')
Use In tvd
ENDIF
ENDPROC
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,141 @@
* test_incarca_cursoare.prg
* Verifica IncarcaCursoareModificareNota (COMUN\programe\ofacturare_editare.prg) pe date reale:
* cod=1140888 - nota cu rulaje (non-regresie)
* cod=1140885 - nota FARA randuri in rul (productie/manopera, fara miscare de stoc)
* si pozitionarea in actactan din do_editare_factura (ofacturare_comun.vc2), pe cursoare sintetice.
* Nu atinge Oracle in scriere - doar SELECT-uri prin goExecutor. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_incarca_cursoare_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
STRTOFILE('gnAn=' + TRANSFORM(gnAn) + ' gnLuna=' + TRANSFORM(gnLuna) + CHR(13) + CHR(10), lcLog, 1)
DO verifica_cod WITH 1140888, 'A (regresie, cu rulaje)', lcLog
DO verifica_cod WITH 1140885, 'B (fara randuri in rul)', lcLog
DO verifica_pozitionare_actactan WITH 9999995, 'a) nota normala, un singur id_fact pe toate randurile', lcLog, 5000, 5000, 25010, 100, .T.
DO verifica_pozitionare_actactan WITH 9999996, 'b) prim rand INCASARE cu id_fact-1, Locate il sare', lcLog, 5000, 5000, 25010, 200, .T.
DO verifica_pozitionare_actactan WITH 9999997, 'c) nota fara randul cu id_fact cerut, cade pe Go Top', lcLog, 9999, 7000, 25011, 50, .F.
DO verifica_pozitionare_actactan WITH 9999998, 'd) lnIdFact=0 (aviz/transfer), direct Go Top', lcLog, 0, 8000, 25012, 10, .F.
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
* reproduce mecanica pozitionarii din do_editare_factura (ofacturare_comun.vc2): cauta in actactan
* randul cu id_fact = lnIdFact (cel citit din crsfacturi/VANZARI.ID_FACT); daca nu-l gaseste (sau
* lnIdFact e 0 - avize, transferuri), cade pe Go Top si preia id_fact de acolo. lnIdSet si
* lnIdFactD se citesc mereu de pe randul gasit (Locate sau Go Top).
PROCEDURE verifica_pozitionare_actactan
LPARAMETERS tnCod, tcEticheta, tcLog, tnIdFactIntrare, tnIdFactAsteptat, tnIdSetAsteptat, tnIdFactDAsteptat, tlGasitAsteptat
LOCAL lnIdFact, lnIdSet, lnIdFactD, llGasitRand, llOk
CREATE CURSOR actactan (id_fact N(9), id_factd N(9), id_set N(9))
DO CASE
CASE tnCod = 9999995
&& a) nota normala: toate randurile cu acelasi id_fact
INSERT INTO actactan VALUES (5000, 100, 25010)
INSERT INTO actactan VALUES (5000, 101, 25010)
CASE tnCod = 9999996
&& b) prim rand INCASARE, id_fact = id_fact-ul facturii - 1
INSERT INTO actactan VALUES (4999, 0, 25010)
INSERT INTO actactan VALUES (5000, 200, 25010)
CASE tnCod = 9999997
&& c) nota nu contine id_fact-ul cerut (document vechi)
INSERT INTO actactan VALUES (7000, 50, 25011)
CASE tnCod = 9999998
&& d) aviz/transfer, fara id_fact la intrare
INSERT INTO actactan VALUES (8000, 10, 25012)
ENDCASE
lnIdFact = tnIdFactIntrare
SELECT actactan
llGasitRand = .F.
IF lnIdFact > 0
LOCATE FOR NVL(id_fact, 0) = lnIdFact
llGasitRand = FOUND()
ENDIF
IF !llGasitRand
GO TOP
lnIdFact = id_fact
ENDIF
lnIdSet = id_set
lnIdFactD = id_factd
USE IN actactan
llOk = (lnIdFact == tnIdFactAsteptat AND lnIdSet == tnIdSetAsteptat AND ;
lnIdFactD == tnIdFactDAsteptat AND llGasitRand == tlGasitAsteptat)
STRTOFILE('--- pozitionare actactan, cod=' + TRANSFORM(tnCod) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' gasit rand = ' + TRANSFORM(llGasitRand) + ' (asteptat ' + TRANSFORM(tlGasitAsteptat) + ')' + CHR(13) + CHR(10) + ;
' id_fact = ' + TRANSFORM(lnIdFact) + ' (asteptat ' + TRANSFORM(tnIdFactAsteptat) + ')' + CHR(13) + CHR(10) + ;
' id_set = ' + TRANSFORM(lnIdSet) + ' (asteptat ' + TRANSFORM(tnIdSetAsteptat) + ')' + CHR(13) + CHR(10) + ;
' id_factd = ' + TRANSFORM(lnIdFactD) + ' (asteptat ' + TRANSFORM(tnIdFactDAsteptat) + ')' + CHR(13) + CHR(10) + ;
' ' + IIF(llOk, 'OK', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
ENDPROC
PROCEDURE verifica_cod
LPARAMETERS tnCod, tcEticheta, tcLog
LOCAL llOk, lcMsg, lnIdSetDistinct
llOk = IncarcaCursoareModificareNota(tnCod, gnAn, gnLuna, .F.)
lnIdSetDistinct = -1
IF Used('actactan') AND Reccount('actactan') > 0
SELECT Distinct id_set FROM actactan INTO CURSOR csr_idset_verif_test
lnIdSetDistinct = Reccount('csr_idset_verif_test')
USE IN csr_idset_verif_test
ENDIF
lcMsg = '--- cod=' + TRANSFORM(tnCod) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' IncarcaCursoareModificareNota => ' + TRANSFORM(llOk) + CHR(13) + CHR(10) + ;
' Reccount(actactan) = ' + TRANSFORM(IIF(Used('actactan'), Reccount('actactan'), -1)) + CHR(13) + CHR(10) + ;
' Reccount(tact) = ' + TRANSFORM(IIF(Used('tact'), Reccount('tact'), -1)) + CHR(13) + CHR(10) + ;
' id_set distincte in actactan = ' + TRANSFORM(lnIdSetDistinct) + CHR(13) + CHR(10) + ;
' Used(trul) = ' + TRANSFORM(Used('trul')) + ' Reccount(trul) = ' + TRANSFORM(IIF(Used('trul'), Reccount('trul'), -1)) + CHR(13) + CHR(10) + ;
' Used(trul_obinv) = ' + TRANSFORM(Used('trul_obinv')) + ' Reccount(trul_obinv) = ' + TRANSFORM(IIF(Used('trul_obinv'), Reccount('trul_obinv'), -1)) + CHR(13) + CHR(10)
STRTOFILE(lcMsg, tcLog, 1)
IF Used('actactan')
USE IN actactan
ENDIF
IF Used('tact')
USE IN tact
ENDIF
IF Used('rul_temp')
USE IN rul_temp
ENDIF
IF Used('trul')
USE IN trul
ENDIF
IF Used('rul_temp_obinv')
USE IN rul_temp_obinv
ENDIF
IF Used('trul_obinv')
USE IN trul_obinv
ENDIF
ENDPROC
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,154 @@
* test_incarca_vanzare_din_nota.prg
* Smoke test izolat pentru IncarcaVanzareDinNota (ofacturare_editare.prg), inainte de a atinge
* omodificari.vc2 runda 2. Verifica pe cazurile de regresie ale bugului "Go Top orb pe tact":
* cod=1137874/an=2009/luna=8 -> trebuie sa gaseasca id_vanzare=506 (azi, cu Go Top orb, da 0 randuri)
* cod=1139934/an=2021/luna=12 -> id_vanzare=882 (coliziune VANZARI.COD deja cunoscuta)
* plus regresie pe cazurile vechi: cod=1140888 -> id_vanzare=1050; cod=1125486 -> nu gaseste (tact fara VANZARI)
* plus cazul EOF: tact pozitionat deliberat la EOF (ca dupa CalculeazaTotal() din Show()) inainte de
* apel - dovedeste ca "cod" se ia din cursorul de triplete (SELECT DISTINCT), nu de pe randul curent
* Nu atinge Oracle in scriere - doar SELECT-uri prin goExecutor. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_incarca_vanzare_din_nota_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
DO verifica WITH 1137874, 2009, 8, 'blocant Go Top - prim rand INCASARE', lcLog, .T., 506
DO verifica WITH 1139934, 2021, 12, 'coliziune VANZARI.COD', lcLog, .T., 882
DO verifica WITH 1140888, (gnAn), (gnLuna), 'regresie runda 1 - factura normala', lcLog, .T., 1050
DO verifica WITH 1125486, 2008, 2, 'regresie runda 1 - fara VANZARI', lcLog, .F., 0
DO verifica_eof WITH 1137874, 2009, 8, lcLog, 506
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
* pozitioneaza tact deliberat la EOF (Go Bottom + Skip) inainte de IncarcaVanzareDinNota - dovedeste
* ca "cod" nu se mai citeste de pe randul curent al aliasului (corectia care a inlocuit Evaluate(alias.cod))
PROCEDURE verifica_eof
LPARAMETERS tnCod, tnAn, tnLuna, tcLog, tnIdVanzareAsteptat
LOCAL llOk, llGasit, lnIdVanzare, llEofInainte, llEofDupa
llOk = IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, .F.)
llGasit = .F.
lnIdVanzare = 0
llEofInainte = .F.
llEofDupa = .F.
IF llOk AND Used('tact')
SELECT tact
Go Bottom In tact
Skip In tact
llEofInainte = Eof('tact')
llGasit = IncarcaVanzareDinNota('tact')
llEofDupa = Eof('tact')
IF llGasit
lnIdVanzare = tvanz.id_vanzare
ENDIF
ENDIF
STRTOFILE('--- EOF pe tact, cod=' + TRANSFORM(tnCod) + ' [pozitionare la EOF inainte de apel] ---' + CHR(13) + CHR(10) + ;
' Eof(tact) inainte de apel = ' + TRANSFORM(llEofInainte) + ' (asteptat .T.)' + CHR(13) + CHR(10) + ;
' gasit = ' + TRANSFORM(llGasit) + ' (asteptat .T.)' + CHR(13) + CHR(10) + ;
' id_vanzare = ' + TRANSFORM(lnIdVanzare) + ' (asteptat ' + TRANSFORM(tnIdVanzareAsteptat) + ')' + CHR(13) + CHR(10) + ;
' Eof(tact) dupa apel (pozitia restaurata) = ' + TRANSFORM(llEofDupa) + ' (asteptat .T.)' + CHR(13) + CHR(10) + ;
' ' + IIF(llEofInainte AND llGasit AND lnIdVanzare == tnIdVanzareAsteptat AND llEofDupa, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
ENDPROC
PROCEDURE verifica
LPARAMETERS tnCod, tnAn, tnLuna, tcEticheta, tcLog, tlAsteptatGasit, tnIdVanzareAsteptat
LOCAL llOk, llGasit, lnIdVanzare, lcMsg, lnAreaOrigineTest, lcAliasOrigineTest
llOk = IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, .F.)
llGasit = .F.
lnIdVanzare = 0
lnAreaOrigineTest = 0
lcAliasOrigineTest = ''
IF llOk AND Used('tact')
SELECT tact
lnAreaOrigineTest = Select()
lcAliasOrigineTest = Alias()
llGasit = IncarcaVanzareDinNota('tact')
IF llGasit
lnIdVanzare = tvanz.id_vanzare
ENDIF
ENDIF
lcMsg = '--- cod=' + TRANSFORM(tnCod) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' IncarcaCursoareModificareNota => ' + TRANSFORM(llOk) + CHR(13) + CHR(10) + ;
' gasit = ' + TRANSFORM(llGasit) + ' (asteptat ' + TRANSFORM(tlAsteptatGasit) + ')' + CHR(13) + CHR(10) + ;
' id_vanzare = ' + TRANSFORM(lnIdVanzare) + ' (asteptat ' + TRANSFORM(tnIdVanzareAsteptat) + ')' + CHR(13) + CHR(10) + ;
' workarea restaurata la ' + TRANSFORM(lnAreaOrigineTest) + ': ' + TRANSFORM(Select() == lnAreaOrigineTest) + CHR(13) + CHR(10) + ;
' ' + IIF(llGasit == tlAsteptatGasit AND lnIdVanzare == tnIdVanzareAsteptat AND Select() == lnAreaOrigineTest, 'PASS', 'FAIL') + CHR(13) + CHR(10)
STRTOFILE(lcMsg, tcLog, 1)
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
ENDPROC
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,305 @@
* test_page3_articole.prg
* Verifica S4 runda 1+2 (PAGE3, view VVANZARI_ARTICOLE, pozitionare in tact, garda ROACONT/ROAGEST) pe date reale:
* - IncarcaVanzareNota/IncarcaArticoleFactura (ofacturare_editare.prg) direct, pe cod=1140888,
* cod=1140885 (au rand in VANZARI) si cod=1125486 (nota fara rand in VANZARI)
* - cazul de coliziune pe cod: cod=1139934 are 4 randuri VANZARI cu acelasi cod - verifica ca
* filtrul compus (cod+nract+serie_act+data_act) gaseste exact randul corect si NU gaseste
* nimic pentru un nract fara corespondent (evitarea unei potriviri gresite)
* - frm_modific2024 instantiat ca in do_editare_factura (Createobject+Show): PageCount ajunge 3
* pe documente cu rand in VANZARI, ramane 2 pe o nota fara VANZARI
* - regresie runda 2: cod=1137874/an=2009/luna=8 si cod=1139934/an=2021/luna=12, unde primul
* rand din tact e o INCASARE - Go Top orb (runda 1) rata id_vanzare, IncarcaVanzareDinNota il
* gaseste prin toate tripletele distincte (nract,serie_act,dataact) din tact
* - garda ROACONT/ROAGEST: cu ofacturare_editare.prg eliberat din SET PROCEDURE, Show() degradeaza
* curat la PageCount=2, fara eroare
* Nu atinge Oracle in scriere - doar SELECT-uri prin goExecutor. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_page3_articole_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
*!* OBLIGATORIU: test_init_env_auto:139 face "Set Classlib To omodificari Additive", iar SET PATH
*!* e pe D:\ROA\ROACONT\..., deci se incarca copia ROACONT a clasei (alt working copy, fara
*!* modificarile noastre). O eliberam si o reincarcam pe cea DE SUB TEST, cu cale completa -
*!* altfel Createobject valideaza cu totul alt fisier decat cel editat.
RELEASE CLASSLIB omodificari
SET CLASSLIB TO D:\ROA\ROAFACTURARE\COMUN\clase\omodificari.vcx ADDITIVE
*!* 1) IncarcaVanzareNota / IncarcaArticoleFactura direct, pe documente reale
*!* (gnAn)/(gnLuna) in paranteze = pasare PRIN VALOARE: DO ... WITH paseaza prin REFERINTA, iar o
*!* variabila pasata prin referinta devine invizibila sub numele ei propriu in procedura apelata -
*!* de acolo venea dialogul nativ "View Parameter: Enter the value for gnAn" (?gnAn din SQL passthrough)
DO verifica_vanzare_nota WITH 1140888, (gnAn), (gnLuna), 'A (factura, cu articole)', lcLog, .T., 1050, 1, 4
DO verifica_vanzare_nota WITH 1140885, (gnAn), (gnLuna), 'B (aviz/tip -12, cu rand in VANZARI)', lcLog, .T., 1047, -12, -1
DO verifica_vanzare_nota WITH 1125486, 2008, 2, 'C (nota fara rand in VANZARI)', lcLog, .F., 0, 0, -1
*!* 2) cazul de coliziune pe cod=1139934 (4 randuri VANZARI cu acelasi cod) - filtrul compus
DO verifica_coliziune_cod WITH lcLog
*!* 3) frm_modific2024 - PageCount pe factura reala (cod=1140888) si pe nota fara VANZARI (cod=1125486)
DO verifica_pagecount_form WITH 1140888, (gnAn), (gnLuna), 'A (factura reala)', lcLog, 3, .T., 1050
DO verifica_pagecount_form WITH 1125486, 2008, 2, 'C (nota fara VANZARI)', lcLog, 2, .F., 0
*!* 4) regresie runda 2 - blocantul "Go Top orb pe tact": prim rand din tact e o INCASARE, cu
*!* nract/serie_act/dataact diferite de randul facturii - Go Top orb (runda 1) rata id_vanzare
DO verifica_pagecount_form WITH 1137874, 2009, 8, 'D (Go Top orb - blocant runda 2)', lcLog, 3, .T., 506
DO verifica_pagecount_form WITH 1139934, 2021, 12, 'E (coliziune cod + Go Top orb)', lcLog, 3, .T., 882
*!* 5) garda ROACONT/ROAGEST: cu ofacturare_editare.prg eliberat, Show() nu mai gaseste garda si
*!* degradeaza curat la PageCount=2 - ultimul test, elibereaza procedura definitiv pentru restul rularii
DO verifica_garda_procedura_lipsa WITH 1140888, (gnAn), (gnLuna), lcLog
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
PROCEDURE verifica_vanzare_nota
LPARAMETERS tnCod, tnAn, tnLuna, tcEticheta, tcLog, tlAsteptatGasit, tnIdVanzareAsteptat, tnTipAsteptat, tnLiniiAsteptate
LOCAL llOk, lcMsg, llGasit, lnIdVanzare, lnTip, lnLinii, llIdOk, llTipOk, llLiniiOk
llOk = IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, .F.)
llGasit = .F.
lnIdVanzare = 0
lnTip = 0
lnLinii = -1
IF llOk AND Used('tact') AND Reccount('tact') > 0
Go Top In tact
IncarcaVanzareNota(tact.cod, tact.nract, tact.serie_act, tact.dataact)
IF Reccount('tvanz') = 1
llGasit = .T.
lnIdVanzare = tvanz.id_vanzare
lnTip = tvanz.tip
IncarcaArticoleFactura(lnIdVanzare)
lnLinii = Reccount('tvd')
ENDIF
ENDIF
llIdOk = IIF(tlAsteptatGasit, lnIdVanzare == tnIdVanzareAsteptat, .T.)
llTipOk = IIF(tlAsteptatGasit, lnTip == tnTipAsteptat, .T.)
llLiniiOk = IIF(tlAsteptatGasit AND tnLiniiAsteptate >= 0, lnLinii == tnLiniiAsteptate, .T.)
lcMsg = '--- cod=' + TRANSFORM(tnCod) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' IncarcaCursoareModificareNota => ' + TRANSFORM(llOk) + CHR(13) + CHR(10) + ;
' gasit in vanzari = ' + TRANSFORM(llGasit) + ' (asteptat ' + TRANSFORM(tlAsteptatGasit) + ')' + CHR(13) + CHR(10) + ;
' id_vanzare = ' + TRANSFORM(lnIdVanzare) + ' (asteptat ' + TRANSFORM(tnIdVanzareAsteptat) + ')' + CHR(13) + CHR(10) + ;
' tip = ' + TRANSFORM(lnTip) + ' (asteptat ' + TRANSFORM(tnTipAsteptat) + ')' + CHR(13) + CHR(10) + ;
' Reccount(tvd) = ' + TRANSFORM(lnLinii) + ' (asteptat ' + TRANSFORM(tnLiniiAsteptate) + ')' + CHR(13) + CHR(10) + ;
' ' + IIF(llGasit == tlAsteptatGasit AND llIdOk AND llTipOk AND llLiniiOk, 'PASS', 'FAIL') + CHR(13) + CHR(10)
STRTOFILE(lcMsg, tcLog, 1)
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
IF Used('tvd')
Use In tvd
ENDIF
ENDPROC
* cod=1139934 are 4 randuri active in VANZARI cu acelasi cod (verificat pe MARIUSM_AUTO):
* id_vanzare=882 numar_act=375/SSS, 883=24/PF, 884=25/PF, 885=26/PF - filtrul pe cod singur
* ar fi ambiguu; filtrul compus (cod+nract+serie_act+data_act) trebuie sa gaseasca exact
* randul cerut si sa NU gaseasca nimic pentru un nract fara corespondent in VANZARI (ACT are
* randuri cu nract=13 pe acelasi cod, fara VANZARI corespunzator)
PROCEDURE verifica_coliziune_cod
LPARAMETERS tcLog
LOCAL ldDataAct, llOk1, llOk2
ldDataAct = DATE(2021,12,31)
IncarcaVanzareNota(1139934, 375, 'SSS', ldDataAct)
llOk1 = (Reccount('tvanz') = 1 AND tvanz.id_vanzare == 882)
IF Used('tvanz')
Use In tvanz
ENDIF
IncarcaVanzareNota(1139934, 13, '', ldDataAct)
llOk2 = (Reccount('tvanz') = 0)
IF Used('tvanz')
Use In tvanz
ENDIF
STRTOFILE('--- coliziune cod=1139934 (4 randuri VANZARI cu acelasi cod) ---' + CHR(13) + CHR(10) + ;
' nract=375/SSS => gaseste id_vanzare=882: ' + IIF(llOk1, 'PASS', 'FAIL') + CHR(13) + CHR(10) + ;
' nract=13 (fara corespondent) => 0 randuri: ' + IIF(llOk2, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
ENDPROC
* instantiaza frm_modific2024 exact ca in do_editare_factura (ofacturare_comun.vc2:3781-3803):
* IncarcaCursoareModificareNota, rebuild tact cu coloana cu_Tva, Createobject+Show; verifica
* pgfArticole.PageCount si proprietatile de detectie dupa Show()
PROCEDURE verifica_pagecount_form
LPARAMETERS tnCod, tnAn, tnLuna, tcEticheta, tcLog, tnPageCountAsteptat, tlAreArticoleAsteptat, tnIdVanzareAsteptat
LOCAL llOk, lnIdSet, lnPageCount, llAreArticole, lnIdVanzare, loForm, llIdVanzareOk
llOk = IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, .F.)
lnPageCount = -1
llAreArticole = .F.
lnIdVanzare = 0
IF llOk AND Used('tact') AND Reccount('tact') > 0
Select a.*, Iif(Nvl(id_jtva_coloana,0)=0,0,1) As cu_Tva From tact a Into Cursor tact Readwrite
Go Top In tact
lnIdSet = tact.id_set
IF !Used('crsJtvaTemp')
update_jtva_coloane("", "crsJtvaTemp", 6)
ENDIF
Select tact
loForm = Createobject([frm_modific2024], lnIdSet)
loForm.WindowType = 0
loForm.Show()
lnPageCount = loForm.pgfArticole.PageCount
llAreArticole = loForm.lAreArticoleVanzari
lnIdVanzare = loForm.nIdVanzare
loForm.Release()
ENDIF
llIdVanzareOk = IIF(PCOUNT() >= 9, lnIdVanzare == tnIdVanzareAsteptat, .T.)
STRTOFILE('--- frm_modific2024, cod=' + TRANSFORM(tnCod) + ' [' + tcEticheta + '] ---' + CHR(13) + CHR(10) + ;
' PageCount = ' + TRANSFORM(lnPageCount) + ' (asteptat ' + TRANSFORM(tnPageCountAsteptat) + ')' + CHR(13) + CHR(10) + ;
' lAreArticoleVanzari = ' + TRANSFORM(llAreArticole) + ' (asteptat ' + TRANSFORM(tlAreArticoleAsteptat) + ')' + CHR(13) + CHR(10) + ;
' nIdVanzare = ' + TRANSFORM(lnIdVanzare) + IIF(PCOUNT() >= 9, ' (asteptat ' + TRANSFORM(tnIdVanzareAsteptat) + ')', '') + CHR(13) + CHR(10) + ;
' ' + IIF(lnPageCount == tnPageCountAsteptat AND llAreArticole == tlAreArticoleAsteptat AND llIdVanzareOk, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
IF Used('tvd')
Use In tvd
ENDIF
ENDPROC
* verifica garda ROACONT/ROAGEST: cu ofacturare_editare.prg eliberat din SET PROCEDURE, Show()
* trebuie sa degradeze curat la PageCount=2, fara eroare - ultimul test din suita, procedura
* ramane eliberata pentru restul rularii (QUIT urmeaza imediat)
PROCEDURE verifica_garda_procedura_lipsa
LPARAMETERS tnCod, tnAn, tnLuna, tcLog
LOCAL llOk, lnIdSet, lnPageCount, loForm, lcProcList, lnI, lcFile
llOk = IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, .F.)
lnPageCount = -1
IF llOk AND Used('tact') AND Reccount('tact') > 0
Select a.*, Iif(Nvl(id_jtva_coloana,0)=0,0,1) As cu_Tva From tact a Into Cursor tact Readwrite
Go Top In tact
lnIdSet = tact.id_set
IF !Used('crsJtvaTemp')
update_jtva_coloane("", "crsJtvaTemp", 6)
ENDIF
*!* simuleaza ROACONT/ROAGEST: reconstruieste lista de proceduri incarcate, fara ofacturare_editare.prg
*!* (VFP nu are un "release" pe un singur fisier din SET PROCEDURE - se inchid toate si se redeschid restul)
lcProcList = Set('Procedure')
SET PROCEDURE TO
FOR lnI = 1 TO GETWORDCOUNT(lcProcList, ',')
lcFile = ALLTRIM(GETWORDNUM(lcProcList, lnI, ','))
IF !EMPTY(lcFile) AND !("OFACTURARE_EDITARE" $ UPPER(lcFile))
SET PROCEDURE TO (lcFile) ADDITIVE
ENDIF
ENDFOR
Select tact
loForm = Createobject([frm_modific2024], lnIdSet)
loForm.WindowType = 0
loForm.Show()
lnPageCount = loForm.pgfArticole.PageCount
loForm.Release()
ENDIF
STRTOFILE('--- garda ofacturare_editare.prg lipsa, cod=' + TRANSFORM(tnCod) + ' ---' + CHR(13) + CHR(10) + ;
' PageCount = ' + TRANSFORM(lnPageCount) + ' (asteptat 2, ca pe ROACONT/ROAGEST)' + CHR(13) + CHR(10) + ;
' ' + IIF(lnPageCount == 2, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
ENDPROC
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,40 @@
* test_repro_izolat_gnan.prg
* Experimentul B (cerut de team-lead): reproduce izolat, FARA nimic din S4 - fara
* IncarcaCursoareModificareNota, fara frm_modific2024, fara PAGE3. Doar init mediu +
* update_jtva_coloane singura. Daca dialogul "View Parameter" apare si aici, blocajul nu are
* nicio legatura cu modificarea S4 - e o capcana preexistenta a harness-ului/mediului.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_repro_izolat_gnan_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_repro_izolat_gnan_errhandler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
STRTOFILE(' TYPE(gnAn)=' + TYPE('gnAn') + ' TRANSFORM(gnAn)=' + TRANSFORM(gnAn) + ;
' TYPE(gnLuna)=' + TYPE('gnLuna') + ' TRANSFORM(gnLuna)=' + TRANSFORM(gnLuna) + CHR(13) + CHR(10), lcLog, 1)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\updateserver.prg ADDITIVE
update_jtva_coloane("", "crsJtvaTemp", 6)
STRTOFILE(' dupa update_jtva_coloane: Used(crsJtvaTemp)=' + TRANSFORM(Used('crsJtvaTemp')) + ;
' Reccount=' + IIF(Used('crsJtvaTemp'), TRANSFORM(Reccount('crsJtvaTemp')), '(n/a)') + CHR(13) + CHR(10), lcLog, 1)
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
PROCEDURE test_repro_izolat_gnan_errhandler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,55 @@
* test_scan_workarea.prg
* Verificare punctuala: IncarcaVanzareDinNota foloseste SCAN...ENDSCAN pe tmp_triplete_pozvanz, iar
* corpul buclei (IncarcaVanzareNota) schimba workarea curenta (creeaza/selecteaza tvanz). SCAN in VFP
* poate sa nu tolereze schimbarea workareai curente in interiorul buclei (SKIP/EOF() implicit la
* ENDSCAN se aplica pe workarea CURENTA, nu neaparat pe cea de la inceputul SCAN). Testul forteaza
* explicit cazul cu 2+ triplete unde primul NU se potriveste, ca sa verifice daca a doua iteratie
* chiar se executa (nu doar "a mers din intamplare" pe cod=1137874 unde ordinea DISTINCT ar fi putut
* pune din start tripletul corect primul).
* Nu atinge Oracle in scriere. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_scan_workarea_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
*!* construieste un cursor "tact" sintetic cu 2 triplete, ordonate explicit ca primul (INCASARE,
*!* nract=99999 fara corespondent in VANZARI) sa iasa PRIMUL din SELECT DISTINCT (fara ORDER BY,
*!* dar inserat primul si numeric mai mic), iar al doilea sa fie tripletul real (cod=1137874,
*!* nract=5, serie=FFFFF, data=27.08.2009) care CHIAR exista in VANZARI (id_vanzare=506)
CREATE CURSOR tact (cod I, nract I, serie_act C(20), dataact D, sters I)
INSERT INTO tact (cod, nract, serie_act, dataact, sters) VALUES (1137874, 1, '', {}, 0)
INSERT INTO tact (cod, nract, serie_act, dataact, sters) VALUES (1137874, 5, 'FFFFF', DATE(2009,8,27), 0)
LOCAL llGasit, lnIdVanzare
llGasit = IncarcaVanzareDinNota('tact')
lnIdVanzare = IIF(llGasit, tvanz.id_vanzare, -1)
STRTOFILE('--- SCAN cu workarea schimbata in corp: 2 triplete, primul fara corespondent ---' + CHR(13) + CHR(10) + ;
' gasit = ' + TRANSFORM(llGasit) + ' (asteptat .T.)' + CHR(13) + CHR(10) + ;
' id_vanzare = ' + TRANSFORM(lnIdVanzare) + ' (asteptat 506)' + CHR(13) + CHR(10) + ;
' ' + IIF(llGasit AND lnIdVanzare == 506, 'PASS', 'FAIL') + CHR(13) + CHR(10), lcLog, 1)
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,27 @@
* test_set_procedure.prg
* Verifica strict formatul intors de SET("PROCEDURE") in VFP9, dupa mai multe
* SET PROCEDURE TO ... ADDITIVE succesive, ca sa se stabileasca garda din omodificari.vc2 Show().
* Nu atinge Oracle, nu deschide formulare. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_set_procedure_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
STRTOFILE('dupa 1 SET PROCEDURE: [' + SET('PROCEDURE') + ']' + CHR(13) + CHR(10), lcLog, 1)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\oproceduri_facturare.prg ADDITIVE
STRTOFILE('dupa 2 SET PROCEDURE (alt fisier ADDITIVE): [' + SET('PROCEDURE') + ']' + CHR(13) + CHR(10), lcLog, 1)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_stoc.prg ADDITIVE
STRTOFILE('dupa 3 SET PROCEDURE (al treilea fisier ADDITIVE): [' + SET('PROCEDURE') + ']' + CHR(13) + CHR(10), lcLog, 1)
LOCAL llGasit
llGasit = "OFACTURARE_EDITARE" $ UPPER(SET('PROCEDURE'))
STRTOFILE('contine OFACTURARE_EDITARE dupa 3 seturi: ' + TRANSFORM(llGasit) + CHR(13) + CHR(10), lcLog, 1)
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT

View File

@@ -0,0 +1,523 @@
* test_writeback_buton1.prg
* Test REAL de write-back pentru ramura buton=1 a lui frm_facturi.do_editare_factura
* (COMUN\clase\ofacturare_comun.vc2:3805-3840) - APROBAT explicit de Marius pe 08.08.2026 sa
* scrie in schema de dev MARIUSM_AUTO@ROA_CENTRAL (nu doar sa citeasca).
*
* Document consumat: cod=1140886, id_vanzare=1048 (factura tip 1, 07-AUG-26, total_cu_tva=302.51,
* 1 linie in VANZARI_DETALII, 5 randuri in ACT, id_set=25010, id_fact=8009658, 1 rand in RUL).
* NU foloseste cod=1140888/1140885 (baze de regresie ale test_incarca_cursoare.prg).
*
* Harness, nu apel direct al metodei: nu instantiaza frm_facturi si NU mai instantiaza
* frm_modific2024 deloc (incercarea initiala s-a blocat la Createobject/Show pe un dialog nativ
* Windows "Open" - cursor/tabela lipsa in acest mediu minimal, capcana j din testare-ui-vfp.md -
* fara legatura cu calea de scriere care se testeaza aici). In loc, harnessul:
* 1) reproduce exact starea de cursoare pe care do_editare_factura o lasa inainte de
* Createobject('frm_modific2024',...) (IncarcaCursoareModificareNota, functia reala din
* ofacturare_editare.prg);
* 2) seteaza buton=1 direct (SARE peste inainte_de_do_termin - vezi ATENTIE mai jos);
* 3) ruleaza LITERAL codul ramurii buton=1 (copiat din ofacturare_comun.vc2:3805-3840).
* Thisform.do_deschide_tranzactie/do_inchide_tranzactie (mostenite nemodificate din _frm_base,
* fara dependinta de vreo clasa de formular anume) sunt reproduse local, INLINE, dupa codul din
* _frm_base.vc2:252-302 - ocolesc si instantierea unui _frmbase generic, ca sa nu riste acelasi
* fel de blocaj vazut la frm_modific2024.
*
* ATENTIE - ce NU acopera acest test: validarea din inainte_de_do_termin
* (omodificari.vc2:13357-13549 - verificare_note_contabile, echilibru 4426-4428,
* VerificaAvertizareExigibilizareTVA) si comportamentul real al formularului la butonul
* "Terminat". Testul demonstreaza ca LANTUL DE SCRIERE merge, nu ca utilizatorul ajunge la el
* prin UI - cele doua nu trebuie confundate la interpretarea rezultatului.
*
* Mediu: test_init_env_auto.prg (bootstrap ROACONT, conexiune reala MARIUSM_AUTO) - acelasi mediu
* folosit deja cu succes de test_incarca_cursoare.prg si test_page3_articole.prg. oscrie_in_fisiere.prg
* e incarcat explicit din COMUN-ul ROAFACTURARE (nu cel auto-rezolvat din calea ROACONT) ca sa
* ruleze exact fisierul pe care il ruleaza aplicatia.
*
* Ruleaza 2 treceri pe acelasi document (cod-ul se schimba dupa fiecare salvare, se recitesc din
* VANZARI la fiecare trecere):
* TEST 1 - salvare "goala" (fara nicio modificare in tact) - proba ca lantul chiar scrie.
* TEST 2 - modifica explicatia unui rand ACT inainte de salvare - proba ca modificarea ajunge.
*
* Nu atinge .PJX/.PJT/.exe, nu modifica cod aplicatie. QUIT la final.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_writeback_buton1_log.txt'
STRTOFILE('start ' + TTOC(DATETIME()) + CHR(13) + CHR(10), lcLog)
PUBLIC gcErrLog
gcErrLog = lcLog
ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
*-- mock amessagebox INCARCAT PRIMUL (inaintea lantului din test_init_env_auto, care incarca
*-- amessagebox real) - la nume duplicat de procedura, castiga fisierul cautat PRIMUL (testare-ui-vfp.md, capcana g)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg ADDITIVE
DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), lcLog, 1)
QUIT
ENDIF
*-- verificare ca mock-ul chiar umbreste amessebox real (altfel un dialog real ar bloca headless)
LOCAL lnVerifMock
lnVerifMock = amessagebox('verificare mock', 4+32, 'test')
STRTOFILE('verificare mock amessagebox = ' + TRANSFORM(lnVerifMock) + ;
IIF(lnVerifMock = 6, ' (OK, mock activ)', ' (ATENTIE: real amessagebox activ, risc de blocaj)') + CHR(13) + CHR(10), lcLog, 1)
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE
SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\oscrie_in_fisiere.prg ADDITIVE
IF TYPE('gnPC') <> 'N'
PUBLIC gnPC
gnPC = 2
ENDIF
*-- capteaza textul ultimului amessagebox mocked (mock_amessagebox.prg, liniile 13-14/23-26) -
*-- necesar ca sa vedem CE mesaj de eroare arunca oscrie_in_fisiere.prg pe caile de esec
PUBLIC gcMockUltimMesaj, gnMockUltimTip
gcMockUltimMesaj = ''
gnMockUltimTip = 0
STRTOFILE('gnAn=' + TRANSFORM(gnAn) + ' gnLuna=' + TRANSFORM(gnLuna) + ' gcS=' + gcS + CHR(13) + CHR(10), lcLog, 1)
DO test_editare_writeback WITH 1048, .F., 'TEST 1: salvare fara nicio modificare', lcLog
DO test_editare_writeback WITH 1048, .T., 'TEST 2: modificare explicatie pe un rand ACT', lcLog
STRTOFILE('done ' + TTOC(DATETIME()) + CHR(13) + CHR(10), lcLog, 1)
QUIT
*-- executa SELECT-ul agregat prin goExecutor si intoarce lnSucces; NU citi campurile cursorului
*-- decat dupa ce ai verificat lnSucces > 0 (IIF() evalueaza ambele ramuri, ar da eroare pe alias lipsa)
PROCEDURE ExecAgg
LPARAMETERS tcSql, tcCursor
LOCAL lnQ
IF USED(tcCursor)
USE IN (tcCursor)
ENDIF
lnQ = goExecutor.oExecute(tcSql, tcCursor)
RETURN lnQ
ENDPROC
*-- logheaza si RESETEAZA gcMockUltimMesaj/goExecutor.cEroare - reseteaza ca sa nu se confunde
*-- mesajul de la un pas cu mesajul (sau lipsa lui) de la pasul urmator
PROCEDURE LogMockSiEroare
LPARAMETERS tcEticheta, tcLog
STRTOFILE(' [' + tcEticheta + '] gcMockUltimMesaj=[' + ALLTRIM(gcMockUltimMesaj) + '] ' + ;
'goExecutor.cEroare=[' + ALLTRIM(TRANSFORM(NVL(goExecutor.cEroare, ''))) + ']' + CHR(13) + CHR(10), tcLog, 1)
gcMockUltimMesaj = ''
ENDPROC
*-- reproduce _frm_base.vc2:252-265 (do_deschide_tranzactie) fara sa instantieze niciun formular
PROCEDURE MyDeschideTranzactie
LOCAL llReturn, lnSuccesLocal
IF TYPE('goExecutor') = 'O'
goExecutor.oExecuta([select * from dual])
ENDIF
lnSuccesLocal = SQLSetprop(gnHandle, "Transactions", 2)
llReturn = IIF(lnSuccesLocal < 0, .F., .T.)
RETURN llReturn
ENDPROC
*-- reproduce _frm_base.vc2:279-302 (do_inchide_tranzactie) fara sa instantieze niciun formular
PROCEDURE MyInchideTranzactie
LPARAMETERS tnTip
LOCAL llReturn, lnSuccesLocal
IF tnTip = 1
lnSuccesLocal = SQLCOMMIT(gnHandle)
ELSE
lnSuccesLocal = SQLROLLBACK(gnHandle)
ENDIF
IF lnSuccesLocal < 0
llReturn = .F.
ELSE
lnSuccesLocal = SQLSetprop(gnHandle, "Transactions", 1)
llReturn = IIF(lnSuccesLocal < 0, .F., .T.)
ENDIF
RETURN llReturn
ENDPROC
PROCEDURE test_editare_writeback
LPARAMETERS tnIdVanzare, tlModificaLinie, tcEticheta, tcLog
*-- pnAn/pnLuna/lnCod/lnIdFact PRIVATE (nu LOCAL), identic cu declararea reala
*-- (ofacturare_comun.vc2:3742) - finalizeaza_modificare_nota le foloseste ca bind-variabile
*-- ?pnLuna/?pnAn in interiorul lui goExecutor.oExecuta, care le cere vizibile PRIVATE pe stiva
PRIVATE pnAn, pnLuna, lnCod, lnIdFact
LOCAL lnSters, llEProforma
LOCAL lnIdSet, lnIdFactD, lnSucces, llGasitRand
LOCAL lcSql, lnQ
LOCAL lnActBeforeCnt, lnActBeforeSuma, lnRulBeforeCnt, lnRulObinvBeforeCnt
LOCAL lnVdCnt, lnVdSumaPret, lnVdSumaPretCuTva
LOCAL lcExplicatieVeche, lcExplicatieNoua
LOCAL lnVzCodBefore, lnVzStersBefore, lnVzTotalFaraTvaBefore, lnVzTotalTvaBefore, lnVzTotalCuTvaBefore, lnVzDiscountBefore
STRTOFILE(CHR(13) + CHR(10) + '========== ' + tcEticheta + ' (id_vanzare=' + TRANSFORM(tnIdVanzare) + ') ==========' + CHR(13) + CHR(10), tcLog, 1)
*-- 1) starea curenta din VANZARI (cod-ul se poate schimba fata de trecerea anterioara)
lcSql = [select cod, sters, id_fact, eproforma, total_fara_tva, total_tva, total_cu_tva, discount, ] + ;
[extract(year from data_act) as anact, extract(month from data_act) as lunaact from vanzari where id_vanzare = ] + TRANSFORM(tnIdVanzare)
lnQ = ExecAgg(lcSql, 'v_vanzare_curenta')
IF lnQ <= 0 OR RECCOUNT('v_vanzare_curenta') <> 1
STRTOFILE('FAIL: VANZARI id_vanzare=' + TRANSFORM(tnIdVanzare) + ' - lnQ=' + TRANSFORM(lnQ) + ;
' reccount=' + IIF(lnQ > 0, TRANSFORM(RECCOUNT('v_vanzare_curenta')), '?') + ;
' cEroare=[' + ALLTRIM(TRANSFORM(NVL(goExecutor.cEroare, ''))) + ']' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
SELECT v_vanzare_curenta
lnCod = cod
lnSters = sters
lnIdFact = id_fact
llEProforma = (eproforma = 1)
pnAn = anact
pnLuna = lunaact
lnVzCodBefore = cod
lnVzStersBefore = sters
lnVzTotalFaraTvaBefore = total_fara_tva
lnVzTotalTvaBefore = total_tva
lnVzTotalCuTvaBefore = total_cu_tva
lnVzDiscountBefore = discount
USE IN v_vanzare_curenta
STRTOFILE(' VANZARI inainte: cod=' + TRANSFORM(lnCod) + ' sters=' + TRANSFORM(lnSters) + ' id_fact=' + TRANSFORM(lnIdFact) + ;
' an/luna=' + TRANSFORM(pnAn) + '/' + TRANSFORM(pnLuna) + ' total_cu_tva=' + TRANSFORM(lnVzTotalCuTvaBefore) + CHR(13) + CHR(10), tcLog, 1)
*-- 2) garzi (replica do_editare_factura, fara UI)
IF lnSters = 1
STRTOFILE(' SKIP: document deja sters' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
IF llEProforma
STRTOFILE(' SKIP: proforma' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
IF (pnAn*12) + pnLuna <> (gnAn*12) + gnLuna
STRTOFILE(' SKIP: nu e luna curenta (document ' + TRANSFORM(pnAn) + '/' + TRANSFORM(pnLuna) + ', curenta ' + TRANSFORM(gnAn) + '/' + TRANSFORM(gnLuna) + ')' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
IF EsteInEFactura(lnIdFact)
STRTOFILE(' SKIP: trimis in eFactura' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
*-- 3) instantaneu INAINTE: ACT / RUL / RUL_OBINV (pe cod-ul curent) + VANZARI_DETALII
lcSql = [select count(*) as cnt, sum(suma) as totsuma from vact_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCod)
lnQ = ExecAgg(lcSql, 'v_act_before')
IF lnQ > 0
lnActBeforeCnt = v_act_before.cnt
lnActBeforeSuma = NVL(v_act_before.totsuma, 0)
USE IN v_act_before
ELSE
lnActBeforeCnt = -1
lnActBeforeSuma = -1
ENDIF
lcSql = [select count(*) as cnt from vrul_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCod)
lnQ = ExecAgg(lcSql, 'v_rul_before')
IF lnQ > 0
lnRulBeforeCnt = v_rul_before.cnt
USE IN v_rul_before
ELSE
lnRulBeforeCnt = -1
ENDIF
lcSql = [select count(*) as cnt from vrul_obinv_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCod)
lnQ = ExecAgg(lcSql, 'v_rulobinv_before')
IF lnQ > 0
lnRulObinvBeforeCnt = v_rulobinv_before.cnt
USE IN v_rulobinv_before
ELSE
lnRulObinvBeforeCnt = -1
ENDIF
lcSql = [select count(*) as cnt, sum(cantitate) as sumcant, sum(pret) as sumpret, sum(pret_cu_tva) as sumpretcutva ] + ;
[from vanzari_detalii where sters = 0 and id_vanzare = ] + TRANSFORM(tnIdVanzare)
lnQ = ExecAgg(lcSql, 'v_vd_before')
IF lnQ > 0
lnVdCnt = v_vd_before.cnt
lnVdSumaPret = NVL(v_vd_before.sumpret, 0)
lnVdSumaPretCuTva = NVL(v_vd_before.sumpretcutva, 0)
USE IN v_vd_before
ELSE
lnVdCnt = -1
lnVdSumaPret = -1
lnVdSumaPretCuTva = -1
ENDIF
STRTOFILE(' INAINTE: ACT cnt=' + TRANSFORM(lnActBeforeCnt) + ' suma=' + TRANSFORM(lnActBeforeSuma) + ;
' RUL cnt=' + TRANSFORM(lnRulBeforeCnt) + ' RUL_OBINV cnt=' + TRANSFORM(lnRulObinvBeforeCnt) + ;
' VANZARI_DETALII cnt=' + TRANSFORM(lnVdCnt) + ' sum(pret)=' + TRANSFORM(lnVdSumaPret) + ' sum(pret_cu_tva)=' + TRANSFORM(lnVdSumaPretCuTva) + CHR(13) + CHR(10), tcLog, 1)
*-- 4) IncarcaCursoareModificareNota (functia reala, ofacturare_editare.prg)
IF !IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.)
STRTOFILE(' FAIL: IncarcaCursoareModificareNota a esuat (eroare Oracle)' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
IF RECCOUNT('actactan') = 0
STRTOFILE(' FAIL: nu exista nota contabila (Reccount(actactan)=0)' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
*-- 5) pozitionare id_fact/id_set/id_factd - copiat identic din do_editare_factura
*-- (ofacturare_comun.vc2:3785-3797; garda id_set scoasa - decizia 24, cod curent nu o mai are)
SELECT actactan
llGasitRand = .F.
IF lnIdFact > 0
LOCATE FOR NVL(id_fact, 0) = lnIdFact
llGasitRand = FOUND()
ENDIF
IF !llGasitRand
GO TOP
lnIdFact = id_fact
ENDIF
lnIdSet = id_set
lnIdFactD = NVL(id_factd, 0)
STRTOFILE(' pozitionare actactan: gasit=' + TRANSFORM(llGasitRand) + ' id_fact=' + TRANSFORM(lnIdFact) + ;
' id_set=' + TRANSFORM(lnIdSet) + ' id_factd=' + TRANSFORM(lnIdFactD) + CHR(13) + CHR(10), tcLog, 1)
SELECT a.*, IIF(NVL(id_jtva_coloana, 0) = 0, 0, 1) AS cu_Tva FROM tact a INTO CURSOR tact READWRITE
*-- 6) TEST 2: modifica un camp simplu si verificabil (explicatia) INAINTE de salvare
lcExplicatieVeche = ''
lcExplicatieNoua = ''
IF tlModificaLinie
SELECT tact
LOCATE FOR !EMPTY(ALLTRIM(NVL(explicatia, '')))
IF FOUND()
lcExplicatieVeche = ALLTRIM(explicatia)
lcExplicatieNoua = lcExplicatieVeche + ' (test writeback)'
REPLACE explicatia WITH lcExplicatieNoua
STRTOFILE(' modific tact.explicatia: [' + lcExplicatieVeche + '] -> [' + lcExplicatieNoua + ']' + CHR(13) + CHR(10), tcLog, 1)
ELSE
STRTOFILE(' ATENTIE: nu am gasit niciun rand cu explicatia completata, testul nu modifica nimic real' + CHR(13) + CHR(10), tcLog, 1)
ENDIF
ENDIF
*-- 7) frm_modific2024 OCOLIT COMPLET (a blocat Createobject/Show pe dialog nativ "Open" -
*-- vezi antetul fisierului). buton=1 fortat direct - inainte_de_do_termin NU se executa.
buton = 1
STRTOFILE(' frm_modific2024 ocolit: buton=1 fortat direct, inainte_de_do_termin SARIT' + CHR(13) + CHR(10), tcLog, 1)
*-- 8) ramura buton=1 din do_editare_factura (ofacturare_comun.vc2:3805-3840), copiata identic;
*-- Thisform.do_deschide_tranzactie/do_inchide_tranzactie sunt reproduse INLINE mai jos
*-- (MyDeschideTranzactie/MyInchideTranzactie, dupa _frm_base.vc2:252-302) - fara sa instantieze
*-- niciun formular, ca sa nu riste acelasi blocaj vazut la frm_modific2024
lnSucces = 0
TRY
STRTOFILE(' [chk] inainte de MyDeschideTranzactie()' + CHR(13) + CHR(10), tcLog, 1)
IF MyDeschideTranzactie()
STRTOFILE(' [chk] MyDeschideTranzactie() => .T., inainte de OSCRIE_IN_FISIERE(2,...)' + CHR(13) + CHR(10), tcLog, 1)
SELECT actactan
lnSucces = OSCRIE_IN_FISIERE(2, .T., .T.)
STRTOFILE(' [chk] OSCRIE_IN_FISIERE(2,...) => ' + TRANSFORM(lnSucces) + CHR(13) + CHR(10), tcLog, 1)
LogMockSiEroare('dupa OSCRIE_IN_FISIERE(2,...)', tcLog)
IF lnSucces > 0
IF USED('actactan')
USE IN actactan
ENDIF
SELECT tact
REPLACE id_jtva_coloana WITH NULL, proc_tva WITH 0 FOR cu_Tva = 0
SELECT * FROM tact INTO CURSOR actactan READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0
IF USED('rul_temp')
USE IN rul_temp
ENDIF
SELECT * FROM trul INTO CURSOR RUL_TEMP READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0
IF USED('rul_temp_obinv')
USE IN rul_temp_obinv
ENDIF
SELECT * FROM trul_obinv INTO CURSOR RUL_TEMP_OBINV READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0
STRTOFILE(' [chk] cursoare rebuild OK, inainte de OSCRIE_IN_FISIERE(0,...)' + CHR(13) + CHR(10), tcLog, 1)
lnSucces = OSCRIE_IN_FISIERE(0, .T., .T.)
STRTOFILE(' [chk] OSCRIE_IN_FISIERE(0,...) => ' + TRANSFORM(lnSucces) + CHR(13) + CHR(10), tcLog, 1)
LogMockSiEroare('dupa OSCRIE_IN_FISIERE(0,...)', tcLog)
ENDIF
IF lnSucces > 0
STRTOFILE(' [chk] inainte de pack_contafin.finalizeaza_modificare_nota' + CHR(13) + CHR(10), tcLog, 1)
lcSql = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,Null,] + ALLTRIM(STR(lnIdSet)) + [,] + ;
ALLTRIM(STR(lnCod)) + [,] + ALLTRIM(STR(lnIdFact)) + [,] + ALLTRIM(STR(lnIdFactD)) + [,?gnIdUtil); end;]
STRTOFILE(' [chk] SQL finalizeaza_modificare_nota = [' + lcSql + ']' + CHR(13) + CHR(10), tcLog, 1)
lnSucces = IIF(goExecutor.oExecuta(lcSql), 1, -1)
STRTOFILE(' [chk] finalizeaza_modificare_nota => ' + TRANSFORM(lnSucces) + CHR(13) + CHR(10), tcLog, 1)
LogMockSiEroare('dupa finalizeaza_modificare_nota', tcLog)
ENDIF
STRTOFILE(' lnSucces dupa lant scriere = ' + TRANSFORM(lnSucces) + CHR(13) + CHR(10), tcLog, 1)
STRTOFILE(' [chk] inainte de MyInchideTranzactie' + CHR(13) + CHR(10), tcLog, 1)
IF MyInchideTranzactie(IIF(lnSucces < 0, 2, 1))
STRTOFILE(' tranzactie inchisa cu ' + IIF(lnSucces < 0, 'ROLLBACK', 'COMMIT') + CHR(13) + CHR(10), tcLog, 1)
ELSE
STRTOFILE(' FAIL la do_inchide_tranzactie' + CHR(13) + CHR(10), tcLog, 1)
ENDIF
ELSE
STRTOFILE(' FAIL: do_deschide_tranzactie a esuat' + CHR(13) + CHR(10), tcLog, 1)
ENDIF
CATCH TO loExc
STRTOFILE(' EXCEPTIE in lantul de scriere: ' + TRANSFORM(loExc.ErrorNo) + ' [' + loExc.Message + '] ' + ;
loExc.Procedure + ':' + TRANSFORM(loExc.LineNo) + ' -> ROLLBACK' + CHR(13) + CHR(10), tcLog, 1)
lnSucces = -99
MyInchideTranzactie(2)
ENDTRY
IF USED('actactan')
USE IN actactan
ENDIF
IF USED('tact')
USE IN tact
ENDIF
IF USED('rul_temp')
USE IN rul_temp
ENDIF
IF USED('trul')
USE IN trul
ENDIF
IF USED('rul_temp_obinv')
USE IN rul_temp_obinv
ENDIF
IF USED('trul_obinv')
USE IN trul_obinv
ENDIF
IF lnSucces <= 0
STRTOFILE(' TEST FAIL - scrierea nu s-a produs (lnSucces=' + TRANSFORM(lnSucces) + '), fara verificari after' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
*-- 9) instantaneu DUPA + verificarile 1-5 cerute
LOCAL lnCodNou, lnVzStersAfter, llV3ok
lcSql = [select cod, sters, id_fact, total_fara_tva, total_tva, total_cu_tva, discount from vanzari where id_vanzare = ] + TRANSFORM(tnIdVanzare)
lnQ = ExecAgg(lcSql, 'v_vanzare_dupa')
IF lnQ <= 0 OR RECCOUNT('v_vanzare_dupa') <> 1
STRTOFILE(' FAIL: VANZARI dupa - nu am gasit exact 1 rand' + CHR(13) + CHR(10), tcLog, 1)
RETURN
ENDIF
SELECT v_vanzare_dupa
lnCodNou = cod
lnVzStersAfter = sters
llV3ok = (lnCodNou <> lnVzCodBefore) AND (lnVzStersAfter = 0) AND (id_fact == lnIdFact) AND ;
(ABS(total_fara_tva - lnVzTotalFaraTvaBefore) < 0.01) AND (ABS(total_tva - lnVzTotalTvaBefore) < 0.01) AND ;
(ABS(total_cu_tva - lnVzTotalCuTvaBefore) < 0.01) AND (ABS(discount - lnVzDiscountBefore) < 0.01)
STRTOFILE(' [3] VANZARI dupa: cod=' + TRANSFORM(lnCodNou) + ' (era ' + TRANSFORM(lnVzCodBefore) + ') sters=' + TRANSFORM(lnVzStersAfter) + ;
' id_fact=' + TRANSFORM(id_fact) + ' total_cu_tva=' + TRANSFORM(total_cu_tva) + ' -> ' + IIF(llV3ok, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
USE IN v_vanzare_dupa
*-- [1] ACT: randurile vechi STERS=1 pe cod vechi; randuri noi pe cod nou, acelasi id_fact, aceeasi suma (daca nemodificat)
LOCAL lnActVechiCnt, lnActVechiSumSters, lnActNouCnt, lnActNouSuma, llV1ok
lcSql = [select count(*) as cnt, sum(sters) as sumsters from vact_tot where an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnVzCodBefore)
lnQ = ExecAgg(lcSql, 'v_act_vechi_dupa')
IF lnQ > 0
lnActVechiCnt = v_act_vechi_dupa.cnt
lnActVechiSumSters = NVL(v_act_vechi_dupa.sumsters, 0)
USE IN v_act_vechi_dupa
ELSE
lnActVechiCnt = -1
lnActVechiSumSters = -1
ENDIF
lcSql = [select count(*) as cnt, sum(suma) as totsuma from vact_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCodNou)
lnQ = ExecAgg(lcSql, 'v_act_nou_dupa')
IF lnQ > 0
lnActNouCnt = v_act_nou_dupa.cnt
lnActNouSuma = NVL(v_act_nou_dupa.totsuma, 0)
USE IN v_act_nou_dupa
ELSE
lnActNouCnt = -1
lnActNouSuma = -1
ENDIF
llV1ok = (lnActVechiCnt = lnActBeforeCnt) AND (lnActVechiSumSters = lnActVechiCnt) AND (lnActNouCnt = lnActBeforeCnt) AND ;
(IIF(tlModificaLinie, .T., ABS(lnActNouSuma - lnActBeforeSuma) < 0.01))
STRTOFILE(' [1] ACT: vechi(cod=' + TRANSFORM(lnVzCodBefore) + ') cnt=' + TRANSFORM(lnActVechiCnt) + ' toate sters=' + TRANSFORM(lnActVechiSumSters = lnActVechiCnt) + ;
'; nou(cod=' + TRANSFORM(lnCodNou) + ') cnt=' + TRANSFORM(lnActNouCnt) + ' suma=' + TRANSFORM(lnActNouSuma) + ;
' (era ' + TRANSFORM(lnActBeforeSuma) + ') -> ' + IIF(llV1ok, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
*-- [2] RUL: acelasi tipar (daca documentul are randuri RUL)
LOCAL lnRulVechiCnt, lnRulVechiSumSters, lnRulNouCnt, llV2ok
lcSql = [select count(*) as cnt, sum(sters) as sumsters from vrul_tot where an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnVzCodBefore)
lnQ = ExecAgg(lcSql, 'v_rul_vechi_dupa')
IF lnQ > 0
lnRulVechiCnt = v_rul_vechi_dupa.cnt
lnRulVechiSumSters = NVL(v_rul_vechi_dupa.sumsters, 0)
USE IN v_rul_vechi_dupa
ELSE
lnRulVechiCnt = -1
lnRulVechiSumSters = -1
ENDIF
lcSql = [select count(*) as cnt from vrul_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCodNou)
lnQ = ExecAgg(lcSql, 'v_rul_nou_dupa')
IF lnQ > 0
lnRulNouCnt = v_rul_nou_dupa.cnt
USE IN v_rul_nou_dupa
ELSE
lnRulNouCnt = -1
ENDIF
llV2ok = (lnRulVechiCnt = lnRulBeforeCnt) AND (lnRulVechiSumSters = lnRulVechiCnt) AND (lnRulNouCnt = lnRulBeforeCnt)
STRTOFILE(' [2] RUL: vechi cnt=' + TRANSFORM(lnRulVechiCnt) + ' toate sters=' + TRANSFORM(lnRulVechiSumSters = lnRulVechiCnt) + ;
'; nou cnt=' + TRANSFORM(lnRulNouCnt) + ' (era ' + TRANSFORM(lnRulBeforeCnt) + ') -> ' + IIF(llV2ok, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
*-- [4] VANZARI_DETALII: neatins de aceasta cale
LOCAL lnVdCntDupa, lnVdSumaPretDupa, lnVdSumaPretCuTvaDupa, llV4ok
lcSql = [select count(*) as cnt, sum(cantitate) as sumcant, sum(pret) as sumpret, sum(pret_cu_tva) as sumpretcutva ] + ;
[from vanzari_detalii where sters = 0 and id_vanzare = ] + TRANSFORM(tnIdVanzare)
lnQ = ExecAgg(lcSql, 'v_vd_dupa')
IF lnQ > 0
lnVdCntDupa = v_vd_dupa.cnt
lnVdSumaPretDupa = NVL(v_vd_dupa.sumpret, 0)
lnVdSumaPretCuTvaDupa = NVL(v_vd_dupa.sumpretcutva, 0)
USE IN v_vd_dupa
ELSE
lnVdCntDupa = -1
lnVdSumaPretDupa = -1
lnVdSumaPretCuTvaDupa = -1
ENDIF
llV4ok = (lnVdCntDupa = lnVdCnt) AND (ABS(lnVdSumaPretDupa - lnVdSumaPret) < 0.01) AND (ABS(lnVdSumaPretCuTvaDupa - lnVdSumaPretCuTva) < 0.01)
STRTOFILE(' [4] VANZARI_DETALII: cnt=' + TRANSFORM(lnVdCntDupa) + ' (era ' + TRANSFORM(lnVdCnt) + ') sum(pret)=' + TRANSFORM(lnVdSumaPretDupa) + ;
' (era ' + TRANSFORM(lnVdSumaPret) + ') -> ' + IIF(llV4ok, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
*-- [5] lnSucces>0 pe tot lantul + tranzactia inchisa cu commit (deja logat mai sus, sintetizat aici)
STRTOFILE(' [5] lnSucces final = ' + TRANSFORM(lnSucces) + ' -> ' + IIF(lnSucces > 0, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
*-- verificare suplimentara TEST 2: explicatia modificata ajunge efectiv in ACT pe randul nou
IF tlModificaLinie AND !EMPTY(lcExplicatieNoua)
LOCAL lnExplicatieCnt
lcSql = [select count(*) as cnt from vact_tot where sters = 0 and an = ] + TRANSFORM(pnAn) + ;
[ and luna = ] + TRANSFORM(pnLuna) + [ and cod = ] + TRANSFORM(lnCodNou) + ;
[ and explicatia = '] + STRTRAN(lcExplicatieNoua, "'", "''") + [']
lnQ = ExecAgg(lcSql, 'v_act_explicatie')
IF lnQ > 0
lnExplicatieCnt = v_act_explicatie.cnt
USE IN v_act_explicatie
ELSE
lnExplicatieCnt = -1
ENDIF
STRTOFILE(' [2b] explicatia modificata ajunge in ACT: cnt=' + TRANSFORM(lnExplicatieCnt) + ' -> ' + IIF(lnExplicatieCnt = 1, 'PASS', 'FAIL') + CHR(13) + CHR(10), tcLog, 1)
ENDIF
STRTOFILE(' REZUMAT ' + tcEticheta + ': cod ' + TRANSFORM(lnVzCodBefore) + ' -> ' + TRANSFORM(lnCodNou) + CHR(13) + CHR(10), tcLog, 1)
ENDPROC
PROCEDURE test_error_handler
LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo
STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1)
ENDPROC

View File

@@ -0,0 +1,663 @@
* test_pret_cu_tva_dialog.prg
* Test UI Nivel 1 (S5, plan #7) pentru dialogul PER-ARTICOL real, clasa frm_articol_factura din
* COMUN\clase\ofacturare.vc2. Instantiaza clasa exact cum o instantiaza aplicatia in
* frm_facturare_articole.do_adauga_articol (ofacturare.vc2:12869):
* Createobject("frm_articol_factura", lnCantitate, tlImplicit)
* apoi exerseaza handlerele REALE (ck_pret_cu_tva.InteractiveChange, Clb_pretctva.tx_suma_nat.
* InteractiveChange, Clb_discountctva.tx_suma_nat.Valid) - nu populeaza direct poArticol cu
* rezultate calculate manual, doar cu DATELE DE INTRARE (pretul tastat, bifa), exact ce ar
* introduce utilizatorul. poArticol se construieste ca obiect liber (CREATEOBJECT+ADDPROPERTY),
* echivalent cu Scatter Name poArticol MEMO din crsarticole (acelasi shape de date), pentru ca
* testul sa ramana independent de Oracle si de celelalte doua griduri ale formularului parinte.
*
* Nivel 2 (flux complet prin frm_facturare_articole, propagare in crsfactura, buton
* but_modificare din S2b) NU e acoperit aici - vezi docs\cercetare\rec_s5_teste.md pentru motiv.
*
* Pasi (vezi vfp_ui_harness.ps1 -Steps):
* 0 mediu pregatit
* 1 cazul tinta: bifa=1, pret tastat 100.00 cu TVA, cantitate 1 -> total exact 100.00
* 2 comutare bifa OFF->ON: pretul fara TVA tastat nu se pierde
* 3 comutare bifa ON->OFF: pretul cu TVA tastat nu se pierde
* 4 cota standard 21%
* 5 cota redusa 11%
* 6 discount unitar cu TVA (ramura discountctva)
* 7 bifa activa pe tip de document din lista (Inlist 1,5,10,22,23,25,29,41)
* 8 bifa dezactivata pe tip din afara listei, cu pret nenul
* 9 final
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog, gcSyncDir
gcUILog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\test_pret_cu_tva_dialog_log.txt"
gcSyncDir = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\uisync\"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
ON ERROR DO AfErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
TRY
LOCAL gcAppPath, lcPath
gcAppPath = "D:\ROA\ROAFACTURARE\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + ;
gcAppPath + 'COMUN\UTILE\CALENDAR;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EMAIL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + gcAppPath + 'COMUN\UTILE\NFXML;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
DO AfLog WITH 'SET PATH OK'
*----- CLASE (lista din Programe\roafacturare.prg, scopul minim pentru ofacturare.vcx) -----
SET CLASSLIB TO (gcAppPath + "comun\clase\appwiz") ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms ADDITIVE
SET CLASSLIB TO ofacturare.vcx ADDITIVE
SET CLASSLIB TO ofacturare_comun.vcx ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO ctl32_statusbar.vcx ADDITIVE
SET CLASSLIB TO ctl32_common.vcx ADDITIVE
SET CLASSLIB TO ctl32_structs.vcx ADDITIVE
SET CLASSLIB TO ctl32_progressbar.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
SET CLASSLIB TO ofacturare_rapoarte ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO onom_curs ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO ferestre_cere_date ADDITIVE
SET CLASSLIB TO baza ADDITIVE
SET CLASSLIB TO caut ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO serii_numere ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO wwdialogs.vcx ADDITIVE
SET CLASSLIB TO _calendar.vcx ADDITIVE
SET CLASSLIB TO locale ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ocomenzi ADDITIVE
DO AfLog WITH 'SET CLASSLIB OK'
*----- PROCEDURI (mock amessagebox PRIMUL, ui_harness la final) -----
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg"
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO onomenclatoare.prg ADDITIVE
SET PROCEDURE TO onomenclatoare2.prg ADDITIVE
SET PROCEDURE TO oproceduri_rapoarte_fact.prg ADDITIVE
SET PROCEDURE TO email.prg ADDITIVE
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO odocumente ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO wwcodeupdate.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO cauta_alfa.prg ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO oproceduri_curs.prg ADDITIVE
SET PROCEDURE TO proceduri.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg ADDITIVE
SET PROCEDURE TO ofacturare.prg ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO wwApi.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO validare.prg ADDITIVE
SET PROCEDURE TO ofacturare_comun.prg ADDITIVE
SET PROCEDURE TO ofacturare_stoc.prg ADDITIVE
SET PROCEDURE TO pmenu.prg ADDITIVE
SET PROCEDURE TO ointroduceri.prg ADDITIVE
SET PROCEDURE TO ovariabile_globale.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO filebringer.prg ADDITIVE
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO oupdate.prg ADDITIVE
SET PROCEDURE TO procese.prg ADDITIVE
SET PROCEDURE TO version.prg ADDITIVE
SET PROCEDURE TO wwhttp.prg ADDITIVE
SET PROCEDURE TO xmlaccess.prg ADDITIVE
SET PROCEDURE TO xmlparser.prg ADDITIVE
SET PROCEDURE TO xdate.prg ADDITIVE
SET PROCEDURE TO suma_in_vorbe.prg ADDITIVE
SET PROCEDURE TO controllerecr ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
DO AfLog WITH 'SET PROCEDURE OK'
*----- Globale aplicatie cerute de frm_articol_factura / calculeaza_totaluri -----
PUBLIC gnPc, gnPVal, gnPcant, gnPPretV, gnScadereStoc, gnMemProcDisc, gl406, gcAcces
gnPc = 2 && precizie sume lei
gnPVal = 2 && precizie sume valuta
gnPcant = 3 && precizie cantitate (doar pt. InputMask)
gnPPretV = 4 && precizie unitara pret/tva/discount
gnScadereStoc = 0 && ocoleste ramura serie/lot needitabila si clb_procent_adaos
gnMemProcDisc = 0 && ocoleste memorarea procentului de discount intre articole
gl406 = .F. && SAFT dezactivat - flagul pret_cu_tva nu are legatura cu taxcode
gcAcces = "1;2;3;4;5;6;7;8;"
PUBLIC nror(65000)
PUBLIC goApp
goApp = CREATEOBJECT('dummyapp')
*----- jtva_coloane: cotele curente (regim post 01.08.2025) - 21% standard, 11% redusa -----
IF USED('jtva_coloane')
USE IN ('jtva_coloane')
ENDIF
CREATE CURSOR jtva_coloane (id_jtva_coloana N(14), denumire C(50), cota_tva N(6,2))
INSERT INTO jtva_coloane VALUES (1, 'TVA 21%', 21)
INSERT INTO jtva_coloane VALUES (2, 'TVA 11%', 11)
GO TOP IN jtva_coloane
*----- saft_taxtable: desi gl406=.F. (codul aplicatiei nu-l cere explicit), cb_explicatie_saft
* din frm_articol_factura are RowSource="select ... from saft_taxtable ..." legat direct
* pe control (RowSourceType=3) - fara cursorul cu acest alias, SELECT-ul cauta un fisier
* saft_taxtable.dbf inexistent si scoate dialogul nativ Windows "Open" care blocheaza
* headless la nesfarsit, fara nicio linie noua in log (capcana j, testare-ui-vfp.md). -----
IF USED('saft_taxtable')
USE IN ('saft_taxtable')
ENDIF
CREATE CURSOR saft_taxtable (taxname C(250), procent_taxa N(7,2), taxcode N(6), tva_livrari N(1))
INSERT INTO saft_taxtable VALUES ('301104-Achizitii de bunuri si servicii taxabile cu cota de 21%', 21, 301104, 1)
INSERT INTO saft_taxtable VALUES ('3011XX-Achizitii de bunuri si servicii taxabile cu cota de 11%', 11, 301108, 1)
*----- tablourile cu campurile poArticol: constructie poArticol INLINE in main la fiecare
* scenariu (nu intr-o PROCEDURA - vezi capcana ADDPROPERTY apelat dintr-o procedura,
* testare-ui-vfp.md litera l), dar bucla de ADDPROPERTY ramane in corpul principal, deci
* e sigura; reduce field-urile "neutre" (0 / '') la doua tablouri reutilizate. -----
LOCAL lnI
LOCAL ARRAY laPropN(49)
laPropN( 1)='id_articol' && identificatori si asociatii
laPropN( 2)='Id_Pol'
laPropN( 3)='id_gestiune'
laPropN( 4)='id_c'
laPropN( 5)='id_ctr'
laPropN( 6)='id_valuta'
laPropN( 7)='id_valuta_d'
laPropN( 8)='id_lucrare_rez'
laPropN( 9)='id_part_rez'
laPropN(10)='id_jtva_coloana'
laPropN(11)='taxcode'
laPropN(12)='opt_facturare'
laPropN(13)='gestionabil' && cantitate / pret / valuta
laPropN(14)='tip_valuta'
laPropN(15)='cantitate'
laPropN(16)='Curs'
laPropN(17)='multiplicator'
laPropN(18)='pret_achizitie'
laPropN(19)='pretv_orig'
laPropN(20)='pretd'
laPropN(21)='proc_tvav'
laPropN(22)='preturi_cu_tva' && preturi
laPropN(23)='pretftva'
laPropN(24)='pretftva_val'
laPropN(25)='pretctva'
laPropN(26)='pretctva_val'
laPropN(27)='tva'
laPropN(28)='tva_val'
laPropN(29)='discount_unitar' && discount unitar
laPropN(30)='discount_unitar_val'
laPropN(31)='discount_unitar_ctva'
laPropN(32)='discount_unitar_ctva_val'
laPropN(33)='valftva' && totaluri lei (calculate de calculeaza_totaluri)
laPropN(34)='valtva'
laPropN(35)='valctva'
laPropN(36)='valdiscountftva'
laPropN(37)='valdiscounttva'
laPropN(38)='valdiscountctva'
laPropN(39)='valdiminuatftva'
laPropN(40)='valdiminuattva'
laPropN(41)='valdiminuatctva'
laPropN(42)='vvalftva' && totaluri valuta (calculate de calculeaza_totaluri)
laPropN(43)='vvaltva'
laPropN(44)='vvalctva'
laPropN(45)='vvaldiscountftva'
laPropN(46)='vvaldiscounttva'
laPropN(47)='vvaldiscountctva'
laPropN(48)='vvaldiminuatftva'
laPropN(49)='vvaldiminuattva'
*-- (vvaldiminuatctva se adauga separat mai jos, ALEN a ramas 49 din motive de numarare initiala)
LOCAL ARRAY laPropC(11)
laPropC( 1)='codmat'
laPropC( 2)='codmatf'
laPropC( 3)='denumire'
laPropC( 4)='um'
laPropC( 5)='serie'
laPropC( 6)='lot'
laPropC( 7)='explicatie'
laPropC( 8)='numar_contract'
laPropC( 9)='codbare'
laPropC(10)='nume_val'
laPropC(11)='Cont'
PRIVATE poArticol, poDate
DO AfLog WITH 'mediu pregatit, incep scenariile'
*========================= PAS 0: mediu pregatit =========================
DO HarnessStep WITH 0, 'mediu pregatit, jtva_coloane cu ' + TRANSFORM(RECCOUNT('jtva_coloane')) + ' cote'
*========================= SCENARIU 1 (cazul tinta): bifa=1, 100.00 cu TVA, cant 1 =========
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1001
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART001'
poArticol.denumire = 'ARTICOL TEST 100 CU TVA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21 && cota standard 21%
poArticol.preturi_cu_tva = 1 && bifa PORNITA - politica implicita cu TVA inclus
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1) && 1 = lista de preturi, in Inlist activator bifa
=ADDPROPERTY(poDate, 'in_valuta', 0)
PUBLIC goDlg
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
IF VARTYPE(goDlg) <> 'O'
DO AfLog WITH 'FAIL: instantiere frm_articol_factura (scenariul 1)'
DO HarnessDone WITH 'done-error'
QUIT
ENDIF
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
DO AfLog WITH 'S1 dupa Init: preturi_cu_tva=' + TRANSFORM(poArticol.preturi_cu_tva) + ;
' ck_pret_cu_tva.Value=' + TRANSFORM(goDlg.ck_pret_cu_tva.Value) + ;
' Enabled=' + TRANSFORM(goDlg.ck_pret_cu_tva.Enabled)
*-- utilizatorul tasteaza 100.00 in campul "Pret cu TVA" (bifa deja pornita)
goDlg.Clb_pretctva.tx_suma_nat.Value = 100
goDlg.Clb_pretctva.tx_suma_nat.InteractiveChange()
DOEVENTS FORCE
DO HarnessStep WITH 1, 'cazul tinta: pretctva tastat 100.00, cantitate 1'
DO VerificaNumeric WITH 'S1 pretctva pastrat', poArticol.pretctva, 100, 0.005
DO VerificaNumeric WITH 'S1 CAZUL TINTA totalul facturii (valctva)', poArticol.valctva, 100, 0.005
*-- cifrele complete ale cazului tinta, indiferent de PASS/FAIL - de citat in raport ca atare
DO AfLog WITH 'S1 CIFRE CAZ TINTA: pretftva=' + TRANSFORM(poArticol.pretftva) + ;
' pretctva=' + TRANSFORM(poArticol.pretctva) + ' tva=' + TRANSFORM(poArticol.tva) + ;
' valftva=' + TRANSFORM(poArticol.valftva) + ' valtva=' + TRANSFORM(poArticol.valtva) + ;
' valctva=' + TRANSFORM(poArticol.valctva)
*-- butonul OK (inainte_de_do_termin): parte din fluxul real, dar poate cere ActiveControl
*-- (focus real de fereastra), nesigur headless. Daca arunca eroare, pasul e NEACOPERIT -
*-- nu se raporteaza PASS/FAIL pe o executie care nu s-a confirmat.
LOCAL llOkS1
TRY
llOkS1 = goDlg.inainte_de_do_termin()
DO VerificaLogic WITH 'S1 buton OK (inainte_de_do_termin)', llOkS1, .T.
CATCH TO loExcOk
DO AfLog WITH 'NEACOPERIT S1 buton OK (inainte_de_do_termin): eroare ' + ;
TRANSFORM(loExcOk.ErrorNo) + ' [' + loExcOk.Message + '] in ' + loExcOk.Procedure + ;
':' + TRANSFORM(loExcOk.LineNo) + ' - pasul nu s-a putut executa headless, nu e nici PASS nici FAIL'
ENDTRY
goDlg.Hide()
DOEVENTS FORCE
*========================= SCENARIU 2: comutare bifa, valoarea tastata nu se pierde =========
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1002
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 2
poArticol.codmat = 'ART002'
poArticol.denumire = 'ARTICOL TEST COMUTARE BIFA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21
poArticol.preturi_cu_tva = 0 && bifa OPRITA - pretul fara TVA e cel editabil
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 2, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
*-- utilizatorul tasteaza 50.00 fara TVA (bifa oprita)
goDlg.Clb_pretftva.tx_suma_nat.Value = 50
goDlg.Clb_pretftva.tx_suma_nat.InteractiveChange()
DOEVENTS FORCE
DO AfLog WITH 'S2 dupa tastare pretftva=50: pretftva=' + TRANSFORM(poArticol.pretftva) + ;
' pretctva=' + TRANSFORM(poArticol.pretctva)
*-- bifeaza (OFF -> ON): pretul fara TVA tastat (50) nu trebuie sa se piarda
goDlg.ck_pret_cu_tva.Value = 1
goDlg.ck_pret_cu_tva.InteractiveChange()
DOEVENTS FORCE
DO HarnessStep WITH 2, 'bifa OFF->ON: pretftva tastat=50 trebuie pastrat'
DO VerificaNumeric WITH 'S2 comutare OFF->ON: pretftva NEPIERDUT', poArticol.pretftva, 50, 0.005
DO VerificaNumeric WITH 'S2 comutare OFF->ON: pretctva derivat', poArticol.pretctva, 60.5, 0.005
*-- debifeaza (ON -> OFF): pretul (acum cu TVA, derivat) trebuie sa duca inapoi la acelasi pretftva=50
goDlg.ck_pret_cu_tva.Value = 0
goDlg.ck_pret_cu_tva.InteractiveChange()
DOEVENTS FORCE
DO HarnessStep WITH 3, 'bifa ON->OFF: pretftva trebuie sa ramana 50 (roundtrip)'
DO VerificaNumeric WITH 'S2 comutare ON->OFF: pretftva NEPIERDUT (roundtrip)', poArticol.pretftva, 50, 0.005
goDlg.Hide()
DOEVENTS FORCE
*========================= SCENARIU 3: cota standard 21% vs cota redusa 11% =========
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1003
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART003A'
poArticol.denumire = 'ARTICOL TEST COTA STANDARD'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21 && cota standard 21%
poArticol.preturi_cu_tva = 0
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
goDlg.Clb_pretftva.tx_suma_nat.Value = 100
goDlg.Clb_pretftva.tx_suma_nat.InteractiveChange()
DOEVENTS FORCE
DO HarnessStep WITH 4, 'cota standard 21%: pretftva=100 -> tva/pretctva'
DO VerificaNumeric WITH 'S3a cota 21%: tva', poArticol.tva, 21, 0.005
DO VerificaNumeric WITH 'S3a cota 21%: pretctva', poArticol.pretctva, 121, 0.005
goDlg.Hide()
DOEVENTS FORCE
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1004
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART003B'
poArticol.denumire = 'ARTICOL TEST COTA REDUSA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.11 && cota redusa 11%
poArticol.preturi_cu_tva = 0
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
goDlg.Clb_pretftva.tx_suma_nat.Value = 100
goDlg.Clb_pretftva.tx_suma_nat.InteractiveChange()
DOEVENTS FORCE
DO HarnessStep WITH 5, 'cota redusa 11%: pretftva=100 -> tva/pretctva'
DO VerificaNumeric WITH 'S3b cota 11%: tva', poArticol.tva, 11, 0.005
DO VerificaNumeric WITH 'S3b cota 11%: pretctva', poArticol.pretctva, 111, 0.005
goDlg.Hide()
DOEVENTS FORCE
*========================= SCENARIU 4: discount unitar cu TVA (ramura discountctva) =========
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1005
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART004'
poArticol.denumire = 'ARTICOL TEST DISCOUNT CU TVA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21
poArticol.preturi_cu_tva = 1 && bifa pornita - ramura discountctva e cea activa
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
goDlg.Clb_pretctva.tx_suma_nat.Value = 100
goDlg.Clb_pretctva.tx_suma_nat.InteractiveChange()
DOEVENTS FORCE
*-- utilizatorul tasteaza 10.00 discount unitar cu TVA (Valid, cu When intai - ca la focus real)
goDlg.Clb_discountctva.tx_suma_nat.When()
goDlg.Clb_discountctva.tx_suma_nat.Value = 10
goDlg.Clb_discountctva.tx_suma_nat.Valid()
DOEVENTS FORCE
DO HarnessStep WITH 6, 'discount unitar cu TVA = 10, pret 100, cant 1'
DO VerificaNumeric WITH 'S4 discount_unitar_ctva pastrat', poArticol.discount_unitar_ctva, 10, 0.005
DO VerificaNumeric WITH 'S4 total diminuat cu TVA (valdiminuatctva)', poArticol.valdiminuatctva, 90, 0.005
DO AfLog WITH 'S4 comparatie: fara discount (scenariul 1) valctva=100.00, cu discount 10 -> valdiminuatctva=' + TRANSFORM(poArticol.valdiminuatctva)
goDlg.Hide()
DOEVENTS FORCE
*========================= SCENARIU 5: bifa ACTIVA pe tip din Inlist =========================
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1006
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART005'
poArticol.denumire = 'ARTICOL TEST BIFA ACTIVA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21
poArticol.preturi_cu_tva = 0
poArticol.pretftva = 0 && pret zero - irelevant, tip 1 activeaza bifa oricum
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 1) && 1 = lista de preturi, IN Inlist(1,5,10,22,23,25,29,41)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
DO HarnessStep WITH 7, 'tip=1 (Inlist) -> bifa trebuie activa (Enabled=.T.)'
DO VerificaLogic WITH 'S5 bifa ACTIVA pe tip din Inlist', goDlg.ck_pret_cu_tva.Enabled, .T.
goDlg.Hide()
DOEVENTS FORCE
*========================= SCENARIU 6: bifa DEZACTIVATA pe tip din afara listei =========
poArticol = CREATEOBJECT('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=ADDPROPERTY(poArticol, laPropN(lnI), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=ADDPROPERTY(poArticol, laPropC(lnI), '')
ENDFOR
poArticol.id_articol = 1007
poArticol.Id_Pol = 1
poArticol.Cont = '707'
poArticol.id_gestiune = 1
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 1
poArticol.codmat = 'ART006'
poArticol.denumire = 'ARTICOL TEST BIFA DEZACTIVATA'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21
poArticol.preturi_cu_tva = 0
poArticol.pretftva = 50 && pret NENUL - conditie ceruta ca bifa sa ramana dezactivata
poDate = CREATEOBJECT('Empty')
=ADDPROPERTY(poDate, 'tip', 3) && 3 = comanda, NU e in Inlist(1,5,10,22,23,25,29,41)
=ADDPROPERTY(poDate, 'in_valuta', 0)
goDlg = CREATEOBJECT('frm_articol_factura', 1, .F.)
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
DO HarnessStep WITH 8, 'tip=3 (afara Inlist), pret nenul -> bifa trebuie dezactivata'
DO VerificaLogic WITH 'S6 bifa DEZACTIVATA pe tip din afara listei, pret nenul', goDlg.ck_pret_cu_tva.Enabled, .F.
goDlg.Hide()
DOEVENTS FORCE
DO AfLog WITH 'GATA - toate scenariile Nivel 1 executate'
DO HarnessStep WITH 9, 'final'
DO HarnessDone WITH 'done'
CATCH TO loExc
DO AfLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']'
DO HarnessDone WITH 'done-error'
ENDTRY
QUIT
*==================================================================================
PROCEDURE VerificaNumeric
LPARAMETERS tcEticheta, tnObtinut, tnAsteptat, tnToleranta
LOCAL lcMsg
IF ABS(NVL(tnObtinut,-999999) - tnAsteptat) < tnToleranta
lcMsg = 'PASS ' + tcEticheta + ': ' + TRANSFORM(tnObtinut) + ' (asteptat ' + TRANSFORM(tnAsteptat) + ')'
ELSE
lcMsg = 'FAIL ' + tcEticheta + ': obtinut=' + TRANSFORM(tnObtinut) + ' asteptat=' + TRANSFORM(tnAsteptat)
ENDIF
DO AfLog WITH lcMsg
ENDPROC
PROCEDURE VerificaLogic
LPARAMETERS tcEticheta, tlObtinut, tlAsteptat
LOCAL lcMsg
IF tlObtinut = tlAsteptat
lcMsg = 'PASS ' + tcEticheta + ': ' + TRANSFORM(tlObtinut) + ' (asteptat ' + TRANSFORM(tlAsteptat) + ')'
ELSE
lcMsg = 'FAIL ' + tcEticheta + ': obtinut=' + TRANSFORM(tlObtinut) + ' asteptat=' + TRANSFORM(tlAsteptat)
ENDIF
DO AfLog WITH lcMsg
ENDPROC
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO AfLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
SET SAFETY OFF
LOCAL lcL
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
ENDPROC
DEFINE CLASS dummyapp AS Custom
PROCEDURE ReadIni
LPARAMETERS tcSection, tcKey
RETURN ''
ENDPROC
PROCEDURE WriteIni
LPARAMETERS tcSection, tcKey, tcValue
RETURN .T.
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,10 @@
# test_pret_cu_tva_dialog.ps1 - wrapper peste harness-ul generic pentru testul frm_articol_factura
# (S5, plan #7 - pret_cu_tva). Rulare: powershell -ExecutionPolicy Bypass -File test_pret_cu_tva_dialog.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
-TestPrg (Join-Path $Teste 'test_pret_cu_tva_dialog.prg') `
-Steps @('mediu','tinta_100', 'comutare_on', 'comutare_off', 'cota_21', 'cota_11', 'discount', 'bifa_activa', 'bifa_dezactivata', 'final') `
-ShotsDir (Join-Path $Teste 'screenshots') `
-SyncDir (Join-Path $Teste 'uisync') `
-StepTimeoutSec 60

View File

@@ -0,0 +1,630 @@
* test_pret_cu_tva_nivel2.prg
* Test UI Nivel 2 (S5, plan #7) pentru fluxul COMPLET prin frm_facturare_articole - cazurile 6 si 8
* din task. Foloseste mecanismul validat in test_modal_unlock_smoketest2.prg (Timer pe _SCREEN +
* _SCREEN.Forms + Controls(i)) ca sa conduca dialogul frm_articol_factura, deschis cu Show(1)
* hardcodat in do_adauga_articol/do_modifica (frm_facturare_articole, ofacturare.vc2).
*
* Flux REAL, nu populare directa: articolul intra in crsfactura prin But_urmator1.Click() ->
* do_urmator() -> do_adauga_articol() (cazul 6); modificarea trece prin But_modifica1.Click() /
* grd_factura.DblClick() -> do_modifica() (cazul 8). crsarticole si crsfactura au structura REALA
* (creeaza_facturacrs, aceleasi campuri ca in productie), fara Oracle.
*
* Cazuri:
* PAS 0: grid gol - But_modifica1.Click() si grd_factura.DblClick() nu fac nimic, fara eroare.
* PAS 1 (caz 6): adaugare cu bifa schimbata fata de politica (policy=0, user seteaza 1, pret cu
* TVA=100) -> crsfactura.cu_tva=1, valctva=100.00 exact.
* PAS 2 (caz 8a): modificare - But_modifica1 redeschide dialogul pe randul adaugat, comuta bifa
* OFF, tasteaza pret fara TVA=60 -> acelasi rand actualizat (cu_tva=0, valctva=72.60).
* PAS 3 (caz 8b): modificare prin grd_factura.DblClick() (al doilea canal, acelasi rezultat) -
* schimba pretul cu TVA la 200, bifa ramane ON dupa pasul anterior... de fapt pasul 2 a
* lasat bifa OFF, deci verifica ramura fara TVA din nou, cu alta valoare.
* PAS 4 (caz 8c): Renunta - deschide dialogul, schimba o valoare, apasa Renunta -> randul ramane
* BIT-IDENTIC (comparat camp cu camp fata de starea dinainte).
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog, gcSyncDir
gcUILog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\test_pret_cu_tva_nivel2_log.txt"
gcSyncDir = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\uisync_nivel2\"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
ON ERROR DO AfErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
TRY
LOCAL gcAppPath, lcPath
gcAppPath = "D:\ROA\ROAFACTURARE\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + ;
gcAppPath + 'COMUN\UTILE\CALENDAR;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EMAIL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + gcAppPath + 'COMUN\UTILE\NFXML;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
DO AfLog WITH 'SET PATH OK'
*----- CLASE (lista dovedita de suita Nivel 1 - mediul unei suite noi se mosteneste din suita
* care TRECE, nu dintr-un smoke-test) -----
SET CLASSLIB TO (gcAppPath + "comun\clase\appwiz") ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms ADDITIVE
SET CLASSLIB TO ofacturare.vcx ADDITIVE
SET CLASSLIB TO ofacturare_comun.vcx ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO ctl32_statusbar.vcx ADDITIVE
SET CLASSLIB TO ctl32_common.vcx ADDITIVE
SET CLASSLIB TO ctl32_structs.vcx ADDITIVE
SET CLASSLIB TO ctl32_progressbar.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
SET CLASSLIB TO ofacturare_rapoarte ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO onom_curs ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO ferestre_cere_date ADDITIVE
SET CLASSLIB TO baza ADDITIVE
SET CLASSLIB TO caut ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO serii_numere ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO wwdialogs.vcx ADDITIVE
SET CLASSLIB TO _calendar.vcx ADDITIVE
SET CLASSLIB TO locale ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ocomenzi ADDITIVE
DO AfLog WITH 'SET CLASSLIB OK'
*----- PROCEDURI (mock amessagebox PRIMUL, ui_harness la final) -----
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg"
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO onomenclatoare.prg ADDITIVE
SET PROCEDURE TO onomenclatoare2.prg ADDITIVE
SET PROCEDURE TO oproceduri_rapoarte_fact.prg ADDITIVE
SET PROCEDURE TO email.prg ADDITIVE
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO odocumente ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO wwcodeupdate.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO cauta_alfa.prg ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO oproceduri_curs.prg ADDITIVE
SET PROCEDURE TO proceduri.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg ADDITIVE
SET PROCEDURE TO ofacturare.prg ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO wwApi.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO validare.prg ADDITIVE
SET PROCEDURE TO ofacturare_comun.prg ADDITIVE
SET PROCEDURE TO ofacturare_stoc.prg ADDITIVE
SET PROCEDURE TO pmenu.prg ADDITIVE
SET PROCEDURE TO ointroduceri.prg ADDITIVE
SET PROCEDURE TO ovariabile_globale.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO filebringer.prg ADDITIVE
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO oupdate.prg ADDITIVE
SET PROCEDURE TO procese.prg ADDITIVE
SET PROCEDURE TO version.prg ADDITIVE
SET PROCEDURE TO wwhttp.prg ADDITIVE
SET PROCEDURE TO xmlaccess.prg ADDITIVE
SET PROCEDURE TO xmlparser.prg ADDITIVE
SET PROCEDURE TO xdate.prg ADDITIVE
SET PROCEDURE TO suma_in_vorbe.prg ADDITIVE
SET PROCEDURE TO controllerecr ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
DO AfLog WITH 'SET PROCEDURE OK'
*----- Globale aplicatie -----
PUBLIC gnPc, gnPVal, gnPcant, gnPPretV, gnScadereStoc, gnMemProcDisc, gl406, gcAcces
PUBLIC gnModTotFact, gnRF_FACTURARE_FARA_STOC
*-- gnModTotFact/gnRF_FACTURARE_FARA_STOC: lista completa a globalelor de aplicatie cerute de
*-- Init/do_adauga_articol/do_modifica/do_verifica_articol/do_initializeaza_articol (extrasa cu
*-- vfp_symbols.ps1 -Class frm_facturare_articole, identificatori g[nlc]\w+), restul deja
*-- prezente in mediu. Puse pe 0 (implicit prudent) ca sa NU activeze ramuri neintentionate -
*-- gnModTotFact=1 ar intra pe modificarea totalului facturii, gnRF_FACTURARE_FARA_STOC=1 pe
*-- facturare fara stoc; niciuna nu e ce se testeaza aici. NVL() nu apara de variabila
*-- nedeclarata, doar de valoare NULL - trebuie sa existe.
gnModTotFact = 0
gnRF_FACTURARE_FARA_STOC = 0
*-- gnPPret/gnPPretVal: presupuse (nu exista in cod - vin din configuratia Oracle citita la
*-- pornirea reala; ceruta de creeaza_facturacrs, ofacturare_comun.prg:1770, neintalnita la
*-- Nivel 1 care nu atinge acel cursor). Ating DOAR pret_achizitie/pretd (max(...,4)) - niciun
*-- camp verificat de testele de mai jos (pretftva/pretctva/valftva/valtva/valctva folosesc
*-- gnPPretV+gnPc, deja corecte). precizie_max_pret_vz e #define=6 in acelasi fisier, nu
*-- variabila - nu se declara aici.
PUBLIC gnPPret, gnPPretVal
gnPc = 2
gnPVal = 2
gnPcant = 3
gnPPretV = 4
gnPPret = 4
gnPPretVal = 4
gnScadereStoc = 0 && bypass complet logica de stoc (do_alege_stoc nu se apeleaza)
gnMemProcDisc = 0
gl406 = .F.
gcAcces = "1;2;3;4;5;6;7;8;"
PUBLIC nror(65000)
PUBLIC goApp, goExport, goExecutor
goApp = CREATEOBJECT('dummyapp')
goExport = CREATEOBJECT('dummyexport')
goExecutor = CREATEOBJECT('dummyexecutor')
IF USED('jtva_coloane')
USE IN ('jtva_coloane')
ENDIF
CREATE CURSOR jtva_coloane (id_jtva_coloana N(14), denumire C(50), cota_tva N(6,2))
INSERT INTO jtva_coloane VALUES (1, 'TVA 21%', 21)
INSERT INTO jtva_coloane VALUES (2, 'TVA 11%', 11)
GO TOP IN jtva_coloane
IF USED('saft_taxtable')
USE IN ('saft_taxtable')
ENDIF
CREATE CURSOR saft_taxtable (taxname C(250), procent_taxa N(7,2), taxcode N(6), tva_livrari N(1))
INSERT INTO saft_taxtable VALUES ('301104-Achizitii de bunuri si servicii taxabile cu cota de 21%', 21, 301104, 1)
INSERT INTO saft_taxtable VALUES ('3011XX-Achizitii de bunuri si servicii taxabile cu cota de 11%', 11, 301108, 1)
*----- crsfactura: structura REALA, fara Oracle (creeaza_facturacrs, ofacturare_comun.prg:1770) -----
DO creeaza_facturacrs WITH 'crsfactura'
DO AfLog WITH 'crsfactura creat, Reccount=' + TRANSFORM(RECCOUNT('crsfactura'))
*----- crsarticole: sursa (stoc/lista de preturi) - RecordSource al grd_articole. Campuri
* alese ca sa acopere atat coloanele gridului (denumire, gestionabil, codmat, pret,
* cantitate, preturi_cu_tva, pret_val, nume_val, nume_lista_preturi, serie, codbare) cat
* si tot ce Scatter+do_initializeaza_articol au nevoie (restul, verificat din cod). -----
IF USED('crsarticole')
USE IN ('crsarticole')
ENDIF
CREATE CURSOR crsarticole (id_articol N(10), Id_Pol N(10), id_gestiune N(10), denumire C(100), ;
codmat C(50), codbare C(50), gestionabil N(1), cantitate N(18,4), pret N(18,4), ;
pret_val N(18,4), preturi_cu_tva N(1), proc_tvav N(18,4), discount_unitar N(18,4), ;
discount_unitar_val N(18,4), pret_achizitie N(18,4), tip_valuta N(1), Curs N(18,4), ;
multiplicator N(10,4), Cont C(10), um C(10), serie C(30), lot C(30), explicatie C(200), ;
opt_facturare N(3), id_ctr N(10), numar_contract C(50), pretd N(18,4), id_valuta N(10), ;
nume_val C(20), nume_lista_preturi C(100), id_jtva_coloana N(10), taxcode N(6), id_c N(10))
INSERT INTO crsarticole (id_articol, Id_Pol, id_gestiune, denumire, codmat, codbare, ;
gestionabil, cantitate, pret, pret_val, preturi_cu_tva, proc_tvav, discount_unitar, ;
discount_unitar_val, pret_achizitie, tip_valuta, Curs, multiplicator, Cont, um, serie, ;
lot, explicatie, opt_facturare, id_ctr, numar_contract, pretd, id_valuta, nume_val, ;
nume_lista_preturi, id_jtva_coloana, taxcode, id_c) ;
VALUES (2001, 1, 1, 'ARTICOL NIVEL2', 'ART2001', '', ;
0, 100, 50, 0, 0, 1.21, 0, ;
0, 0, 0, 1, 1, '707', 'BUC', '', ;
'', '', 0, 0, '', 0, 0, '', ;
'LISTA TEST', 1, 0, 1)
GO TOP IN crsarticole
DO AfLog WITH 'crsarticole creat, Reccount=' + TRANSFORM(RECCOUNT('crsarticole'))
*----- poDate: clasa REALA oDateFactura (ofacturare_comun.prg:99, deja incarcata prin SET
* PROCEDURE), nu obiect Empty umplut manual - are toate proprietatile cu valorile
* implicite de productie (inclusiv discount_evidentiat=0). PRIVATE la nivel de PROGRAM
* PRINCIPAL, vizibil (scoping VFP) in tot lantul apelat mai jos (frm_facturare_articole,
* do_adauga_articol, do_modifica, frm_articol_factura) - la fel ca in productie
* (Procedure factureaza, ofacturare.prg:95). Constructia ramane INLINE in main (capcana l). -----
PRIVATE poDate
poDate = CREATEOBJECT('oDateFactura')
poDate.tip = 1 && 1 = facturare pe baza de lista de preturi
poDate.serie_act = 'TST'
poDate.nract = 1
DO AfLog WITH 'poDate pregatit (oDateFactura), tip=' + TRANSFORM(poDate.tip)
*----- driverul de deblocare Show(1): Timer la nivel _SCREEN + _SCREEN.Forms + Controls(i),
* mecanism validat in test_modal_unlock_smoketest2.prg (PASS). gcCazAct selecteaza
* interactiunea de aplicat la fiecare dialog nou detectat. -----
PUBLIC goDriver, gnDriverTick, glDlgTratat, gcCazAct
gnDriverTick = 0
glDlgTratat = .F.
gcCazAct = ''
goDriver = CREATEOBJECT('driverdeblocare3')
_SCREEN.AddObject('tmrDrvN2', 'Timer')
_SCREEN.tmrDrvN2.Interval = 200
BINDEVENT(_SCREEN.tmrDrvN2, 'Timer', goDriver, 'Executa')
_SCREEN.tmrDrvN2.Enabled = .T.
DO AfLog WITH 'driver+timer pregatiti'
*----- Desktop VFP vizibil, ca la celelalte suite UI -----
_SCREEN.Visible = .T.
_SCREEN.WindowState = 2
_SCREEN.Caption = 'TEST UI Nivel 2 (cazurile 6 si 8)'
PUBLIC goFrm
goFrm = CREATEOBJECT('frm_facturare_articole')
goFrm.WindowType = 0 && testul instantiaza direct - modeless, Show() revine imediat
goFrm.Show()
goFrm.WindowState = 2
DOEVENTS FORCE
DO AfLog WITH 'frm_facturare_articole afisat modeless, Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
DO HarnessStep WITH 0, 'formular afisat, grid gol'
*========================= PAS 0: grid gol - But_modifica1/DblClick nu fac nimic =========
LOCAL lnRecFataDe0
lnRecFataDe0 = RECCOUNT('crsfactura')
goFrm.But_modifica1.Click()
DOEVENTS FORCE
IF RECCOUNT('crsfactura') = lnRecFataDe0
DO UILog WITH 'PASS P0a But_modifica1 pe grid gol: nu a modificat Reccount (' + TRANSFORM(RECCOUNT('crsfactura')) + ')'
ELSE
DO UILog WITH 'FAIL P0a But_modifica1 pe grid gol: Reccount a devenit ' + TRANSFORM(RECCOUNT('crsfactura'))
ENDIF
goFrm.grd_factura.DblClick()
DOEVENTS FORCE
IF RECCOUNT('crsfactura') = lnRecFataDe0
DO UILog WITH 'PASS P0b grd_factura.DblClick pe grid gol: nu a modificat Reccount'
ELSE
DO UILog WITH 'FAIL P0b grd_factura.DblClick pe grid gol: Reccount a devenit ' + TRANSFORM(RECCOUNT('crsfactura'))
ENDIF
DO HarnessStep WITH 1, 'P0 grid gol verificat'
*========================= PAS 1 (CAZUL 6): adaugare cu bifa schimbata =========================
*-- politica implicita (crsarticole.preturi_cu_tva=0, fara TVA) - userul o schimba in dialog la
*-- 1 (cu TVA), tasteaza pret cu TVA=100, cantitate=1 (zerorizata de do_initializeaza_articol
*-- pt. tip=1, se completeaza in dialog, ca la fluxul real).
SELECT crsarticole
GO TOP
gcCazAct = 'CASE6'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_urmator1.Click()
DOEVENTS FORCE
LOCAL lnWait
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_urmator1: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
IF RECCOUNT('crsfactura') = 1
SELECT crsfactura
GO TOP
IF cu_tva = 1 AND ABS(valctva - 100) < 0.01
DO UILog WITH 'PASS P1 CAZUL 6: cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=1 valctva=100)'
ELSE
DO UILog WITH 'FAIL P1 CAZUL 6: cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=1 valctva=100)'
ENDIF
DO UILog WITH 'P1 cifre complete: pretftva=' + TRANSFORM(pretftva) + ' pretctva=' + TRANSFORM(pretctva) + ' valftva=' + TRANSFORM(valftva) + ' valtva=' + TRANSFORM(valtva)
ELSE
DO UILog WITH 'FAIL P1 CAZUL 6: Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura')) + ' (asteptat 1) - articolul nu a fost adaugat'
ENDIF
DO HarnessStep WITH 2, 'P1 caz 6 propagare: Reccount=' + TRANSFORM(RECCOUNT('crsfactura'))
*========================= PAS 2 (CAZUL 8a): modificare prin But_modifica1 =========================
*-- comuta bifa OFF (fara TVA), tasteaza pret fara TVA=60 -> valctva asteptat 60*1.21=72.60
IF RECCOUNT('crsfactura') = 1
gcCazAct = 'CASE8_MOD_OFF'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P2): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF cu_tva = 0 AND ABS(valctva - 72.6) < 0.01
DO UILog WITH 'PASS P2 CAZUL 8a (But_modifica1): cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=0 valctva=72.60)'
ELSE
DO UILog WITH 'FAIL P2 CAZUL 8a (But_modifica1): cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=0 valctva=72.60)'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P2: nu exista randul din P1 (Reccount=' + TRANSFORM(RECCOUNT('crsfactura')) + ')'
ENDIF
DO HarnessStep WITH 3, 'P2 caz 8a modificare But_modifica1'
*========================= PAS 3 (CAZUL 8b): modificare prin grd_factura.DblClick() =========
*-- al doilea canal cerut de task - schimba pretul cu TVA la 200, bifa ON
IF RECCOUNT('crsfactura') = 1
gcCazAct = 'CASE8_MOD_ON'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.grd_factura.DblClick()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa grd_factura.DblClick (P3): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF cu_tva = 1 AND ABS(valctva - 200) < 0.01
DO UILog WITH 'PASS P3 CAZUL 8b (DblClick): cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=1 valctva=200)'
ELSE
DO UILog WITH 'FAIL P3 CAZUL 8b (DblClick): cu_tva=' + TRANSFORM(cu_tva) + ' valctva=' + TRANSFORM(valctva) + ' (asteptat cu_tva=1 valctva=200)'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P3: nu exista randul (Reccount=' + TRANSFORM(RECCOUNT('crsfactura')) + ')'
ENDIF
DO HarnessStep WITH 4, 'P3 caz 8b modificare DblClick'
*========================= PAS 4 (CAZUL 8c): Renunta - randul ramane BIT-IDENTIC =========
*-- SCATTER TO array (nu AFIELDS - AFIELDS umple un tablou de METADATE si intoarce un numar,
*-- nu e o colectie FOR EACH) captureaza VALORILE campurilor din randul curent, memo inclusiv.
IF RECCOUNT('crsfactura') = 1
LOCAL ARRAY laSnapDinainte[1]
LOCAL lnF, lnCampuri
SELECT crsfactura
GO TOP
SCATTER TO laSnapDinainte
gcCazAct = 'CASE8_RENUNTA'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P4, Renunta): glDlgTratat=' + TRANSFORM(glDlgTratat)
LOCAL ARRAY laSnapDupa[1]
SELECT crsfactura
GO TOP
SCATTER TO laSnapDupa
LOCAL llIdentic
llIdentic = (ALEN(laSnapDinainte,1) == ALEN(laSnapDupa,1))
lnCampuri = 0
IF llIdentic
FOR lnF = 1 TO ALEN(laSnapDinainte,1)
lnCampuri = lnCampuri + 1
IF !(TRANSFORM(laSnapDinainte(lnF)) == TRANSFORM(laSnapDupa(lnF)))
llIdentic = .F.
DO AfLog WITH 'P4 diagnostic - campul ' + TRANSFORM(lnF) + ' difera: [' + ;
TRANSFORM(laSnapDinainte(lnF)) + '] -> [' + TRANSFORM(laSnapDupa(lnF)) + ']'
ENDIF
ENDFOR
ENDIF
IF llIdentic
DO UILog WITH 'PASS P4 CAZUL 8c Renunta: randul ramane BIT-IDENTIC (' + TRANSFORM(lnCampuri) + ' campuri comparate)'
ELSE
DO UILog WITH 'FAIL P4 CAZUL 8c Renunta: randul S-A MODIFICAT desi s-a apasat Renunta (vezi diag pe campuri mai sus)'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P4: nu exista randul (Reccount=' + TRANSFORM(RECCOUNT('crsfactura')) + ')'
ENDIF
DO HarnessStep WITH 5, 'P4 caz 8c Renunta'
*========================= PAS 5 (CAZUL 11, rec_s2c): crestere cantitate pe tip FARA verificare
*========================= de stoc -> acceptata neconditionat (plafonul exista dar nu se verifica)
*-- tip=1 nu e in Inlist(poDate.tip,4,21,23,28,42,47) din inainte_de_do_termin, deci cresterea
*-- cantitatii nu are plafon real - verifica ca S2c (recalcularea plafonului pt. tipurile CU
*-- stoc) nu a introdus vreo restrictie neintentionata pe tipurile FARA verificare.
IF RECCOUNT('crsfactura') = 1
gcCazAct = 'CASE11_CANTITATE'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P5, caz 11): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF ABS(cantitate - 50) < 0.001
DO UILog WITH 'PASS P5 CAZUL 11 (rec_s2c): crestere cantitate pe tip fara verificare de stoc acceptata: cantitate=' + TRANSFORM(cantitate) + ' (asteptat 50)'
ELSE
DO UILog WITH 'FAIL P5 CAZUL 11 (rec_s2c): cantitate=' + TRANSFORM(cantitate) + ' (asteptat 50) - crestere respinsa sau neaplicata'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P5: nu exista randul (Reccount=' + TRANSFORM(RECCOUNT('crsfactura')) + ')'
ENDIF
DO HarnessStep WITH 6, 'P5 caz 11 plafon - final'
DO HarnessDone WITH 'done'
CATCH TO loExc
DO AfLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']'
DO HarnessDone WITH 'done-error'
ENDTRY
QUIT
*==================================================================================
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO AfLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
SET SAFETY OFF
LOCAL lcL
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
ENDPROC
PROCEDURE UILog
LPARAMETERS tcMsg
DO AfLog WITH tcMsg
ENDPROC
*-- FindCtl: referinta directa la un control prin Controls(i), potrivit dupa .Name - tehnica
*-- validata in test_modal_unlock_smoketest2.prg (accesul cu prefix direct pe o referinta obtinuta
*-- din _SCREEN.Forms a dat eroare 1925 in acel diagnostic; Controls(i) e calea sigura, folosita
*-- consecvent, inclusiv pentru nivelurile imbricate).
PROCEDURE FindCtl
LPARAMETERS toParent, tcName
LOCAL lnI, loGasit
loGasit = .NULL.
FOR lnI = 1 TO toParent.ControlCount
IF UPPER(toParent.Controls(lnI).Name) == UPPER(tcName)
loGasit = toParent.Controls(lnI)
ENDIF
ENDFOR
RETURN loGasit
ENDPROC
DEFINE CLASS dummyapp AS Custom
PROCEDURE ReadIni
LPARAMETERS tcSection, tcKey
RETURN ''
ENDPROC
PROCEDURE WriteIni
LPARAMETERS tcSection, tcKey, tcValue
RETURN .T.
ENDPROC
ENDDEFINE
DEFINE CLASS dummyexport AS Custom
PROCEDURE citesteSetareRegistru
LPARAMETERS tcCheie
RETURN ''
ENDPROC
ENDDEFINE
DEFINE CLASS dummyexecutor AS Custom
cEroare = ''
PROCEDURE oExecute
LPARAMETERS tcSql, tcCursor
IF USED(tcCursor)
USE IN (tcCursor)
ENDIF
CREATE CURSOR (tcCursor) (codmatf C(50))
RETURN 1
ENDPROC
PROCEDURE oReset
ENDPROC
ENDDEFINE
DEFINE CLASS driverdeblocare3 AS Custom
PROCEDURE Executa
*-- rulat la fiecare tick al _SCREEN.tmrDrvN2. Cauta FRM_ARTICOL_FACTURA prin _SCREEN.Forms,
*-- aplica interactiunea selectata de gcCazAct (setata de test INAINTE de fiecare click),
*-- si inchide dialogul (do_termin sau do_renunt, dupa caz).
LOCAL lnI, loForm, llGasit
gnDriverTick = gnDriverTick + 1
llGasit = .F.
FOR lnI = 1 TO _SCREEN.FormCount
IF UPPER(_SCREEN.Forms(lnI).Class) == 'FRM_ARTICOL_FACTURA'
loForm = _SCREEN.Forms(lnI)
llGasit = .T.
ENDIF
ENDFOR
IF glDlgTratat OR !llGasit
RETURN
ENDIF
DO AfLog WITH 'driver3 tick ' + TRANSFORM(gnDriverTick) + ' POTRIVIT (caz=' + gcCazAct + '), intru in interactiune'
LOCAL loBifa, loCantitateCtn, loCantitate, loPretCtvaCtn, loPretCtvaNat, loPretFtvaCtn, loPretFtvaNat, loRenunt
TRY
DO CASE
CASE gcCazAct == 'CASE6'
loBifa = FindCtl(loForm, 'ck_pret_cu_tva')
loBifa.Value = 1
loBifa.InteractiveChange()
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 1
loCantitate.InteractiveChange()
loPretCtvaCtn = FindCtl(loForm, 'Clb_pretctva')
loPretCtvaNat = FindCtl(loPretCtvaCtn, 'tx_suma_nat')
loPretCtvaNat.Value = 100
loPretCtvaNat.InteractiveChange()
DO AfLog WITH 'driver3 CASE6: bifa=1 cantitate=1 pretctva=100, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'CASE8_MOD_OFF'
loBifa = FindCtl(loForm, 'ck_pret_cu_tva')
loBifa.Value = 0
loBifa.InteractiveChange()
loPretFtvaCtn = FindCtl(loForm, 'Clb_pretftva')
loPretFtvaNat = FindCtl(loPretFtvaCtn, 'tx_suma_nat')
loPretFtvaNat.Value = 60
loPretFtvaNat.InteractiveChange()
DO AfLog WITH 'driver3 CASE8_MOD_OFF: bifa=0 pretftva=60, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'CASE8_MOD_ON'
loBifa = FindCtl(loForm, 'ck_pret_cu_tva')
loBifa.Value = 1
loBifa.InteractiveChange()
loPretCtvaCtn = FindCtl(loForm, 'Clb_pretctva')
loPretCtvaNat = FindCtl(loPretCtvaCtn, 'tx_suma_nat')
loPretCtvaNat.Value = 200
loPretCtvaNat.InteractiveChange()
DO AfLog WITH 'driver3 CASE8_MOD_ON: bifa=1 pretctva=200, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'CASE8_RENUNTA'
loPretCtvaCtn = FindCtl(loForm, 'Clb_pretctva')
loPretCtvaNat = FindCtl(loPretCtvaCtn, 'tx_suma_nat')
loPretCtvaNat.Value = 9999
loPretCtvaNat.InteractiveChange()
loRenunt = FindCtl(loForm, 'But_renunt1')
DO AfLog WITH 'driver3 CASE8_RENUNTA: pretctva tastat 9999, apas But_renunt1 (Renunta)'
loRenunt.Click()
CASE gcCazAct == 'CASE11_CANTITATE'
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 50
loCantitate.InteractiveChange()
DO AfLog WITH 'driver3 CASE11_CANTITATE: cantitate=50 (tip fara verificare de stoc), apas do_termin()'
loForm.do_termin()
OTHERWISE
DO AfLog WITH 'driver3: gcCazAct necunoscut [' + gcCazAct + ']'
ENDCASE
glDlgTratat = .T.
DO AfLog WITH 'driver3: interactiune REUSITA pentru caz=' + gcCazAct
CATCH TO loExcDrv
DO AfLog WITH 'driver3: CATCH caz=' + gcCazAct + ' ErrorNo=' + TRANSFORM(loExcDrv.ErrorNo) + ;
' Message=' + loExcDrv.Message + ' Procedure=' + loExcDrv.Procedure + ;
' LineNo=' + TRANSFORM(loExcDrv.LineNo) + ' LineContents=[' + loExcDrv.LineContents + ']'
ENDTRY
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,11 @@
# test_pret_cu_tva_nivel2.ps1 - wrapper peste harness-ul generic pentru testele Nivel 2
# (cazurile 6 si 8, S5, plan #7). Rulare: powershell -ExecutionPolicy Bypass -File test_pret_cu_tva_nivel2.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
-TestPrg (Join-Path $Teste 'test_pret_cu_tva_nivel2.prg') `
-Steps @('grid_gol_afisat', 'p0_grid_gol', 'p1_caz6', 'p2_caz8a', 'p3_caz8b', 'p4_caz8c', 'p5_caz11_plafon') `
-ShotsDir (Join-Path $Teste 'screenshots_nivel2') `
-SyncDir (Join-Path $Teste 'uisync_nivel2') `
-StepTimeoutSec 60 `
-ReadyTimeoutSec 90

View File

@@ -0,0 +1,506 @@
* test_pret_cu_tva_nivel2_retur.prg
* Test UI Nivel 2 (S5, plan #7) pentru RAMURA DE RETUR (tip 8/9) a plafonului recalculat de S2c
* (rec_s2c_ncantitatemax.md). Verificarea de plafon pentru retur (frm_articol_factura.
* inainte_de_do_termin, ofacturare.vc2:2265, "Nu se poate returna mai mult decat a fost facturat!")
* NU are garda de gestionabil/llStoculConteaza - se verifica NECONDITIONAT - deci articolul poate
* fi gestionabil=0, ceea ce pastreaza fluxul de adaugare pe calea SIMPLA (frm_articol_factura
* direct, fara do_alege_stoc), aceeasi infrastructura dovedita la cazurile 6/8.
*
* Cazuri (din rec_s2c_ncantitatemax.md, ramura retur - tip 8/9):
* PAS 0: adaugare linie retur (crsarticole.cantitate=10 "cat s-a facturat", id_c=3001) prin
* But_urmator1.Click() real -> crsfactura.cantitate=-10 (negat de do_initializeaza_articol
* pt. tip 8/9), crsarticole.cantitate scade la 0 (decrementata de do_adauga_articol).
* PAS 1: modificare DOAR de pret (cantitate neschimbata) -> trebuie ACCEPTATA (plafonul recalculat
* egaleaza cantitatea curenta a liniei: 0 - (-10) = 10 = Abs(-10), nu strict mai mare).
* PAS 2: se simuleaza o schimbare externa a stocului sursa (alt utilizator/proces a modificat
* cat mai e disponibil de returnat) - crsarticole.cantitate setat manual la 5 (NU e
* populare de crsfactura, e o schimbare pe cursorul SURSA, plauzibila in productie).
* PAS 3: crestere cantitate returnata la -12 (magnitudine 12) -> plafonul RECALCULAT e
* 5 - (-10) = 15, deci 12 <= 15 -> ACCEPTATA. Sub formula VECHE (ncantitatemax fixat la
* cantitatea curenta a liniei, magnitudine 10, nerecalculat), 12 > 10 ar fi fost RESPINSA -
* acesta e cazul care distinge formula veche de cea noua (S2c).
* PAS 4: crestere cantitate returnata la -20 (magnitudine 20) -> peste plafonul recalculat (15) ->
* RESPINSA cu mesajul "Nu se poate returna mai mult decat a fost facturat!"; iesire din
* dialog prin do_renunt() (nu do_termin(), care nu elibereaza formularul la respingere).
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog, gcSyncDir
gcUILog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\test_pret_cu_tva_nivel2_retur_log.txt"
gcSyncDir = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\uisync_nivel2_retur\"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
ON ERROR DO AfErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
TRY
LOCAL gcAppPath, lcPath
gcAppPath = "D:\ROA\ROAFACTURARE\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + ;
gcAppPath + 'COMUN\UTILE\CALENDAR;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EMAIL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + gcAppPath + 'COMUN\UTILE\NFXML;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
DO AfLog WITH 'SET PATH OK'
SET CLASSLIB TO (gcAppPath + "comun\clase\appwiz") ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms ADDITIVE
SET CLASSLIB TO ofacturare.vcx ADDITIVE
SET CLASSLIB TO ofacturare_comun.vcx ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO ctl32_statusbar.vcx ADDITIVE
SET CLASSLIB TO ctl32_common.vcx ADDITIVE
SET CLASSLIB TO ctl32_structs.vcx ADDITIVE
SET CLASSLIB TO ctl32_progressbar.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
SET CLASSLIB TO ofacturare_rapoarte ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO onom_curs ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO ferestre_cere_date ADDITIVE
SET CLASSLIB TO baza ADDITIVE
SET CLASSLIB TO caut ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO serii_numere ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO wwdialogs.vcx ADDITIVE
SET CLASSLIB TO _calendar.vcx ADDITIVE
SET CLASSLIB TO locale ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ocomenzi ADDITIVE
DO AfLog WITH 'SET CLASSLIB OK'
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg"
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO onomenclatoare.prg ADDITIVE
SET PROCEDURE TO onomenclatoare2.prg ADDITIVE
SET PROCEDURE TO oproceduri_rapoarte_fact.prg ADDITIVE
SET PROCEDURE TO email.prg ADDITIVE
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO odocumente ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO wwcodeupdate.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO cauta_alfa.prg ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO oproceduri_curs.prg ADDITIVE
SET PROCEDURE TO proceduri.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg ADDITIVE
SET PROCEDURE TO ofacturare.prg ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO wwApi.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO validare.prg ADDITIVE
SET PROCEDURE TO ofacturare_comun.prg ADDITIVE
SET PROCEDURE TO ofacturare_stoc.prg ADDITIVE
SET PROCEDURE TO pmenu.prg ADDITIVE
SET PROCEDURE TO ointroduceri.prg ADDITIVE
SET PROCEDURE TO ovariabile_globale.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO filebringer.prg ADDITIVE
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO oupdate.prg ADDITIVE
SET PROCEDURE TO procese.prg ADDITIVE
SET PROCEDURE TO version.prg ADDITIVE
SET PROCEDURE TO wwhttp.prg ADDITIVE
SET PROCEDURE TO xmlaccess.prg ADDITIVE
SET PROCEDURE TO xmlparser.prg ADDITIVE
SET PROCEDURE TO xdate.prg ADDITIVE
SET PROCEDURE TO suma_in_vorbe.prg ADDITIVE
SET PROCEDURE TO controllerecr ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
DO AfLog WITH 'SET PROCEDURE OK'
PUBLIC gnPc, gnPVal, gnPcant, gnPPretV, gnScadereStoc, gnMemProcDisc, gl406, gcAcces
PUBLIC gnModTotFact, gnRF_FACTURARE_FARA_STOC, gnPPret, gnPPretVal
gnPc = 2
gnPVal = 2
gnPcant = 3
gnPPretV = 4
gnPPret = 4
gnPPretVal = 4
gnScadereStoc = 0
gnMemProcDisc = 0
gl406 = .F.
gcAcces = "1;2;3;4;5;6;7;8;"
gnModTotFact = 0
gnRF_FACTURARE_FARA_STOC = 0
PUBLIC nror(65000)
PUBLIC goApp, goExport, goExecutor
goApp = CREATEOBJECT('dummyapp')
goExport = CREATEOBJECT('dummyexport')
goExecutor = CREATEOBJECT('dummyexecutor')
IF USED('jtva_coloane')
USE IN ('jtva_coloane')
ENDIF
CREATE CURSOR jtva_coloane (id_jtva_coloana N(14), denumire C(50), cota_tva N(6,2))
INSERT INTO jtva_coloane VALUES (1, 'TVA 21%', 21)
GO TOP IN jtva_coloane
IF USED('saft_taxtable')
USE IN ('saft_taxtable')
ENDIF
CREATE CURSOR saft_taxtable (taxname C(250), procent_taxa N(7,2), taxcode N(6), tva_livrari N(1))
INSERT INTO saft_taxtable VALUES ('301104-Achizitii de bunuri si servicii taxabile cu cota de 21%', 21, 301104, 1)
DO creeaza_facturacrs WITH 'crsfactura'
DO AfLog WITH 'crsfactura creat, Reccount=' + TRANSFORM(RECCOUNT('crsfactura'))
*-- crsarticole: cantitate=10 reprezinta "cat s-a facturat / e disponibil de returnat".
*-- gestionabil=0: verificarea de retur (:2265) nu are garda de gestionabil, deci ramane pe
*-- calea simpla (frm_articol_factura direct), dar plafonul tot se verifica.
IF USED('crsarticole')
USE IN ('crsarticole')
ENDIF
CREATE CURSOR crsarticole (id_articol N(10), Id_Pol N(10), id_gestiune N(10), denumire C(100), ;
codmat C(50), codbare C(50), gestionabil N(1), cantitate N(18,4), pret N(18,4), ;
pret_val N(18,4), preturi_cu_tva N(1), proc_tvav N(18,4), discount_unitar N(18,4), ;
discount_unitar_val N(18,4), pret_achizitie N(18,4), tip_valuta N(1), Curs N(18,4), ;
multiplicator N(10,4), Cont C(10), um C(10), serie C(30), lot C(30), explicatie C(200), ;
opt_facturare N(3), id_ctr N(10), numar_contract C(50), pretd N(18,4), id_valuta N(10), ;
nume_val C(20), nume_lista_preturi C(100), id_jtva_coloana N(10), taxcode N(6), id_c N(10))
INSERT INTO crsarticole (id_articol, Id_Pol, id_gestiune, denumire, codmat, codbare, ;
gestionabil, cantitate, pret, pret_val, preturi_cu_tva, proc_tvav, discount_unitar, ;
discount_unitar_val, pret_achizitie, tip_valuta, Curs, multiplicator, Cont, um, serie, ;
lot, explicatie, opt_facturare, id_ctr, numar_contract, pretd, id_valuta, nume_val, ;
nume_lista_preturi, id_jtva_coloana, taxcode, id_c) ;
VALUES (3001, 1, 1, 'ARTICOL RETUR NIVEL2', 'ART3001', '', ;
0, 10, 50, 0, 1, 1.21, 0, ;
0, 0, 0, 1, 1, '707', 'BUC', '', ;
'', '', 0, 0, '', 0, 0, '', ;
'LISTA TEST', 1, 0, 3001)
GO TOP IN crsarticole
DO AfLog WITH 'crsarticole (retur) creat, Reccount=' + TRANSFORM(RECCOUNT('crsarticole'))
PRIVATE poDate
poDate = CREATEOBJECT('oDateFactura')
poDate.tip = 8 && 8 = factura retur lei
poDate.serie_act = 'TST'
poDate.nract = 1
DO AfLog WITH 'poDate pregatit (oDateFactura), tip=' + TRANSFORM(poDate.tip)
PUBLIC goDriver, gnDriverTick, glDlgTratat, gcCazAct
gnDriverTick = 0
glDlgTratat = .F.
gcCazAct = ''
goDriver = CREATEOBJECT('driverdeblocare4')
_SCREEN.AddObject('tmrDrvN2R', 'Timer')
_SCREEN.tmrDrvN2R.Interval = 200
BINDEVENT(_SCREEN.tmrDrvN2R, 'Timer', goDriver, 'Executa')
_SCREEN.tmrDrvN2R.Enabled = .T.
DO AfLog WITH 'driver+timer pregatiti'
_SCREEN.Visible = .T.
_SCREEN.WindowState = 2
_SCREEN.Caption = 'TEST UI Nivel 2 - ramura retur (S2c)'
PUBLIC goFrm
goFrm = CREATEOBJECT('frm_facturare_articole')
goFrm.WindowType = 0
goFrm.Show()
goFrm.WindowState = 2
DOEVENTS FORCE
DO AfLog WITH 'frm_facturare_articole afisat modeless, Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
DO HarnessStep WITH 0, 'formular afisat, grid gol'
*========================= PAS 0: adaugare linie retur (cantitate default, neschimbata) =========
SELECT crsarticole
GO TOP
gcCazAct = 'ADD_DEFAULT'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_urmator1.Click()
DOEVENTS FORCE
LOCAL lnWait
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_urmator1: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
IF RECCOUNT('crsfactura') = 1
SELECT crsfactura
GO TOP
SELECT crsarticole
LOCATE FOR id_c = 3001
IF ABS(crsfactura.cantitate - (-10)) < 0.001 AND ABS(crsarticole.cantitate - 0) < 0.001
DO UILog WITH 'PASS P0 adaugare retur: crsfactura.cantitate=' + TRANSFORM(crsfactura.cantitate) + ' crsarticole.cantitate=' + TRANSFORM(crsarticole.cantitate) + ' (asteptat -10 / 0)'
ELSE
DO UILog WITH 'FAIL P0 adaugare retur: crsfactura.cantitate=' + TRANSFORM(crsfactura.cantitate) + ' crsarticole.cantitate=' + TRANSFORM(crsarticole.cantitate) + ' (asteptat -10 / 0)'
ENDIF
ELSE
DO UILog WITH 'FAIL P0: Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura')) + ' (asteptat 1) - articolul retur nu a fost adaugat'
ENDIF
DO HarnessStep WITH 1, 'P0 adaugare retur: Reccount=' + TRANSFORM(RECCOUNT('crsfactura'))
*========================= PAS 1: modificare DOAR de pret, cantitate neschimbata -> ACCEPTATA ===
IF RECCOUNT('crsfactura') = 1
gcCazAct = 'RETUR_DOAR_PRET'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P1): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF ABS(cantitate - (-10)) < 0.001 AND ABS(pretftva - 77) < 0.01
DO UILog WITH 'PASS P1 retur - doar pret modificat, ACCEPTAT: cantitate=' + TRANSFORM(cantitate) + ' pretftva=' + TRANSFORM(pretftva) + ' (asteptat -10 / 77)'
ELSE
DO UILog WITH 'FAIL P1 retur - doar pret: cantitate=' + TRANSFORM(cantitate) + ' pretftva=' + TRANSFORM(pretftva) + ' (asteptat -10 / 77 - verifica daca a fost respins pe nedrept)'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P1: nu exista randul'
ENDIF
DO HarnessStep WITH 2, 'P1 retur doar pret'
*========================= PAS 2: simulare schimbare externa a stocului sursa =========
SELECT crsarticole
LOCATE FOR id_c = 3001
IF FOUND()
REPLACE cantitate WITH 5
DO AfLog WITH 'P2: crsarticole.cantitate setat manual la 5 (simuleaza schimbare externa a stocului sursa, NU populare de crsfactura)'
ENDIF
DO HarnessStep WITH 3, 'P2 stoc extern schimbat'
*========================= PAS 3: crestere la -12 (in limita plafonului RECALCULAT=15, dar peste
*========================= plafonul VECHI fixat la 10) -> trebuie ACCEPTATA =========
IF RECCOUNT('crsfactura') = 1
gcCazAct = 'RETUR_CRESTERE_IN_PLAFON_NOU'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P3): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF ABS(cantitate - (-12)) < 0.001
DO UILog WITH 'PASS P3 retur - crestere la magnitudine 12 (peste plafonul VECHI=10, in plafonul NOU recalculat=15), ACCEPTATA: cantitate=' + TRANSFORM(cantitate) + ' - confirma ca S2c chiar RECALCULEAZA plafonul, nu il fixeaza la cantitatea initiala a liniei'
ELSE
DO UILog WITH 'FAIL P3 retur - crestere in plafonul nou: cantitate=' + TRANSFORM(cantitate) + ' (asteptat -12) - fie a fost respinsa (plafon nerecalculat), fie alta problema'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P3: nu exista randul'
ENDIF
DO HarnessStep WITH 4, 'P3 retur crestere in plafon nou'
*========================= PAS 4: crestere la -20 (peste plafonul NOU=15) -> RESPINSA =========
IF RECCOUNT('crsfactura') = 1
LOCAL lnCantitateInainte
SELECT crsfactura
GO TOP
lnCantitateInainte = cantitate
gcCazAct = 'RETUR_CRESTERE_PESTE_PLAFON'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa But_modifica1 (P4): glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
GO TOP
IF ABS(cantitate - lnCantitateInainte) < 0.001
DO UILog WITH 'PASS P4 retur - crestere la magnitudine 20 (peste plafonul nou=15) RESPINSA: randul a ramas neschimbat, cantitate=' + TRANSFORM(cantitate)
ELSE
DO UILog WITH 'FAIL P4 retur - crestere peste plafon: cantitate=' + TRANSFORM(cantitate) + ' (asteptat neschimbat, ' + TRANSFORM(lnCantitateInainte) + ') - a fost acceptata desi trebuia respinsa'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P4: nu exista randul'
ENDIF
DO HarnessStep WITH 5, 'P4 retur peste plafon - final'
DO HarnessDone WITH 'done'
CATCH TO loExc
DO AfLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']'
DO HarnessDone WITH 'done-error'
ENDTRY
QUIT
*==================================================================================
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO AfLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
SET SAFETY OFF
LOCAL lcL
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
ENDPROC
PROCEDURE UILog
LPARAMETERS tcMsg
DO AfLog WITH tcMsg
ENDPROC
PROCEDURE FindCtl
LPARAMETERS toParent, tcName
LOCAL lnI, loGasit
loGasit = .NULL.
FOR lnI = 1 TO toParent.ControlCount
IF UPPER(toParent.Controls(lnI).Name) == UPPER(tcName)
loGasit = toParent.Controls(lnI)
ENDIF
ENDFOR
RETURN loGasit
ENDPROC
DEFINE CLASS dummyapp AS Custom
PROCEDURE ReadIni
LPARAMETERS tcSection, tcKey
RETURN ''
ENDPROC
PROCEDURE WriteIni
LPARAMETERS tcSection, tcKey, tcValue
RETURN .T.
ENDPROC
ENDDEFINE
DEFINE CLASS dummyexport AS Custom
PROCEDURE citesteSetareRegistru
LPARAMETERS tcCheie
RETURN ''
ENDPROC
ENDDEFINE
DEFINE CLASS dummyexecutor AS Custom
cEroare = ''
PROCEDURE oExecute
LPARAMETERS tcSql, tcCursor
IF USED(tcCursor)
USE IN (tcCursor)
ENDIF
CREATE CURSOR (tcCursor) (codmatf C(50))
RETURN 1
ENDPROC
PROCEDURE oReset
ENDPROC
ENDDEFINE
DEFINE CLASS driverdeblocare4 AS Custom
PROCEDURE Executa
LOCAL lnI, loForm, llGasit
gnDriverTick = gnDriverTick + 1
llGasit = .F.
FOR lnI = 1 TO _SCREEN.FormCount
IF UPPER(_SCREEN.Forms(lnI).Class) == 'FRM_ARTICOL_FACTURA'
loForm = _SCREEN.Forms(lnI)
llGasit = .T.
ENDIF
ENDFOR
IF glDlgTratat OR !llGasit
RETURN
ENDIF
DO AfLog WITH 'driver4 tick ' + TRANSFORM(gnDriverTick) + ' POTRIVIT (caz=' + gcCazAct + '), intru in interactiune'
LOCAL loCantitateCtn, loCantitate, loPretFtvaCtn, loPretFtvaNat, loRenunt
TRY
DO CASE
CASE gcCazAct == 'ADD_DEFAULT'
DO AfLog WITH 'driver4 ADD_DEFAULT: nu ating nimic, apas do_termin() (accepta valorile implicite)'
loForm.do_termin()
CASE gcCazAct == 'RETUR_DOAR_PRET'
loPretFtvaCtn = FindCtl(loForm, 'Clb_pretftva')
loPretFtvaNat = FindCtl(loPretFtvaCtn, 'tx_suma_nat')
loPretFtvaNat.Value = 77
loPretFtvaNat.InteractiveChange()
DO AfLog WITH 'driver4 RETUR_DOAR_PRET: pretftva=77, cantitate neatinsa, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'RETUR_CRESTERE_IN_PLAFON_NOU'
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = -12
loCantitate.InteractiveChange()
DO AfLog WITH 'driver4 RETUR_CRESTERE_IN_PLAFON_NOU: cantitate=-12, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'RETUR_CRESTERE_PESTE_PLAFON'
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = -20
loCantitate.InteractiveChange()
DO AfLog WITH 'driver4 RETUR_CRESTERE_PESTE_PLAFON: cantitate=-20, apas do_termin() (asteptat: respins, ramane deschis)'
loForm.do_termin()
DO AfLog WITH 'driver4: dupa do_termin() pe cazul de respingere - inchid explicit prin do_renunt() ca sa nu ramana Show(1) blocat'
loForm.do_renunt()
OTHERWISE
DO AfLog WITH 'driver4: gcCazAct necunoscut [' + gcCazAct + ']'
ENDCASE
glDlgTratat = .T.
DO AfLog WITH 'driver4: interactiune REUSITA pentru caz=' + gcCazAct
CATCH TO loExcDrv
DO AfLog WITH 'driver4: CATCH caz=' + gcCazAct + ' ErrorNo=' + TRANSFORM(loExcDrv.ErrorNo) + ;
' Message=' + loExcDrv.Message + ' Procedure=' + loExcDrv.Procedure + ;
' LineNo=' + TRANSFORM(loExcDrv.LineNo) + ' LineContents=[' + loExcDrv.LineContents + ']'
ENDTRY
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,12 @@
# test_pret_cu_tva_nivel2_retur.ps1 - wrapper peste harness-ul generic pentru ramura de retur
# a plafonului recalculat (S2c, rec_s2c_ncantitatemax.md). Rulare:
# powershell -ExecutionPolicy Bypass -File test_pret_cu_tva_nivel2_retur.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
-TestPrg (Join-Path $Teste 'test_pret_cu_tva_nivel2_retur.prg') `
-Steps @('formular_afisat', 'p0_adaugare', 'p1_doar_pret', 'p2_stoc_extern', 'p3_in_plafon_nou', 'p4_peste_plafon') `
-ShotsDir (Join-Path $Teste 'screenshots_nivel2_retur') `
-SyncDir (Join-Path $Teste 'uisync_nivel2_retur') `
-StepTimeoutSec 60 `
-ReadyTimeoutSec 90

View File

@@ -0,0 +1,940 @@
* test_pret_cu_tva_nivel3_gestiuni.prg
* Test UI Nivel 3 (S2d, plan #7) pentru ramura GESTIONABILA a lui do_modifica/do_adauga_articol -
* dialogul frm_articol_gest_factura, deschis prin do_alege_stoc (frm_facturare_articole,
* ofacturare.vc2). Decizia coordonatorului: se mockuieste Oracle la GRANITA (goExecutor.oExecute,
* singurul punct de contact al lui do_alege_stoc cu Oracle), NU se populeaza direct crsgestarticol/
* crsfactura - fluxul real (butoane, taste, SPACE) ramane intact, doar sursa de date se inlocuieste.
*
* Articol 3001, gestionabil=1, gnScadereStoc=1, poDate.tip=4 (aviz - in Inlist-ul validat de
* inainte_de_do_termin SI de plafonul S2c/S2d). 4 gestiuni mock, stoc constant (10/15/8/6) - Oracle
* nu stie de cosul in lucru, exact ca in productie; scaderea celor deja pe factura o face codul
* real (sub-selectul cu excluderea id_temp, S2d pct. 1).
*
* Cazuri (litere din review-ul S2d):
* PAS 1 (caz a): adaugare linie1 din gestiunea G1 -> dialogul cu gestiuni arata mai multe
* gestiuni (nu auto-select), ck_pret_cu_tva exista si e la Top=510 pe forma Height=546.
* PAS 2: adaugare linie2 (acelasi articol) din gestiunea G2 - pregateste discriminantul de la c.
* PAS 3 (cazuri b+c): redeschide linia1 -> crsgestarticol pozitionat pe gestiunea G1 a liniei;
* randul G1 arata stocul disponibil PLUS cantitatea proprie (10, nu 7); randul G2 (linia2,
* neexclusa) arata stocul scazut normal (11, nu 15). Inchis cu Renunta, nimic comis.
* PAS 4 (caz d, respins): redeschide linia1, cere cantitate 11 (peste stocul gestiunii G1=10) ->
* respins cu mesajul real "Cantitatea nu poate fi mai mare decat stocul gestiunii ...".
* PAS 5 (caz d, acceptat): redeschide linia1, cere cantitate 10 (exact stocul gestiunii) ->
* acceptat.
* PAS 6 (caz e): redeschide linia1, navigheaza (fara SPACE) pe gestiunea G3, cantitate 5 ->
* acceptat, linia1 trece pe G3. Verifica si g) crsarticole ajustat cu diferenta (-5).
* PAS 7 (caz f+g): redeschide linia1, SPACE pe G1 si G4 (multi-selectie) -> linia1 devine G1/10,
* apare O SINGURA linie noua G4/6 (exact regresia Scan/Skip, deja corectata) - Reccount
* creste cu 1, nu cu 2. Verifica si crsarticole ajustat cu diferenta (delta 16-5=11).
* PAS 8 (caz h): redeschide linia1, schimba pretul, apasa Renunta -> randul ramane BIT-IDENTIC.
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog, gcSyncDir
gcUILog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\test_pret_cu_tva_nivel3_gestiuni_log.txt"
gcSyncDir = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_pret_cu_tva\uisync_nivel3\"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
ON ERROR DO AfErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
TRY
LOCAL gcAppPath, lcPath
gcAppPath = "D:\ROA\ROAFACTURARE\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + ;
gcAppPath + 'COMUN\UTILE\CALENDAR;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EMAIL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + gcAppPath + 'COMUN\UTILE\NFXML;' + ;
gcAppPath + 'COMUN\UTILE\GridExtras;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
DO AfLog WITH 'SET PATH OK'
*----- CLASE (lista dovedita de Nivel 1/2 - mediul unei suite noi se mosteneste din suita
* care TRECE, nu dintr-un smoke-test) -----
SET CLASSLIB TO (gcAppPath + "comun\clase\appwiz") ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms ADDITIVE
SET CLASSLIB TO ofacturare.vcx ADDITIVE
SET CLASSLIB TO ofacturare_comun.vcx ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO ctl32_statusbar.vcx ADDITIVE
SET CLASSLIB TO ctl32_common.vcx ADDITIVE
SET CLASSLIB TO ctl32_structs.vcx ADDITIVE
SET CLASSLIB TO ctl32_progressbar.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
SET CLASSLIB TO ofacturare_rapoarte ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO onom_curs ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO ferestre_cere_date ADDITIVE
SET CLASSLIB TO baza ADDITIVE
SET CLASSLIB TO caut ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO serii_numere ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO wwdialogs.vcx ADDITIVE
SET CLASSLIB TO _calendar.vcx ADDITIVE
SET CLASSLIB TO locale ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ocomenzi ADDITIVE
DO AfLog WITH 'SET CLASSLIB OK'
*----- PROCEDURI (mock amessagebox PRIMUL, ui_harness la final) -----
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg"
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO onomenclatoare.prg ADDITIVE
SET PROCEDURE TO onomenclatoare2.prg ADDITIVE
SET PROCEDURE TO oproceduri_rapoarte_fact.prg ADDITIVE
SET PROCEDURE TO email.prg ADDITIVE
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO odocumente ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO wwcodeupdate.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO cauta_alfa.prg ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO oproceduri_curs.prg ADDITIVE
SET PROCEDURE TO proceduri.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg ADDITIVE
SET PROCEDURE TO ofacturare.prg ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO wwApi.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO validare.prg ADDITIVE
SET PROCEDURE TO ofacturare_comun.prg ADDITIVE
SET PROCEDURE TO ofacturare_stoc.prg ADDITIVE
SET PROCEDURE TO pmenu.prg ADDITIVE
SET PROCEDURE TO ointroduceri.prg ADDITIVE
SET PROCEDURE TO ovariabile_globale.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO filebringer.prg ADDITIVE
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO oupdate.prg ADDITIVE
SET PROCEDURE TO procese.prg ADDITIVE
SET PROCEDURE TO version.prg ADDITIVE
SET PROCEDURE TO wwhttp.prg ADDITIVE
SET PROCEDURE TO xmlaccess.prg ADDITIVE
SET PROCEDURE TO xmlparser.prg ADDITIVE
SET PROCEDURE TO xdate.prg ADDITIVE
SET PROCEDURE TO suma_in_vorbe.prg ADDITIVE
SET PROCEDURE TO controllerecr ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
DO AfLog WITH 'SET PROCEDURE OK'
*----- Globale aplicatie -----
PUBLIC gnPc, gnPVal, gnPcant, gnPPretV, gnScadereStoc, gnMemProcDisc, gl406, gcAcces
PUBLIC gnModTotFact, gnRF_FACTURARE_FARA_STOC
gnModTotFact = 0
gnRF_FACTURARE_FARA_STOC = 0
PUBLIC gnPPret, gnPPretVal
gnPc = 2
gnPVal = 2
gnPcant = 3
gnPPretV = 4
gnPPret = 4
gnPPretVal = 4
gnScadereStoc = 1 && activeaza ramura de stoc - do_alege_stoc SE apeleaza (opusul Nivel 2)
gnMemProcDisc = 0
gl406 = .F.
gcAcces = "1;2;3;4;5;6;7;8;"
*-- do_alege_stoc citeste si aceste globale (parametri SQL cursor_gestiuni_articol) - lipsa lor
*-- da ON ERROR 12 "Variable not found" la primul apel
PUBLIC gnAn, gnLuna, gnIdUtil, gnIdSucursala
gnAn = YEAR(DATE())
gnLuna = MONTH(DATE())
gnIdUtil = 1
gnIdSucursala = 0
PUBLIC nror(65000)
*-- gcMockUltimMesaj: mock_amessagebox.prg memoreaza aici ultimul mesaj afisat - folosit pt.
*-- asertia pe TEXTUL respingerii de plafon (caz d).
PUBLIC gcMockUltimMesaj, gnMockUltimTip
gcMockUltimMesaj = ''
gnMockUltimTip = 0
PUBLIC goApp, goExport, goExecutor
goApp = CREATEOBJECT('dummyapp')
goExport = CREATEOBJECT('dummyexport')
goExecutor = CREATEOBJECT('dummyexecutor')
IF USED('jtva_coloane')
USE IN ('jtva_coloane')
ENDIF
CREATE CURSOR jtva_coloane (id_jtva_coloana N(14), denumire C(50), cota_tva N(6,2))
INSERT INTO jtva_coloane VALUES (1, 'TVA 21%', 21)
INSERT INTO jtva_coloane VALUES (2, 'TVA 11%', 11)
GO TOP IN jtva_coloane
IF USED('saft_taxtable')
USE IN ('saft_taxtable')
ENDIF
CREATE CURSOR saft_taxtable (taxname C(250), procent_taxa N(7,2), taxcode N(6), tva_livrari N(1))
INSERT INTO saft_taxtable VALUES ('301104-Achizitii de bunuri si servicii taxabile cu cota de 21%', 21, 301104, 1)
INSERT INTO saft_taxtable VALUES ('3011XX-Achizitii de bunuri si servicii taxabile cu cota de 11%', 11, 301108, 1)
*----- crsfactura: structura REALA, fara Oracle -----
DO creeaza_facturacrs WITH 'crsfactura'
DO AfLog WITH 'crsfactura creat, Reccount=' + TRANSFORM(RECCOUNT('crsfactura'))
*----- crsarticole: sursa (stoc/lista de preturi). Articolul 3001, gestionabil=1, cantitate mare
* (plafonul S2c/S2d ramane generos - testele de mai jos verifica plafonul PE LOT din
* dialogul de gestiuni, nu plafonul pe articol din crsarticole). -----
IF USED('crsarticole')
USE IN ('crsarticole')
ENDIF
CREATE CURSOR crsarticole (id_articol N(10), Id_Pol N(10), id_gestiune N(10), denumire C(100), ;
codmat C(50), codbare C(50), gestionabil N(1), cantitate N(18,4), pret N(18,4), ;
pret_val N(18,4), preturi_cu_tva N(1), proc_tvav N(18,4), discount_unitar N(18,4), ;
discount_unitar_val N(18,4), pret_achizitie N(18,4), tip_valuta N(1), Curs N(18,4), ;
multiplicator N(10,4), Cont C(10), um C(10), serie C(30), lot C(30), explicatie C(200), ;
opt_facturare N(3), id_ctr N(10), numar_contract C(50), pretd N(18,4), id_valuta N(10), ;
nume_val C(20), nume_lista_preturi C(100), id_jtva_coloana N(10), taxcode N(6), id_c N(10))
INSERT INTO crsarticole (id_articol, Id_Pol, id_gestiune, denumire, codmat, codbare, ;
gestionabil, cantitate, pret, pret_val, preturi_cu_tva, proc_tvav, discount_unitar, ;
discount_unitar_val, pret_achizitie, tip_valuta, Curs, multiplicator, Cont, um, serie, ;
lot, explicatie, opt_facturare, id_ctr, numar_contract, pretd, id_valuta, nume_val, ;
nume_lista_preturi, id_jtva_coloana, taxcode, id_c) ;
VALUES (3001, 1, 0, 'ARTICOL GESTIUNI NIVEL3', 'ART3001', '', ;
1, 1000, 50, 0, 0, 1.21, 0, ;
0, 0, 0, 1, 1, '701', 'BUC', '', ;
'', '', 0, 0, '', 0, 0, '', ;
'LISTA TEST', 1, 0, 3001)
GO TOP IN crsarticole
DO AfLog WITH 'crsarticole creat, Reccount=' + TRANSFORM(RECCOUNT('crsarticole'))
*----- crsMockStoc: gestiunile "Oracle" pentru articolul 3001, stoc FIX pe tot testul - Oracle
* nu stie de cosul in lucru; scaderea celor deja pe factura o face codul real (LEFT JOIN +
* excluderea id_temp, S2d pct. 1), nu mock-ul. dummyexecutor.oExecute o serveste la fiecare
* apel cu 'cursor_gestiuni_articol' in SQL. Coloanele sunt exact cele citite de do_alege_stoc
* (Insert Into (lcCursor) (...), ofacturare.vc2:13299, si copiaza_structura_cursor). -----
IF USED('crsMockStoc')
USE IN ('crsMockStoc')
ENDIF
*-- Cont/serie/lot cu ACEEASI latime ca in crsfactura (creeaza_facturacrs: Cont c(4), serie c(100),
*-- lot C(20)) - LEFT JOIN-ul din do_alege_stoc compara aceste campuri intre cele doua cursoare
*-- (:13304-13306); latimi diferite ar produce padding diferit si ar rupe egalitatea sub SET EXACT ON.
*-- datain e DateTime (T), nu Date: coloana cDataIn a gridului are ControlSource "TTOD(datain)"
*-- (ofacturare.vc2:3519), iar TTOD pe un camp D da eroarea 11 la constructia formularului.
CREATE CURSOR crsMockStoc (ales N(1), id_gestiune N(10), cantitate N(18,4), Cont C(4), ;
serie C(100), lot C(20), Pret N(18,4), nume_gestiune C(50), datain T, pretv N(18,4), ;
pretvctva N(18,4), part_rez C(30), id_part_rez N(10), nrord_rez N(10), id_lucrare_rez N(10), ;
pretd N(18,4), id_valuta N(10), nume_val C(20))
INSERT INTO crsMockStoc VALUES (0, 101, 10, '701', 'SG1', 'LOT1', 50, 'GESTIUNE 1', {^2020-01-01 08:00:00}, 50, 60.50, '', 0, 0, 0, 0, 0, '')
INSERT INTO crsMockStoc VALUES (0, 102, 15, '701', 'SG2', 'LOT2', 55, 'GESTIUNE 2', {^2020-01-02 08:00:00}, 55, 66.55, '', 0, 0, 0, 0, 0, '')
INSERT INTO crsMockStoc VALUES (0, 103, 8, '701', 'SG3', 'LOT3', 52, 'GESTIUNE 3', {^2020-01-03 08:00:00}, 52, 62.92, '', 0, 0, 0, 0, 0, '')
INSERT INTO crsMockStoc VALUES (0, 104, 6, '701', 'SG4', 'LOT4', 48, 'GESTIUNE 4', {^2020-01-04 08:00:00}, 48, 58.08, '', 0, 0, 0, 0, 0, '')
GO TOP IN crsMockStoc
DO AfLog WITH 'crsMockStoc creat (4 gestiuni, stoc 10/15/8/6), Reccount=' + TRANSFORM(RECCOUNT('crsMockStoc'))
*----- poDate: clasa REALA oDateFactura -----
PRIVATE poDate
poDate = CREATEOBJECT('oDateFactura')
poDate.tip = 4 && 4 = aviz - in Inlist-ul validat de inainte_de_do_termin SI de plafonul S2c/S2d
poDate.serie_act = 'TST'
poDate.nract = 1
DO AfLog WITH 'poDate pregatit (oDateFactura), tip=' + TRANSFORM(poDate.tip) + ' gnScadereStoc=' + TRANSFORM(gnScadereStoc)
*----- driverul de deblocare Show(1): Timer la nivel _SCREEN + _SCREEN.Forms + Controls(i),
* mecanism validat (test_modal_unlock_smoketest2.prg / Nivel 2). De data asta cauta
* FRM_ARTICOL_GEST_FACTURA, nu FRM_ARTICOL_FACTURA. -----
PUBLIC goDriver, gnDriverTick, glDlgTratat, gcCazAct
gnDriverTick = 0
glDlgTratat = .F.
gcCazAct = ''
goDriver = CREATEOBJECT('driverdeblocaregest')
_SCREEN.AddObject('tmrDrvN3', 'Timer')
_SCREEN.tmrDrvN3.Interval = 200
BINDEVENT(_SCREEN.tmrDrvN3, 'Timer', goDriver, 'Executa')
_SCREEN.tmrDrvN3.Enabled = .T.
DO AfLog WITH 'driver+timer pregatiti (cauta FRM_ARTICOL_GEST_FACTURA)'
*----- Desktop VFP vizibil, ca la celelalte suite UI -----
_SCREEN.Visible = .T.
_SCREEN.WindowState = 2
_SCREEN.Caption = 'TEST UI Nivel 3 (S2d - ramura gestiuni)'
PUBLIC goFrm
goFrm = CREATEOBJECT('frm_facturare_articole')
goFrm.WindowType = 0 && testul instantiaza direct - modeless, Show() revine imediat
goFrm.Show()
goFrm.WindowState = 2
DOEVENTS FORCE
DO AfLog WITH 'frm_facturare_articole afisat modeless, Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
DO HarnessStep WITH 0, 'formular afisat, mediu pregatit'
*-- Local-e folosite pe tot parcursul --
LOCAL lnWait, lnIdTempLinie1, lnIdTempLinie2, lnArtStocInainte, lnArtStocDupa
*========================= PAS 1 (caz a): adaugare linie1 din G1 =========================
SELECT crsarticole
GO TOP
gcCazAct = 'ADD_G1_Q3'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_urmator1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa ADD_G1_Q3: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
IF RECCOUNT('crsfactura') = 1
SELECT crsfactura
GO TOP
lnIdTempLinie1 = id_temp
IF id_gestiune = 101 AND ABS(cantitate - 3) < 0.001
DO UILog WITH 'PASS P1 (caz a) linia1 adaugata din G1: id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' pret_achizitie=' + TRANSFORM(pret_achizitie)
ELSE
DO UILog WITH 'FAIL P1 (caz a) linia1: id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' (asteptat id_gestiune=101 cantitate=3)'
ENDIF
ELSE
DO UILog WITH 'FAIL P1 (caz a): Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura')) + ' (asteptat 1) - linia1 nu a fost adaugata'
ENDIF
DO HarnessStep WITH 1, 'P1 linia1 adaugata din G1'
*========================= PAS 2: adaugare linie2 (acelasi articol) din G2 =========================
SELECT crsarticole
GO TOP
gcCazAct = 'ADD_G2_Q4'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_urmator1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa ADD_G2_Q4: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
IF RECCOUNT('crsfactura') = 2
SELECT crsfactura
LOCATE FOR id_gestiune = 102
IF FOUND()
lnIdTempLinie2 = id_temp
IF ABS(cantitate - 4) < 0.001
DO UILog WITH 'PASS P2 linia2 adaugata din G2: cantitate=' + TRANSFORM(cantitate)
ELSE
DO UILog WITH 'FAIL P2 linia2: cantitate=' + TRANSFORM(cantitate) + ' (asteptat 4)'
ENDIF
ELSE
DO UILog WITH 'FAIL P2: nu exista rand cu id_gestiune=102'
ENDIF
ELSE
DO UILog WITH 'FAIL P2: Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura')) + ' (asteptat 2)'
ENDIF
DO HarnessStep WITH 2, 'P2 linia2 adaugata din G2'
*========================= PAS 3 (cazuri b+c): redeschide linia1, verifica preselectia si
*========================= excluderea id_temp, apoi Renunta (nimic comis) =========================
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
gcCazAct = 'MOD_L1_PRESELECT_CHECK'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_PRESELECT_CHECK: glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
IF RECCOUNT('crsfactura') = 2 AND FOUND() AND id_gestiune = 101 AND ABS(cantitate - 3) < 0.001
DO UILog WITH 'PASS P3 (caz b+c, Renunta) nimic comis: Reccount=2, linia1 neschimbata (G1/3)'
ELSE
DO UILog WITH 'FAIL P3 (caz b+c, Renunta): Reccount=' + TRANSFORM(RECCOUNT('crsfactura')) + ' found=' + TRANSFORM(FOUND()) + ' id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' (asteptat 2 / 101 / 3)'
ENDIF
DO HarnessStep WITH 3, 'P3 cazuri b+c - preselectie si excludere id_temp'
*========================= PAS 4 (caz d, respins): redeschide linia1, cere 11 (peste stocul G1=10) =========================
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
gcCazAct = 'MOD_L1_REJECT_OVER_LOT'
glDlgTratat = .F.
gnDriverTick = 0
gcMockUltimMesaj = ''
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_REJECT_OVER_LOT: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' mesaj=[' + gcMockUltimMesaj + ']'
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
IF ABS(cantitate - 3) < 0.001 AND 'stocul gestiunii' $ gcMockUltimMesaj
DO UILog WITH 'PASS P4 (caz d, respins) cantitate 11 peste stocul G1(10) respinsa, linia neschimbata (cantitate=' + TRANSFORM(cantitate) + '), mesaj=[' + gcMockUltimMesaj + ']'
ELSE
DO UILog WITH 'FAIL P4 (caz d, respins): cantitate=' + TRANSFORM(cantitate) + ' (asteptat 3, neschimbata) mesaj=[' + gcMockUltimMesaj + ']'
ENDIF
DO HarnessStep WITH 4, 'P4 caz d - respins peste plafonul lotului'
*========================= PAS 5 (caz d, acceptat): redeschide linia1, cere exact 10 =========================
SELECT crsarticole
lnArtStocInainte = cantitate
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
gcCazAct = 'MOD_L1_ACCEPT_AT_LOT'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_ACCEPT_AT_LOT: glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
IF ABS(cantitate - 10) < 0.001 AND id_gestiune = 101
DO UILog WITH 'PASS P5 (caz d, acceptat) cantitate 10 (exact stocul G1) acceptata: cantitate=' + TRANSFORM(cantitate)
ELSE
DO UILog WITH 'FAIL P5 (caz d, acceptat): cantitate=' + TRANSFORM(cantitate) + ' id_gestiune=' + TRANSFORM(id_gestiune) + ' (asteptat 10 / 101)'
ENDIF
*-- caz g: cantitatea liniei a crescut de la 3 la 10 (delta +7) -> crsarticole trebuie sa scada cu 7
SELECT crsarticole
lnArtStocDupa = cantitate
IF ABS((lnArtStocInainte - lnArtStocDupa) - 7) < 0.001
DO UILog WITH 'PASS P5 (caz g) crsarticole ajustat cu diferenta: ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (-7, cantitatea liniei a crescut 3->10)'
ELSE
DO UILog WITH 'FAIL P5 (caz g): crsarticole ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (asteptat -7)'
ENDIF
DO HarnessStep WITH 5, 'P5 caz d - acceptat la exact plafonul lotului'
*========================= PAS 6 (caz e + g): navigheaza (fara SPACE) pe G3, cantitate 5 =========================
*-- martorul se ia AICI: cel din PAS 5 masoara efectul lui PAS 5, nu al lui PAS 6
SELECT crsarticole
lnArtStocInainte = cantitate
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
gcCazAct = 'MOD_L1_CHANGE_GESTIUNE_NAV'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_CHANGE_GESTIUNE_NAV: glDlgTratat=' + TRANSFORM(glDlgTratat)
SELECT crsarticole
lnArtStocDupa = cantitate
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
IF id_gestiune = 103 AND ABS(cantitate - 5) < 0.001 AND ABS(pret_achizitie - 52) < 0.001
DO UILog WITH 'PASS P6 (caz e) schimbare gestiune prin navigare (fara SPACE): id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' pret_achizitie=' + TRANSFORM(pret_achizitie)
ELSE
DO UILog WITH 'FAIL P6 (caz e): id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' pret_achizitie=' + TRANSFORM(pret_achizitie) + ' (asteptat 103 / 5 / 52)'
ENDIF
*-- caz g: cantitatea liniei a scazut de la 10 la 5 (delta -5) -> crsarticole trebuie sa creasca cu 5
IF ABS((lnArtStocDupa - lnArtStocInainte) - 5) < 0.001
DO UILog WITH 'PASS P6 (caz g) crsarticole ajustat cu diferenta: ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (+5, cantitatea liniei a scazut 10->5)'
ELSE
DO UILog WITH 'FAIL P6 (caz g): crsarticole ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (asteptat +5)'
ENDIF
DO HarnessStep WITH 6, 'P6 caz e+g - schimbare gestiune prin navigare + sincronizare crsarticole'
*========================= PAS 7 (caz f + g): multi-selectie SPACE pe G1 si G4 =========================
SELECT crsarticole
lnArtStocInainte = cantitate
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
gcCazAct = 'MOD_L1_MULTISELECT'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_MULTISELECT: glDlgTratat=' + TRANSFORM(glDlgTratat) + ' Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura'))
SELECT crsarticole
lnArtStocDupa = cantitate
IF RECCOUNT('crsfactura') = 3
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
LOCAL llL1ok, llL2ok, llNouaOk
llL1ok = (id_gestiune = 101 AND ABS(cantitate - 10) < 0.001)
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie2
llL2ok = FOUND() AND id_gestiune = 102 AND ABS(cantitate - 4) < 0.001
SELECT crsfactura
LOCATE FOR id_gestiune = 104
llNouaOk = FOUND() AND ABS(cantitate - 6) < 0.001 AND id_temp <> lnIdTempLinie1 AND id_temp <> lnIdTempLinie2
IF llL1ok AND llL2ok AND llNouaOk
DO UILog WITH 'PASS P7 (caz f) multi-selectie: Reccount=3 (linia1 actualizata G1/10, linia2 neschimbata G2/4, O SINGURA linie noua G4/6 - fara duplicat)'
ELSE
DO UILog WITH 'FAIL P7 (caz f): llL1ok=' + TRANSFORM(llL1ok) + ' llL2ok=' + TRANSFORM(llL2ok) + ' llNouaOk=' + TRANSFORM(llNouaOk)
ENDIF
ELSE
DO UILog WITH 'FAIL P7 (caz f): Reccount(crsfactura)=' + TRANSFORM(RECCOUNT('crsfactura')) + ' (asteptat 3 - daca e 4, a reaparut regresia Scan/Skip cu linie duplicat)'
ENDIF
*-- caz g: cantitatea totala a articolului pe factura a crescut de la 5+4=9 la 10+6+4=20, delta +11 -> crsarticole trebuie sa scada cu 11
IF ABS((lnArtStocInainte - lnArtStocDupa) - 11) < 0.001
DO UILog WITH 'PASS P7 (caz g) crsarticole ajustat cu diferenta: ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (-11, cantitatea totala a crescut de la 5 la 16 pe aceasta redeschidere)'
ELSE
DO UILog WITH 'FAIL P7 (caz g): crsarticole ' + TRANSFORM(lnArtStocInainte) + ' -> ' + TRANSFORM(lnArtStocDupa) + ' (asteptat -11)'
ENDIF
DO HarnessStep WITH 7, 'P7 caz f+g - multi-selectie si sincronizare crsarticole'
*========================= PAS 8 (caz h): Renunta pe dialogul cu gestiuni - rand bit-identic =========================
IF RECCOUNT('crsfactura') >= 1
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
IF FOUND()
LOCAL ARRAY laSnapDinainte[1]
LOCAL lnF, lnCampuri
SCATTER TO laSnapDinainte
gcCazAct = 'MOD_L1_RENUNTA'
glDlgTratat = .F.
gnDriverTick = 0
goFrm.But_modifica1.Click()
DOEVENTS FORCE
lnWait = 0
DO WHILE !glDlgTratat AND lnWait < 150
DOEVENTS FORCE
lnWait = lnWait + 1
ENDDO
DO AfLog WITH 'dupa MOD_L1_RENUNTA: glDlgTratat=' + TRANSFORM(glDlgTratat)
LOCAL ARRAY laSnapDupa[1]
SELECT crsfactura
LOCATE FOR id_temp = lnIdTempLinie1
SCATTER TO laSnapDupa
LOCAL llIdentic
llIdentic = (ALEN(laSnapDinainte,1) == ALEN(laSnapDupa,1))
lnCampuri = 0
IF llIdentic
FOR lnF = 1 TO ALEN(laSnapDinainte,1)
lnCampuri = lnCampuri + 1
IF !(TRANSFORM(laSnapDinainte(lnF)) == TRANSFORM(laSnapDupa(lnF)))
llIdentic = .F.
DO AfLog WITH 'P8 diagnostic - campul ' + TRANSFORM(lnF) + ' difera: [' + ;
TRANSFORM(laSnapDinainte(lnF)) + '] -> [' + TRANSFORM(laSnapDupa(lnF)) + ']'
ENDIF
ENDFOR
ENDIF
IF llIdentic
DO UILog WITH 'PASS P8 (caz h) Renunta pe dialogul cu gestiuni: randul ramane BIT-IDENTIC (' + TRANSFORM(lnCampuri) + ' campuri comparate)'
ELSE
DO UILog WITH 'FAIL P8 (caz h): randul S-A MODIFICAT desi s-a apasat Renunta (vezi diag pe campuri mai sus)'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P8: linia1 (id_temp=' + TRANSFORM(lnIdTempLinie1) + ') nu mai exista'
ENDIF
ELSE
DO UILog WITH 'NEACOPERIT P8: crsfactura gol'
ENDIF
DO HarnessStep WITH 8, 'P8 caz h - Renunta bit-identic'
DO HarnessDone WITH 'done'
CATCH TO loExc
DO AfLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']'
*-- DIAGNOSTIC temporar: AERROR() suplimentar, stare crsgestarticol, si o proba izolata de
*-- CREATEOBJECT("frm_articol_gest_factura",...) cu poArticol construit liber (ca Nivel 1) -
*-- separa o cauza de MEDIU (clase/globale) de una legata de FORMA lui poArticol produs de
*-- fluxul real (do_initializeaza_articol).
LOCAL ARRAY laErrDiag(1)
LOCAL lnEd
=AERROR(laErrDiag)
FOR lnEd = 1 TO ALEN(laErrDiag,1)
DO AfLog WITH 'AERROR[' + TRANSFORM(lnEd) + ']=' + TRANSFORM(NVL(laErrDiag(lnEd),'.NULL.'))
ENDFOR
DO AfLog WITH 'DIAG: USED(crsgestarticol)=' + TRANSFORM(USED('crsgestarticol')) + IIF(USED('crsgestarticol'), ' Reccount=' + TRANSFORM(RECCOUNT('crsgestarticol')), '')
LOCAL lnPi, loProba
LOCAL ARRAY laPPropN(49), laPPropC(11)
laPPropN( 1)='id_articol'
laPPropN( 2)='Id_Pol'
laPPropN( 3)='id_gestiune'
laPPropN( 4)='id_c'
laPPropN( 5)='id_ctr'
laPPropN( 6)='id_valuta'
laPPropN( 7)='id_valuta_d'
laPPropN( 8)='id_lucrare_rez'
laPPropN( 9)='id_part_rez'
laPPropN(10)='id_jtva_coloana'
laPPropN(11)='taxcode'
laPPropN(12)='opt_facturare'
laPPropN(13)='gestionabil'
laPPropN(14)='tip_valuta'
laPPropN(15)='cantitate'
laPPropN(16)='Curs'
laPPropN(17)='multiplicator'
laPPropN(18)='pret_achizitie'
laPPropN(19)='pretv_orig'
laPPropN(20)='pretd'
laPPropN(21)='proc_tvav'
laPPropN(22)='preturi_cu_tva'
laPPropN(23)='pretftva'
laPPropN(24)='pretftva_val'
laPPropN(25)='pretctva'
laPPropN(26)='pretctva_val'
laPPropN(27)='tva'
laPPropN(28)='tva_val'
laPPropN(29)='discount_unitar'
laPPropN(30)='discount_unitar_val'
laPPropN(31)='discount_unitar_ctva'
laPPropN(32)='discount_unitar_ctva_val'
laPPropN(33)='valftva'
laPPropN(34)='valtva'
laPPropN(35)='valctva'
laPPropN(36)='valdiscountftva'
laPPropN(37)='valdiscounttva'
laPPropN(38)='valdiscountctva'
laPPropN(39)='valdiminuatftva'
laPPropN(40)='valdiminuattva'
laPPropN(41)='valdiminuatctva'
laPPropN(42)='vvalftva'
laPPropN(43)='vvaltva'
laPPropN(44)='vvalctva'
laPPropN(45)='vvaldiscountftva'
laPPropN(46)='vvaldiscounttva'
laPPropN(47)='vvaldiscountctva'
laPPropN(48)='vvaldiminuatftva'
laPPropN(49)='vvaldiminuattva'
laPPropC( 1)='codmat'
laPPropC( 2)='codmatf'
laPPropC( 3)='denumire'
laPPropC( 4)='um'
laPPropC( 5)='serie'
laPPropC( 6)='lot'
laPPropC( 7)='explicatie'
laPPropC( 8)='numar_contract'
laPPropC( 9)='codbare'
laPPropC(10)='nume_val'
laPPropC(11)='Cont'
PRIVATE poArticol
poArticol = CREATEOBJECT('Empty')
FOR lnPi = 1 TO 49
=ADDPROPERTY(poArticol, laPPropN(lnPi), 0)
ENDFOR
=ADDPROPERTY(poArticol, 'vvaldiminuatctva', 0)
FOR lnPi = 1 TO 11
=ADDPROPERTY(poArticol, laPPropC(lnPi), '')
ENDFOR
poArticol.id_articol = 3001
poArticol.Id_Pol = 1
poArticol.Cont = '701'
poArticol.id_gestiune = 101
poArticol.gestionabil = 1
poArticol.tip_valuta = 0
poArticol.Curs = 1
poArticol.multiplicator = 1
poArticol.cantitate = 3
poArticol.codmat = 'ART3001'
poArticol.denumire = 'ARTICOL GESTIUNI NIVEL3'
poArticol.um = 'BUC'
poArticol.proc_tvav = 1.21
poArticol.preturi_cu_tva = 0
poArticol.pretftva = 50
poArticol.pretctva = 60.5
TRY
loProba = CREATEOBJECT('frm_articol_gest_factura', 3, .F., .F.)
DO AfLog WITH 'DIAG PROBA: CREATEOBJECT reusit izolat, Class=' + loProba.Class
loProba.Release()
CATCH TO loExcProba
DO AfLog WITH 'DIAG PROBA: CATCH ErrorNo=' + TRANSFORM(loExcProba.ErrorNo) + ' Message=' + loExcProba.Message + ' Proc=' + loExcProba.Procedure + ' Line=' + TRANSFORM(loExcProba.LineNo) + ' [' + loExcProba.LineContents + ']'
ENDTRY
DO HarnessDone WITH 'done-error'
ENDTRY
QUIT
*==================================================================================
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO AfLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
SET SAFETY OFF
LOCAL lcL
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
ENDPROC
PROCEDURE UILog
LPARAMETERS tcMsg
DO AfLog WITH tcMsg
ENDPROC
*-- FindCtl: referinta directa la un control prin Controls(i), potrivit dupa .Name - tehnica
*-- validata in test_modal_unlock_smoketest2.prg / Nivel 2 (accesul cu prefix direct pe o referinta
*-- obtinuta din _SCREEN.Forms da eroare 1925; Controls(i) e calea sigura).
PROCEDURE FindCtl
LPARAMETERS toParent, tcName
LOCAL lnI, loGasit
loGasit = .NULL.
FOR lnI = 1 TO toParent.ControlCount
IF UPPER(toParent.Controls(lnI).Name) == UPPER(tcName)
loGasit = toParent.Controls(lnI)
ENDIF
ENDFOR
RETURN loGasit
ENDPROC
DEFINE CLASS dummyapp AS Custom
PROCEDURE ReadIni
LPARAMETERS tcSection, tcKey
RETURN ''
ENDPROC
PROCEDURE WriteIni
LPARAMETERS tcSection, tcKey, tcValue
RETURN .T.
ENDPROC
ENDDEFINE
DEFINE CLASS dummyexport AS Custom
PROCEDURE citesteSetareRegistru
LPARAMETERS tcCheie
RETURN ''
ENDPROC
ENDDEFINE
*-- dummyexecutor: mock la GRANITA (goExecutor.oExecute e singurul punct de contact al lui
*-- do_alege_stoc cu Oracle, ofacturare.vc2:13254). Ramifica pe continutul SQL-ului: cererile
*-- 'cursor_gestiuni_articol*' (normal/_retur/_stoc0 - toate three trec prin acelasi mock, textul
*-- nu se distinge in teste, doar sursa comuna crsMockStoc) primesc structura+datele din
*-- crsMockStoc; orice alta interogare (ex. select codmatf ... from nom_articole, apelata dupa
*-- gnButon=1) primeste comportamentul implicit de dinainte (cursor gol cu un singur camp).
DEFINE CLASS dummyexecutor AS Custom
cEroare = ''
PROCEDURE oExecute
LPARAMETERS tcSql, tcCursor
IF USED(tcCursor)
USE IN (tcCursor)
ENDIF
IF 'CURSOR_GESTIUNI_ARTICOL' $ UPPER(tcSql)
SELECT * FROM crsMockStoc INTO CURSOR (tcCursor) READWRITE
ELSE
CREATE CURSOR (tcCursor) (codmatf C(50))
ENDIF
RETURN 1
ENDPROC
PROCEDURE oPrelucrareEroare
RETURN cEroare
ENDPROC
PROCEDURE oReset
ENDPROC
ENDDEFINE
DEFINE CLASS driverdeblocaregest AS Custom
PROCEDURE Executa
*-- rulat la fiecare tick al _SCREEN.tmrDrvN3. Cauta FRM_ARTICOL_GEST_FACTURA (nu
*-- FRM_ARTICOL_FACTURA - dialogul cu gridul de gestiuni, deschis de do_alege_stoc),
*-- aplica interactiunea selectata de gcCazAct, inchide dialogul (do_termin sau
*-- But_renunt1.Click(), dupa caz).
LOCAL lnI, loForm, llGasit
gnDriverTick = gnDriverTick + 1
llGasit = .F.
FOR lnI = 1 TO _SCREEN.FormCount
IF UPPER(_SCREEN.Forms(lnI).Class) == 'FRM_ARTICOL_GEST_FACTURA'
loForm = _SCREEN.Forms(lnI)
llGasit = .T.
ENDIF
ENDFOR
IF glDlgTratat OR !llGasit
RETURN
ENDIF
DO AfLog WITH 'driverGest tick ' + TRANSFORM(gnDriverTick) + ' POTRIVIT (caz=' + gcCazAct + '), intru in interactiune'
LOCAL loCantitateCtn, loCantitate, loBifa, loRenunt, loGrid
TRY
DO CASE
CASE gcCazAct == 'ADD_G1_Q3'
*-- caz a: dialogul cu gestiuni s-a deschis pe mai multe gestiuni (nu auto-select);
*-- verific ck_pret_cu_tva (mostenit din frm_articol_factura, S2a) - existenta si layout.
loBifa = FindCtl(loForm, 'ck_pret_cu_tva')
IF VARTYPE(loBifa) = 'O'
IF loForm.Height = 546 AND loBifa.Top = 510
DO AfLog WITH 'driverGest ADD_G1_Q3: ck_pret_cu_tva EXISTA, Top=' + TRANSFORM(loBifa.Top) + ' pe forma Height=' + TRANSFORM(loForm.Height) + ' -> PASS layout'
ELSE
DO AfLog WITH 'driverGest ADD_G1_Q3: ck_pret_cu_tva EXISTA dar layout neasteptat: Top=' + TRANSFORM(loBifa.Top) + ' Height forma=' + TRANSFORM(loForm.Height)
ENDIF
ELSE
DO AfLog WITH 'driverGest ADD_G1_Q3: ck_pret_cu_tva LIPSESTE din instanta'
ENDIF
DO AfLog WITH 'driverGest ADD_G1_Q3: Reccount(crsgestarticol)=' + TRANSFORM(RECCOUNT('crsgestarticol'))
*-- pozitia implicita (Go Top, tnIdTempExclus=0 la adaugare) e deja pe G1 (datain cel mai vechi)
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 3
loCantitate.InteractiveChange()
DO AfLog WITH 'driverGest ADD_G1_Q3: cantitate=3 pe G1 (pozitia implicita), apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'ADD_G2_Q4'
SELECT crsgestarticol
LOCATE FOR id_gestiune = 102
loGrid = FindCtl(loForm, 'grd_gestiuni')
loGrid.AfterRowColChange(1)
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 4
loCantitate.InteractiveChange()
DO AfLog WITH 'driverGest ADD_G2_Q4: navigheaza pe G2, cantitate=4, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'MOD_L1_PRESELECT_CHECK'
*-- cazuri b+c: verifica preselectia pe randul liniei si excluderea id_temp, fara sa comita nimic
SELECT crsgestarticol
IF id_gestiune = 101 AND ABS(cantitate - 10) < 0.001
DO UILog WITH 'PASS P3 (caz b) preselectie pe randul liniei modificate, cu propria cantitate reintoarsa in stoc: id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate)
ELSE
DO UILog WITH 'FAIL P3 (caz b): id_gestiune=' + TRANSFORM(id_gestiune) + ' cantitate=' + TRANSFORM(cantitate) + ' (asteptat 101 / 10)'
ENDIF
LOCATE FOR id_gestiune = 102
IF FOUND() AND ABS(cantitate - 11) < 0.001
DO UILog WITH 'PASS P3 (caz c) randul G2 (linia2, neexclusa) scade normal cu cantitatea ei: cantitate=' + TRANSFORM(cantitate) + ' (15-4)'
ELSE
DO UILog WITH 'FAIL P3 (caz c): randul G2 found=' + TRANSFORM(FOUND()) + IIF(FOUND(), ' cantitate=' + TRANSFORM(cantitate), '') + ' (asteptat 11 = 15-4)'
ENDIF
loRenunt = FindCtl(loForm, 'But_renunt1')
DO AfLog WITH 'driverGest MOD_L1_PRESELECT_CHECK: apas Renunta (nimic de comis)'
loRenunt.Click()
CASE gcCazAct == 'MOD_L1_REJECT_OVER_LOT'
SELECT crsgestarticol
LOCATE FOR id_gestiune = 101
loGrid = FindCtl(loForm, 'grd_gestiuni')
loGrid.AfterRowColChange(1)
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 11
loCantitate.InteractiveChange()
DO AfLog WITH 'driverGest MOD_L1_REJECT_OVER_LOT: cantitate=11 pe G1 (stoc 10), apas do_termin() - astept respingere'
loForm.do_termin()
*-- daca a respins, formularul ramane deschis (testare-ui-vfp.md, "Dialoguri modale") - inchid prin Renunta
loRenunt = FindCtl(loForm, 'But_renunt1')
IF VARTYPE(loRenunt) = 'O'
DO AfLog WITH 'driverGest MOD_L1_REJECT_OVER_LOT: dialogul a ramas deschis (validare respinsa, cum era asteptat), inchid cu Renunta'
loRenunt.Click()
ENDIF
CASE gcCazAct == 'MOD_L1_ACCEPT_AT_LOT'
SELECT crsgestarticol
LOCATE FOR id_gestiune = 101
loGrid = FindCtl(loForm, 'grd_gestiuni')
loGrid.AfterRowColChange(1)
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 10
loCantitate.InteractiveChange()
DO AfLog WITH 'driverGest MOD_L1_ACCEPT_AT_LOT: cantitate=10 pe G1 (exact stocul), apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'MOD_L1_CHANGE_GESTIUNE_NAV'
SELECT crsgestarticol
LOCATE FOR id_gestiune = 103
loGrid = FindCtl(loForm, 'grd_gestiuni')
loGrid.AfterRowColChange(1)
loCantitateCtn = FindCtl(loForm, 'clb_cantitate')
loCantitate = FindCtl(loCantitateCtn, 'Text_simplu1')
loCantitate.Value = 5
loCantitate.InteractiveChange()
DO AfLog WITH 'driverGest MOD_L1_CHANGE_GESTIUNE_NAV: navigheaza (fara SPACE) pe G3, cantitate=5, apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'MOD_L1_MULTISELECT'
SELECT crsgestarticol
LOCATE FOR id_gestiune = 101
DO AfLog WITH 'driverGest MOD_L1_MULTISELECT: SPACE (do_executa) pe G1'
loForm.do_executa()
SELECT crsgestarticol
LOCATE FOR id_gestiune = 104
DO AfLog WITH 'driverGest MOD_L1_MULTISELECT: SPACE (do_executa) pe G4'
loForm.do_executa()
DO AfLog WITH 'driverGest MOD_L1_MULTISELECT: nselectate=' + TRANSFORM(loForm.nselectate) + IIF(TYPE('poArticol.cantitate') = 'N', ' poArticol.cantitate acumulata=' + TRANSFORM(poArticol.cantitate), '') + ', apas do_termin()'
loForm.do_termin()
CASE gcCazAct == 'MOD_L1_RENUNTA'
loCantitateCtn = FindCtl(loForm, 'Clb_pretftva')
IF VARTYPE(loCantitateCtn) = 'O'
loCantitate = FindCtl(loCantitateCtn, 'tx_suma_nat')
IF VARTYPE(loCantitate) = 'O'
loCantitate.Value = 9999
loCantitate.InteractiveChange()
ENDIF
ENDIF
loRenunt = FindCtl(loForm, 'But_renunt1')
DO AfLog WITH 'driverGest MOD_L1_RENUNTA: pret tastat 9999, apas But_renunt1 (Renunta)'
loRenunt.Click()
OTHERWISE
DO AfLog WITH 'driverGest: gcCazAct necunoscut [' + gcCazAct + ']'
ENDCASE
glDlgTratat = .T.
DO AfLog WITH 'driverGest: interactiune REUSITA pentru caz=' + gcCazAct
CATCH TO loExcDrv
DO AfLog WITH 'driverGest: CATCH caz=' + gcCazAct + ' ErrorNo=' + TRANSFORM(loExcDrv.ErrorNo) + ;
' Message=' + loExcDrv.Message + ' Procedure=' + loExcDrv.Procedure + ;
' LineNo=' + TRANSFORM(loExcDrv.LineNo) + ' LineContents=[' + loExcDrv.LineContents + ']'
ENDTRY
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,13 @@
# test_pret_cu_tva_nivel3_gestiuni.ps1 - wrapper peste harness-ul generic pentru ramura GESTIONABILA
# a lui do_modifica/do_adauga_articol (S2d, review). Oracle mockuit la granita (goExecutor), fluxul
# real (butoane, taste, SPACE) ramane intact. Rulare:
# powershell -ExecutionPolicy Bypass -File test_pret_cu_tva_nivel3_gestiuni.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
-TestPrg (Join-Path $Teste 'test_pret_cu_tva_nivel3_gestiuni.prg') `
-Steps @('mediu', 'p1_add_g1', 'p2_add_g2', 'p3_preselectie_excludere', 'p4_respins_peste_lot', 'p5_acceptat_la_lot', 'p6_schimbare_gestiune_nav', 'p7_multiselectie', 'p8_renunta') `
-ShotsDir (Join-Path $Teste 'screenshots_nivel3') `
-SyncDir (Join-Path $Teste 'uisync_nivel3') `
-StepTimeoutSec 60 `
-ReadyTimeoutSec 90

View File

@@ -0,0 +1,128 @@
# Date de test - NNIR editabil in Registru Jurnal
Baza: `MARIUSM_AUTO@ROA_CENTRAL` (test, nu productie). Verificare: `verif_nnir_cod.sql` in acest
folder (`sqlplus ... @verif_nnir_cod.sql <cod>`).
| Caz | COD | AN | LUNA | ID_SET | NNIR curent | ACT randuri | RUL randuri | RUL_OBINV randuri |
|---|---|---|---|---|---|---|---|---|
| NIR/achizitie (principal) | 1140841 | 2026 | 7 | 209 | 3 | 7 (doar 1 cu nnir=3, restul 0) | 1 (nnir=3) | 0 |
| Obiecte de inventar | 1140835 | 2026 | 6 | 211 | 2026060001 | 1 | 0 | 2 (nnir=2026060001) |
| Fara rulaje | 1140848 | 2026 | 7 | 209 | 124 | 2 (ambele nnir=124) | 0 | 0 |
| Nota de inventar (blocare) | 1140716 | 2026 | 3 | 90101 | 2026030004 | 1 | 1 (nnir=2026030004) | 0 |
Note:
- ACT e pe linii (nu pe antet) - la COD 1140841 doar linia efectiv legata de rulaj are NNIR-ul
real, restul liniilor documentului au NNIR=0. Sincronizarea (`WHERE Nvl(nnir,0) = vechi`) trebuie
sa lase liniile cu 0 neatinse.
- Nu exista nicio nota cu `id_set=90101` sau cu rulaje in `RUL_OBINV` in luna curenta de lucru
(AN=2026, LUNA=7) - alese din perioade anterioare. Editarea reala prin `afisjurcom.do_modifica`
e limitata la luna curenta (`comun.vc2:2265-2268`); testul instantiaza `frm_modific2024` direct
(ca `test_repro_cnrcrt_footer.prg`), cu cursoare construite pe AN/LUNA propriu notei, ocolind
acel filtru - la fel ca precedentul deja acceptat in `achizitie_import`.
## Stare implementare (livrata, 03.08.2026)
`COMUN\clase\omodificari.vc2` (frm_modific2024):
- `Grid1.ColumnCount = 44`, `Column44.ControlSource = "nnir"` (la runtime apare calificat automat
de VFP cu aliasul cursorului: `tact.nnir`), `ReadOnly = .F.` - confirmat prin instantiere reala
(nu doar citire de sursa).
- `PROCEDURE sincronizeaza_nnir(tnNnirVechi, tnNnirNou)` (`omodificari.vc2:13762`) - update pe
`tact`/`trul`/`trul_obinv` unde `Nvl(nnir,0) = vechi`, cu revenire pe recno. Propaga si valoarea
0 (stergerea NNIR) - nu exista garda `EMPTY` pe valoarea noua.
- Legare pe coloana: `Grid1.Column44.Text1.When` retine valoarea veche in `thisform.nnnirvechi`;
**`Grid1.Column44.Text1.LostFocus`** apeleaza `sincronizeaza_nnir` si `Thisform.Grid1.Refresh()`
- `Valid` a fost eliminat (la textbox valoarea nu ajunge in ControlSource decat DUPA ce Valid
returneaza .T., deci nu propaga). Testul declanseaza `LostFocus`.
- Blocarea pentru `id_set = 90101` (nota de inventar): in `Init` (`omodificari.vc2:13654`) SI
reimpusa in `Grid1.AfterRowColChange` (14289-14292), dupa `SetAll("ReadOnly", ...)` - fara a doua,
`SetAll` anuleaza blocarea la prima navigare in grid.
- `ColumnOrder = 7` in clasa, plus repozitionare la runtime in `Show()`, dupa `gridextra1.setup()`
(13729-13738) - preferintele de grid salvate per utilizator impingeau coloana noua la coada
(vezi `COMUN\docs\capcana_grid_preferinte_utilizator.md`). Pozitia NU e o asertiune stabila intre
masini; asertat tare in test: `ControlSource = "nnir"`, `ReadOnly` (.F. normal / .T. pe
id_set 90101), propagarea valorii.
## Cerinte de mediu descoperite la construirea harness-ului (deja tratate in scripturile livrate)
- `COMUN\utile\Teste\test_init_env_auto.prg` (generic) e de fapt specific ROACONT (`gcAppPath`,
classlib-uri si proceduri hardcodate `D:\ROA\ROACONT\`) - inutilizabil pentru ROAGEST. S-a scris
`COMUN\utile\Teste\test_init_env_auto_roagest.prg`, cu SET PATH/CLASSLIB/PROCEDURE reconstruite
din `Programe\roagest.prg`.
- `gcUserName` trebuie setat explicit inainte de `optiuni_firma` (`oinit_optiuni.prg`) - altfel
`SCRIE_OPTIUNI(gcUserName)` da "Operator/operand type mismatch" (PUBLIC nedeclarat ramane
logic .F.). **`gcUserName` e schema/userul de conectare Oracle** (`Programe\roagest.prg:560,575`)
- `SCRIE_OPTIUNI` il foloseste direct in `from <gcUserName>.optiuni`, deci trebuie
`gcUserName = m.gcS`, NU un nume de persoana (ex. 'MARIUS M' da ORA-00907, identificator invalid
- incercare gresita initiala). Numele de persoana e `gcUserNameApp` (variabila separata).
- `frm_modific2024` face `Seek(..,'crsJtvaTemp','id_jtva')` in ControlSource-ul coloanei de
explicatie TVA a rulajelor (Column63) - evaluat la CONSTRUCTIA formularului. Fara cursorul
deschis, `CREATEOBJECT('frm_modific2024',...)` pica cu "File 'crsjtvatemp.dbf' does not exist".
Fix: `update_jtva_coloane('', 'crsJtvaTemp', 6)` (in `COMUN\programe\updateserver.prg:553`)
inainte de instantiere - construieste direct cursorul cu indexul cerut, fara pasii intermediari
folositi de exemplul ROACONT (`update_jtva_coloana`/`crsExplicatiiTVATemp`, care oricum nu
exista in ROAGEST).
- Mock-ul `amessagebox` trebuie incarcat **INAINTE** de `test_init_env_auto_roagest.prg` (nu doar
dupa, cum sugereaza exemplele din `achizitie_import`) - `optiuni_firma` poate afisa un dialog
real daca `SCRIE_OPTIUNI` raporteaza eroare, inainte sa apuce sa se incarce mock-ul "la coada".
- La citirea unei coloane de grid prin ControlSource dintr-un cursor legat ca RecordSource, VFP
calificat automat campul simplu cu aliasul (`nnir` -> `tact.nnir`) - comparatiile exacte
`== 'NNIR'` trebuie sa accepte si forma calificata.
- Coloanele de grid nu sunt garantat numite `Column<N>` - unele au `Name` custom (ex. `cAles` pe
pozitia 41 in acest grid); accesul dinamic la coloana trebuie facut prin colectia
`Grid1.Columns(i)`, nu prin constructia textuala a numelui `"column" + TRANSFORM(i)`.
- `frm_modific2024.Grid1.AfterRowColChange` are propria logica de blocare pe sucursala (SetAll
ReadOnly pe toate coloanele daca `Nvl(gnIdSucursala,0) <> Nvl(tAct.id_sucursala,0)`) - independenta
de blocarea 90101, se declanseaza automat la pozitionare in grid. COD 1140835 (cazul obiecte de
inventar) are `id_sucursala` diferit de sesiunea de test (`gnIdSucursala = NULL`), deci Column44
iese `ReadOnly=.T.` in acest scenariu - nu e o eroare, e comportament existent, neplanificat de
NNIR; sincronizarea tot functioneaza (apelul e direct, nu prin UI).
- **Termin reatribuie COD nou**: `afisjurcom.do_modifica` (comun.vc2:2444-2487) cheama
`oscrie_in_fisiere` de DOUA ori - intai `(2,.T.,llRul)` (STERGE, marcheaza `sters=1` pe COD-ul
ORIGINAL, din `actactan` neatins de editare), apoi `(0,.T.,llRul)` (SCRIE varianta editata sub
COD nou, generat de `pack_contafin`, sub AN/LUNA de sesiune curenta - nu pastreaza COD-ul/AN/LUNA
notei editate). Verificarea si curatenia testului se fac dupa NNIR (marcaj distinct), nu dupa
COD, si readuc nota originala la `sters=0` dupa test (pasul STERGE o dezactiveaza altfel permanent).
- Salvarea reala cere tranzactie manuala explicita: `SQLSetProp(gnHandle,'Transactions',2)` inainte
de blocul STERGE+SCRIE+finalizeaza, apoi `SQLCOMMIT(gnHandle)`/`SQLROLLBACK` +
`SQLSetProp(...,1)` dupa - echivalentul direct al `thisform.do_deschide_tranzactie()`/
`do_inchide_tranzactie()` din `afisjurcom` (`_frm_base.vc2:252-305`, mostenite, apelate pe
formularul de jurnal - nu pe `frm_modific2024`, deci invizibile la o privire doar pe clasa notei).
Fara acest wrapping, `oscrie_in_fisiere`/`finalizeaza_modificare_nota` raporteaza succes dar nu
se vede nimic persistat, nici in aceeasi sesiune.
## Capcana: .FXP stale ascunde scenariile noi
VFP nu recompileaza .prg-ul daca exista un .FXP mai vechi - ruleaza tacut versiunea veche a
scriptului. Simptom: suita raporteaza PASS-uri corecte, dar scenariile adaugate dupa ultima
compilare nu apar deloc in log (verifica numarul de assert-uri, nu doar `0 FAIL`). Sterge
.FXP-ul inainte de fiecare rulare.
## Capcana: dialog modal "Enter the value for <var>" in loc de eroare catchabila
O variabila memorie lipsa/umbrita folosita ca `?param` intr-un SQL pass-through (SQLEXEC/
`goExecutor.oExecuta`) NU da o eroare VFP catchabila (ON ERROR) - deschide dialogul nativ
"View Parameter" ("Enter the value for <var>"), MODAL, care blocheaza tot procesul headless la
nesfarsit si nu lasa nimic in log (spre deosebire de un `REPLACE`/expresie cu aceeasi variabila
lipsa, care DA eroare catchabila - vezi cazul `gnIdUtil` scapat o data ca `PRIVATE` neasignat).
Simptom: proces `vfp9.exe` care nu mai raspunde, fara `.ERR`, fara linie noua in log.
Remediu: **garda explicita inainte de orice rulare care ajunge la cod ce foloseste `?param`** -
verifica `TYPE(<nume>) == 'U'` pe toate variabilele relevante (nu doar cele proprii testului, ci
si cele din codul apelat: `oscrie_in_fisiere`, `pack_contafin`/`pack_sesiune`, `oinit_optiuni.prg`)
si opreste testul cu FAIL clar in log daca lipseste ceva, inainte sa ajunga la SQLEXEC. Implementat
in `test_nnir_sincronizare.prg` (`NnirGardaVariabile`, apelata imediat dupa init mediu). `TYPE()`
returneaza `'X'` (nu `'U'`) pentru NULL - o valoare NULL e un bind valid, doar variabila absenta
e problema.
## Rezultat test complet (03.08.2026, pe binarul livrat)
**33 PASS, 0 FAIL** pe cele 6 scenarii: NIR, obiecte de inventar si nota fara rulaje (toate cu
salvare reala prin Termin + verificare in Oracle), blocare `id_set=90101`, `NNIR -> 0`, si blocare
`id_set=90101` pe sucursala curenta. Baza de test verificata dupa rulare: cele 4 note originale
(1140841, 1140835, 1140848, 1140716) raman intacte (NNIR si `sters` la valorile initiale); notele
noi create de Termin (COD reatribuit) au fost marcate `sters=1` de curatenia din test.
Scenariul 6 (`INVENTAR2`) exista pentru ca scenariul 4 ruleaza pe o nota din ALTA sucursala, unde
`AfterRowColChange` blocheaza oricum tot gridul - trecea din motivul gresit. Scenariul 6 aliniaza
`gnIdSucursala` la nota (`llReadOnly` iese `.F.`) si asertesteaza si ca restul coloanelor raman
editabile, altfel blocarea NNIR nu dovedeste nimic.

View File

@@ -0,0 +1,839 @@
* test_nnir_sincronizare.prg
* Test e2e (fluxul real): NNIR editabil in Registru Jurnal, cu sincronizare in tact/trul/trul_obinv
* si in ACT/RUL/RUL_OBINV (Oracle). Vezi cerinta initiala (todos.txt pct. 9) si
* date_test_nnir.md (datele de test alese, an/luna/cod, stare implementare la data scrierii).
*
* Instantiaza frm_modific2024 direct (ca test_repro_cnrcrt_footer.prg din achizitie_import),
* cu cursoarele tact/trul/trul_obinv construite exact ca afisjurcom.do_modifica (comun.vc2:2352-
* 2434), dar pe AN/LUNA proprii notei - do_modifica limiteaza editarea la luna curenta de lucru
* (comun.vc2:2265-2268), iar notele de test nu sunt toate in luna curenta.
*
* Editarea NNIR se simuleaza ca un utilizator: pozitionare pe rand, declansarea evenimentelor
* reale ale coloanei (When la intrare, LostFocus la iesire - textboxul nu comite valoarea in
* ControlSource inainte de Valid, de-aia implementarea sincronizeaza pe LostFocus), NU apel
* direct al metodei de sincronizare. Salvarea (Termin) replica blocul din
* afisjurcom.do_modifica (comun.vc2:2456-2487): oscrie_in_fisiere + pack_contafin.
* finalizeaza_modificare_nota. Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune
* curenta - nu pastreaza COD-ul original; verificarea si curatenia de dupa salvare se fac dupa
* valoarea NNIR marcaj (nu poate coincide cu date reale), marcand sters=1 (conventia aplicatiei)
* orice a ajuns sub acea valoare - nota originala (COD/NNIR vechi) ramane intacta.
*
* Rulare headless (nu tine VFP IDE deschis; nu rula cu roagest.exe pornit):
* & "C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -A -T ;
* "D:\ROA\ROAGEST\COMUN\utile\Teste\nnir_registru_jurnal\test_nnir_sincronizare.prg"
* Timeout recomandat: minim 220s. Log: %TEMP%\test_nnir_sincronizare_log.txt (PASS/FAIL pe linie).
* STERGE .FXP-ul inainte de rulare: VFP nu recompileaza automat si ruleaza tacut versiunea
* veche a scriptului - scenariile adaugate intre timp lipsesc cu totul din log.
LPARAMETERS tcMode
tcMode = IIF(EMPTY(tcMode), 'ALL', UPPER(ALLTRIM(tcMode)))
SET SAFETY OFF
SET TALK OFF
PUBLIC gcLogFile, gnFail, gnPass
gcLogFile = ADDBS(SYS(2023)) + 'test_nnir_sincronizare_log.txt'
gnFail = 0
gnPass = 0
STRTOFILE('START ' + tcMode + ' ' + TTOC(DATETIME()) + CHR(13)+CHR(10), gcLogFile)
ON ERROR DO NnirErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
* mock amessagebox incarcat INAINTE de mediul aplicatiei: optiuni_firma (in mediul de test)
* poate afisa un dialog real daca SCRIE_OPTIUNI raporteaza eroare
SET PROCEDURE TO D:\ROA\ROAGEST\COMUN\utile\Teste\mock_amessagebox.prg ADDITIVE
DO D:\ROA\ROAGEST\COMUN\utile\Teste\test_init_env_auto_roagest.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
DO NnirLog WITH 'EROARE: conectare Oracle esuata'
DO NnirLog WITH 'REZULTAT SUITA: NEDETERMINAT'
QUIT
ENDIF
DO NnirLog WITH 'mediu OK, gnAn=' + TRANSFORM(gnAn) + ' gnLuna=' + TRANSFORM(gnLuna)
* garda anti-blocaj: o variabila lipsa folosita ca ?param intr-un SQL pass-through NU da eroare
* catchabila - VFP deschide dialogul modal nativ "Enter the value for <var>", care blocheaza
* headless-ul la nesfarsit si nu lasa nimic in log (vezi date_test_nnir.md). Verificare
* explicita INAINTE de orice apel care le foloseste, opreste testul cu FAIL clar daca lipseste ceva.
IF !NnirGardaVariabile()
DO NnirLog WITH 'REZULTAT SUITA: NEDETERMINAT (garda variabile a picat)'
QUIT
ENDIF
* mock amessagebox - se incarca ULTIMUL (dupa fisierele aplicatiei), vezi antetul mock-ului
SET PROCEDURE TO D:\ROA\ROAGEST\COMUN\utile\Teste\mock_amessagebox.prg ADDITIVE
* Grid1.Column63 (explicatie TVA pe rulaje) face Seek pe alias 'crsJtvaTemp' la CONSTRUCTIA
* formularului (inainte de Init) - fara cursorul deschis, CREATEOBJECT('frm_modific2024',...)
* pica cu "File 'crsjtvatemp.dbf' does not exist"
update_jtva_coloane('', 'crsJtvaTemp', 6)
LOCAL Omodif, lcCallWhen, lcCallLostFocus, lcCall
*=====================================================================================
* Scenariul 1: NIR/achizitie, cu rulaje in RUL, cu salvare (Termin) + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'NIR')
LOCAL lnCod, lnAn, lnLuna, lnIdSet, lnNnirVechi, lnNnirNou
LOCAL lnCntTactVechi, lnCntTrulVechi, lnCntTactNou, lnCntTrulNou
LOCAL i, llGasit, lnColOrder, llReadOnly, lnColCheck, lcColName
lnCod = 1140841
lnAn = 2026
lnLuna = 7
lnIdSet = 209
lnNnirVechi = 3
lnNnirNou = lnNnirVechi + 90000000
DO NnirConstruiesteCursoare WITH lnCod, lnAn, lnLuna
SELECT tact
lnCntTactVechi = 0
COUNT FOR NVL(nnir,0) = lnNnirVechi TO lnCntTactVechi
SELECT trul
lnCntTrulVechi = 0
COUNT FOR NVL(nnir,0) = lnNnirVechi TO lnCntTrulVechi
Omodif = CREATEOBJECT('frm_modific2024', lnIdSet)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'NIR', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
llGasit = .F.
lnColOrder = 0
llReadOnly = .T.
lnColCheck = 0
FOR i = 1 TO Omodif.grid1.ColumnCount
lcColName = 'Omodif.grid1.Columns(' + TRANSFORM(i) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColName + '.ControlSource'))
llGasit = .T.
lnColOrder = EVALUATE(lcColName + '.ColumnOrder')
llReadOnly = EVALUATE(lcColName + '.ReadOnly')
lnColCheck = i
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'NIR', llGasit, 'ControlSource=nnir gasit=' + ;
TRANSFORM(llGasit) + ' ColumnOrder=' + TRANSFORM(lnColOrder) + ' ReadOnly=' + TRANSFORM(llReadOnly)
IF llGasit
DO NnirAssert WITH 'coloana_editabila', 'NIR', !llReadOnly, 'nota normala: ReadOnly asteptat .F.'
SELECT tact
LOCATE FOR NVL(nnir,0) = lnNnirVechi
IF FOUND()
lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck) + ').Text1.When'
&lcCallWhen
REPLACE nnir WITH lnNnirNou
lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck) + ').Text1.LostFocus'
&lcCallLostFocus
SELECT tact
lnCntTactNou = 0
COUNT FOR NVL(nnir,0) = lnNnirNou TO lnCntTactNou
DO NnirAssert WITH 'sync_tact', 'NIR', lnCntTactNou = lnCntTactVechi, ;
TRANSFORM(lnCntTactNou) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi) + ')'
* trul = cursorul legat de pgfArticole.page1.grdRulaje (RecordSource) - verificare
* explicita ca propagarea se vede in cursorul de rulaje, nu doar in tact
SELECT trul
lnCntTrulNou = 0
COUNT FOR NVL(nnir,0) = lnNnirNou TO lnCntTrulNou
DO NnirAssert WITH 'sync_trul', 'NIR', lnCntTrulNou = lnCntTrulVechi, ;
TRANSFORM(lnCntTrulNou) + ' randuri trul (grid rulaje) cu nnir nou (asteptat ' + TRANSFORM(lnCntTrulVechi) + ')'
ELSE
DO NnirAssert WITH 'locate_rand_vechi', 'NIR', .F., 'nu s-a gasit randul cu nnir vechi in tact'
ENDIF
ENDIF
DO NnirVerificaOracleNeschimbat WITH lnCod, lnNnirVechi, 'NIR'
Omodif.Release()
Omodif = NULL
DO NnirSalveazaSiVerifica WITH lnCod, lnAn, lnLuna, lnIdSet, lnNnirVechi, lnNnirNou, 'NIR'
ENDIF
DO NnirCurataCursoare
ENDIF
*=====================================================================================
* Scenariul 2: obiecte de inventar, cu rulaje in RUL_OBINV, cu salvare + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'OBINV')
LOCAL lnCod2, lnAn2, lnLuna2, lnIdSet2, lnNnirVechi2, lnNnirNou2
LOCAL lnCntTactVechi2, lnCntRobinvVechi2, lnCntTactNou2, lnCntRobinvNou2
LOCAL i2, llGasit2, lnColOrder2, llReadOnly2, lnColCheck2, lcColName2
lnCod2 = 1140835
lnAn2 = 2026
lnLuna2 = 6
lnIdSet2 = 211
lnNnirVechi2 = 2026060001
lnNnirNou2 = lnNnirVechi2 + 90000000
DO NnirConstruiesteCursoare WITH lnCod2, lnAn2, lnLuna2
SELECT tact
lnCntTactVechi2 = 0
COUNT FOR NVL(nnir,0) = lnNnirVechi2 TO lnCntTactVechi2
SELECT trul_obinv
lnCntRobinvVechi2 = 0
COUNT FOR NVL(nnir,0) = lnNnirVechi2 TO lnCntRobinvVechi2
Omodif = CREATEOBJECT('frm_modific2024', lnIdSet2)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'OBINV', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
llGasit2 = .F.
lnColOrder2 = 0
llReadOnly2 = .T.
lnColCheck2 = 0
FOR i2 = 1 TO Omodif.grid1.ColumnCount
lcColName2 = 'Omodif.grid1.Columns(' + TRANSFORM(i2) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColName2 + '.ControlSource'))
llGasit2 = .T.
lnColOrder2 = EVALUATE(lcColName2 + '.ColumnOrder')
llReadOnly2 = EVALUATE(lcColName2 + '.ReadOnly')
lnColCheck2 = i2
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'OBINV', llGasit2, 'ControlSource=nnir gasit=' + ;
TRANSFORM(llGasit2) + ' ColumnOrder=' + TRANSFORM(lnColOrder2) + ' ReadOnly=' + TRANSFORM(llReadOnly2)
IF llGasit2
SELECT tact
LOCATE FOR NVL(nnir,0) = lnNnirVechi2
IF FOUND()
lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck2) + ').Text1.When'
&lcCallWhen
REPLACE nnir WITH lnNnirNou2
lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck2) + ').Text1.LostFocus'
&lcCallLostFocus
SELECT tact
lnCntTactNou2 = 0
COUNT FOR NVL(nnir,0) = lnNnirNou2 TO lnCntTactNou2
DO NnirAssert WITH 'sync_tact', 'OBINV', lnCntTactNou2 = lnCntTactVechi2, ;
TRANSFORM(lnCntTactNou2) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi2) + ')'
SELECT trul_obinv
lnCntRobinvNou2 = 0
COUNT FOR NVL(nnir,0) = lnNnirNou2 TO lnCntRobinvNou2
DO NnirAssert WITH 'sync_trul_obinv', 'OBINV', lnCntRobinvNou2 = lnCntRobinvVechi2, ;
TRANSFORM(lnCntRobinvNou2) + ' randuri trul_obinv cu nnir nou (asteptat ' + TRANSFORM(lnCntRobinvVechi2) + ')'
ELSE
DO NnirAssert WITH 'locate_rand_vechi', 'OBINV', .F., 'nu s-a gasit randul cu nnir vechi in tact'
ENDIF
ENDIF
Omodif.Release()
Omodif = NULL
DO NnirSalveazaSiVerificaObinv WITH lnCod2, lnAn2, lnLuna2, lnIdSet2, lnNnirVechi2, lnNnirNou2
ENDIF
DO NnirCurataCursoare
ENDIF
*=====================================================================================
* Scenariul 3: nota fara rulaje - regresie (nu crapa), cu salvare + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'FARARUL')
LOCAL lnCod3, lnAn3, lnLuna3, lnIdSet3, lnNnirVechi3, lnNnirNou3
LOCAL lnCntTactVechi3, lnCntTactNou3
LOCAL i3, llGasit3, lnColCheck3, lcColName3
lnCod3 = 1140848
lnAn3 = 2026
lnLuna3 = 7
lnIdSet3 = 209
lnNnirVechi3 = 124
lnNnirNou3 = lnNnirVechi3 + 90000000
DO NnirConstruiesteCursoare WITH lnCod3, lnAn3, lnLuna3
SELECT tact
lnCntTactVechi3 = 0
COUNT FOR NVL(nnir,0) = lnNnirVechi3 TO lnCntTactVechi3
Omodif = CREATEOBJECT('frm_modific2024', lnIdSet3)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'FARARUL', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
llGasit3 = .F.
lnColCheck3 = 0
FOR i3 = 1 TO Omodif.grid1.ColumnCount
lcColName3 = 'Omodif.grid1.Columns(' + TRANSFORM(i3) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColName3 + '.ControlSource'))
llGasit3 = .T.
lnColCheck3 = i3
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'FARARUL', llGasit3, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit3)
IF llGasit3
SELECT tact
LOCATE FOR NVL(nnir,0) = lnNnirVechi3
IF FOUND()
lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck3) + ').Text1.When'
&lcCallWhen
REPLACE nnir WITH lnNnirNou3
lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck3) + ').Text1.LostFocus'
&lcCallLostFocus
SELECT tact
lnCntTactNou3 = 0
COUNT FOR NVL(nnir,0) = lnNnirNou3 TO lnCntTactNou3
DO NnirAssert WITH 'sync_tact', 'FARARUL', lnCntTactNou3 = lnCntTactVechi3, ;
TRANSFORM(lnCntTactNou3) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi3) + ')'
DO NnirAssert WITH 'nu_crapa', 'FARARUL', .T., 'editarea pe nota fara rulaje nu a generat eroare'
ELSE
DO NnirAssert WITH 'locate_rand_vechi', 'FARARUL', .F., 'nu s-a gasit randul cu nnir vechi in tact'
ENDIF
ENDIF
Omodif.Release()
Omodif = NULL
DO NnirSalveazaSiVerifica WITH lnCod3, lnAn3, lnLuna3, lnIdSet3, lnNnirVechi3, lnNnirNou3, 'FARARUL'
ENDIF
DO NnirCurataCursoare
ENDIF
*=====================================================================================
* Scenariul 4: nota de inventar (id_set=90101) - regresie blocare editare NNIR
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'INVENTAR')
LOCAL lnCod4, lnAn4, lnLuna4, lnIdSet4
LOCAL i4, llGasit4, llReadOnly4, lcColName4
lnCod4 = 1140716
lnAn4 = 2026
lnLuna4 = 3
lnIdSet4 = 90101
DO NnirConstruiesteCursoare WITH lnCod4, lnAn4, lnLuna4
Omodif = CREATEOBJECT('frm_modific2024', lnIdSet4)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'INVENTAR', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
llGasit4 = .F.
llReadOnly4 = .F.
FOR i4 = 1 TO Omodif.grid1.ColumnCount
lcColName4 = 'Omodif.grid1.Columns(' + TRANSFORM(i4) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColName4 + '.ControlSource'))
llGasit4 = .T.
llReadOnly4 = EVALUATE(lcColName4 + '.ReadOnly')
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'INVENTAR', llGasit4, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit4)
IF llGasit4
* nu se incearca editarea - doar se verifica blocarea, ca sa nu se altereze o nota
* reala de inventar cat timp blocarea nu e implementata
DO NnirAssert WITH 'coloana_blocata', 'INVENTAR', llReadOnly4, ;
'id_set=90101: ReadOnly asteptat .T., gasit ' + TRANSFORM(llReadOnly4)
ENDIF
Omodif.Release()
Omodif = NULL
ENDIF
DO NnirCurataCursoare
ENDIF
*=====================================================================================
* Scenariul 5: stergere NNIR (-> 0) pe randul unei note cu rulaje - propagare la 0.
* Comportament nou (runda 4): garda EMPTY(NVL(tnNnirNou,0)) eliminata din sincronizeaza_nnir,
* ramane doar egalitatea - stergerea celulei (0 scris pe rand inainte de LostFocus) trebuie sa
* se propage la toate liniile cu valoarea veche, nu doar schimbarile intre doua valori nenule.
* Doar la nivel de cursoare (tact/trul) - nu se salveaza in Oracle.
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'ZERO')
LOCAL lnCodZ, lnAnZ, lnLunaZ, lnIdSetZ, lnNnirVechiZ
LOCAL lnCntTactVechiZ, lnCntTrulVechiZ, lnCntTactRamasVechiZ, lnCntTrulRamasVechiZ
LOCAL lnCntTactZeroZ, lnCntTrulZeroZ
LOCAL iz, llGasitZ, lnColCheckZ, lcColNameZ
lnCodZ = 1140841
lnAnZ = 2026
lnLunaZ = 7
lnIdSetZ = 209
lnNnirVechiZ = 3
DO NnirConstruiesteCursoare WITH lnCodZ, lnAnZ, lnLunaZ
SELECT tact
lnCntTactVechiZ = 0
COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTactVechiZ
SELECT trul
lnCntTrulVechiZ = 0
COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTrulVechiZ
Omodif = CREATEOBJECT('frm_modific2024', lnIdSetZ)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'ZERO', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
llGasitZ = .F.
lnColCheckZ = 0
FOR iz = 1 TO Omodif.grid1.ColumnCount
lcColNameZ = 'Omodif.grid1.Columns(' + TRANSFORM(iz) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColNameZ + '.ControlSource'))
llGasitZ = .T.
lnColCheckZ = iz
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'ZERO', llGasitZ, 'ControlSource=nnir gasit=' + TRANSFORM(llGasitZ)
IF llGasitZ
SELECT tact
LOCATE FOR NVL(nnir,0) = lnNnirVechiZ
IF FOUND()
lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheckZ) + ').Text1.When'
&lcCallWhen
* simuleaza stergerea celulei: utilizatorul goleste campul, valoarea ajunge 0
REPLACE nnir WITH 0
lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheckZ) + ').Text1.LostFocus'
&lcCallLostFocus
SELECT tact
lnCntTactRamasVechiZ = 0
COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTactRamasVechiZ
lnCntTactZeroZ = 0
COUNT FOR NVL(nnir,0) = 0 TO lnCntTactZeroZ
DO NnirAssert WITH 'sync_tact_zero', 'ZERO', lnCntTactRamasVechiZ = 0 AND lnCntTactZeroZ >= lnCntTactVechiZ, ;
TRANSFORM(lnCntTactRamasVechiZ) + ' randuri tact au ramas pe valoarea veche (asteptat 0), ' + ;
TRANSFORM(lnCntTactZeroZ) + ' au ajuns la 0 (asteptat cel putin ' + TRANSFORM(lnCntTactVechiZ) + ')'
* verificare explicita in cursorul legat de grid-ul de rulaje (pgfArticole.page1.grdRulaje)
SELECT trul
lnCntTrulRamasVechiZ = 0
COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTrulRamasVechiZ
lnCntTrulZeroZ = 0
COUNT FOR NVL(nnir,0) = 0 TO lnCntTrulZeroZ
DO NnirAssert WITH 'sync_trul_zero', 'ZERO', lnCntTrulRamasVechiZ = 0 AND lnCntTrulZeroZ >= lnCntTrulVechiZ, ;
TRANSFORM(lnCntTrulRamasVechiZ) + ' randuri trul au ramas pe valoarea veche (asteptat 0), ' + ;
TRANSFORM(lnCntTrulZeroZ) + ' au ajuns la 0 (asteptat cel putin ' + TRANSFORM(lnCntTrulVechiZ) + ')'
ELSE
DO NnirAssert WITH 'locate_rand_vechi', 'ZERO', .F., 'nu s-a gasit randul cu nnir vechi in tact'
ENDIF
ENDIF
Omodif.Release()
Omodif = NULL
ENDIF
DO NnirCurataCursoare
ENDIF
*=====================================================================================
* Scenariul 6: nota de inventar (id_set=90101) pe sucursala CURENTA - blocarea NNIR trebuie sa
* vina din regula 90101, nu din blocarea pe sucursala din AfterRowColChange. Scenariul 4 ruleaza
* pe o nota din alta sucursala, unde SetAll("ReadOnly",.T.) blocheaza oricum tot gridul, deci ar
* trece si fara implementare. Aici gnIdSucursala se aliniaza la id_sucursala notei (llReadOnly
* iese .F.), se declanseaza AfterRowColChange (care face SetAll dupa Init) si se verifica ca
* Column44 ramane blocata cat timp restul coloanelor sunt editabile.
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'INVENTAR2')
LOCAL lnCod6, lnAn6, lnLuna6, lnIdSet6
LOCAL i6, llGasit6, llReadOnly6, lnEditabile6, lnSucVechi6, llMamaVechi6
LOCAL lnIdSucNota6, lcColName6
lnCod6 = 1140716
lnAn6 = 2026
lnLuna6 = 3
lnIdSet6 = 90101
DO NnirConstruiesteCursoare WITH lnCod6, lnAn6, lnLuna6
SELECT tact
GO TOP
lnIdSucNota6 = NVL(tact.id_sucursala, 0)
lnSucVechi6 = gnIdSucursala
llMamaVechi6 = glEMama
gnIdSucursala = lnIdSucNota6
glEMama = .F.
Omodif = CREATEOBJECT('frm_modific2024', lnIdSet6)
IF VARTYPE(Omodif) <> 'O'
DO NnirAssert WITH 'instantiere', 'INVENTAR2', .F., 'frm_modific2024 nu s-a instantiat'
ELSE
SELECT tact
GO TOP
Omodif.grid1.SetFocus
Omodif.gridextra1.setup()
Omodif.CalculeazaTotal()
* AfterRowColChange face SetAll("ReadOnly", llReadOnly) peste blocarea pusa in Init
Omodif.grid1.AfterRowColChange(1)
llGasit6 = .F.
llReadOnly6 = .F.
lnEditabile6 = 0
FOR i6 = 1 TO Omodif.grid1.ColumnCount
lcColName6 = 'Omodif.grid1.Columns(' + TRANSFORM(i6) + ')'
IF NnirEsteColoanaNnir(EVALUATE(lcColName6 + '.ControlSource'))
llGasit6 = .T.
llReadOnly6 = EVALUATE(lcColName6 + '.ReadOnly')
ELSE
IF !EVALUATE(lcColName6 + '.ReadOnly')
lnEditabile6 = lnEditabile6 + 1
ENDIF
ENDIF
ENDFOR
DO NnirAssert WITH 'coloana_grid', 'INVENTAR2', llGasit6, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit6)
* control: daca gridul e blocat integral, testul de blocare NNIR nu dovedeste nimic
DO NnirAssert WITH 'grid_editabil', 'INVENTAR2', lnEditabile6 > 0, ;
'coloane editabile (fara nnir): ' + TRANSFORM(lnEditabile6) + ' (asteptat > 0, ' + ;
'gnIdSucursala=' + TRANSFORM(lnIdSucNota6) + ')'
IF llGasit6
DO NnirAssert WITH 'coloana_blocata', 'INVENTAR2', llReadOnly6, ;
'id_set=90101 pe sucursala curenta: ReadOnly asteptat .T., gasit ' + TRANSFORM(llReadOnly6)
ENDIF
Omodif.Release()
Omodif = NULL
ENDIF
gnIdSucursala = lnSucVechi6
glEMama = llMamaVechi6
DO NnirCurataCursoare
ENDIF
DO NnirLog WITH 'REZULTAT SUITA: ' + TRANSFORM(gnPass) + ' PASS, ' + TRANSFORM(gnFail) + ' FAIL'
QUIT
*=====================================================================================
* proceduri ajutatoare (fara CREATEOBJECT - vezi depanare_testare_vfp.md / capcana l:
* CREATEOBJECT apelat dintr-o procedura se comporta gresit in acest runtime headless)
*=====================================================================================
PROCEDURE NnirLog
LPARAMETERS tcMsg
STRTOFILE(tcMsg + CHR(13)+CHR(10), gcLogFile, 1)
ENDPROC
PROCEDURE NnirAssert
LPARAMETERS tcPas, tcCaz, llOk, tcDetaliu
LOCAL lcRez
lcRez = IIF(llOk, 'PASS', 'FAIL')
IF llOk
gnPass = gnPass + 1
ELSE
gnFail = gnFail + 1
ENDIF
DO NnirLog WITH lcRez + ' [' + tcCaz + '/' + tcPas + '] ' + tcDetaliu
ENDPROC
PROCEDURE NnirErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO NnirLog WITH 'ERR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
* verifica ca toate variabilele folosite ca ?param in SQL pass-through pe calea de test (env-init,
* optiuni_firma, oscrie_in_fisiere, pack_contafin/pack_sesiune) sunt definite - o variabila
* PUBLIC lipsa/umbrita da direct dialogul modal "Enter the value for <var>", nu o eroare catchabila
FUNCTION NnirGardaVariabile
LOCAL laVar(9), i, llOk
laVar(1) = 'gnIdUtil'
laVar(2) = 'gnAn'
laVar(3) = 'gnLuna'
laVar(4) = 'gnIdFirma'
laVar(5) = 'gnIdSucursala'
laVar(6) = 'gcS'
laVar(7) = 'gnIdProgram'
laVar(8) = 'gnId_Prg_Owner'
laVar(9) = 'gnHandle'
llOk = .T.
FOR i = 1 TO ALEN(laVar)
IF TYPE(laVar(i)) == 'U'
DO NnirLog WITH 'FAIL [garda_variabile] ' + laVar(i) + ' nu exista (TYPE U) - ar fi dat dialog modal "Enter the value"'
llOk = .F.
ENDIF
ENDFOR
RETURN llOk
ENDFUNC
* VFP calificat automat ControlSource-ul unui camp simplu cu aliasul cursorului (RecordSource) -
* "nnir" definit in sursa apare la runtime ca "tact.nnir" - se accepta ambele forme
FUNCTION NnirEsteColoanaNnir
LPARAMETERS tcControlSource
LOCAL lcCs
lcCs = UPPER(ALLTRIM(TRANSFORM(tcControlSource)))
RETURN lcCs == 'NNIR' OR RIGHT(lcCs, 5) == '.NNIR'
ENDFUNC
* construieste tact/trul/trul_obinv exact ca afisjurcom.do_modifica (comun.vc2:2352-2434),
* dar pe AN/LUNA proprii notei (nu gnAn/gnLuna) - vezi antetul fisierului
PROCEDURE NnirConstruiesteCursoare
LPARAMETERS tnCod, tnAn, tnLuna
LOCAL lcSql, lnSucces
DO NnirCurataCursoare
lcSql = [select * from vact_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_act]
lnSucces = goExecutor.oExecute(lcSql, 'v_act')
goExecutor.oReset()
IF lnSucces < 0
DO NnirLog WITH 'EROARE construire tact: ' + goExecutor.cEroare
RETURN .F.
ENDIF
SELECT * FROM v_act INTO CURSOR actactan
SELECT .F. AS ales, T.*, CAST(0 AS N(2)) AS tipnota FROM actactan T INTO CURSOR tact READWRITE
USE IN v_act
lcSql = [select * from vrul_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_rul]
goExecutor.oExecute(lcSql, 'v_rul')
goExecutor.oReset()
SELECT *, valoare + valtva AS valoarectva, valoarev + valtvav AS valoarevctva ;
FROM v_rul INTO CURSOR RUL_TEMP READWRITE
SELECT * FROM RUL_TEMP INTO CURSOR trul READWRITE
USE IN v_rul
lcSql = [select * from vrul_obinv_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_rul_obinv]
goExecutor.oExecute(lcSql, 'v_rul_obinv')
goExecutor.oReset()
SELECT *, valoare + valtva AS valoarectva, valoarev + valtvav AS valoarevctva ;
FROM v_rul_obinv INTO CURSOR RUL_TEMP_OBINV READWRITE
SELECT * FROM RUL_TEMP_OBINV INTO CURSOR trul_obinv READWRITE
USE IN v_rul_obinv
SELECT a.*, IIF(NVL(a.id_jtva_coloana,0)=0,0,1) AS cu_tva FROM tact a INTO CURSOR tact READWRITE
SELECT tact
GO TOP
RETURN .T.
ENDPROC
PROCEDURE NnirCurataCursoare
IF USED('tact')
USE IN tact
ENDIF
IF USED('trul')
USE IN trul
ENDIF
IF USED('trul_obinv')
USE IN trul_obinv
ENDIF
IF USED('actactan')
USE IN actactan
ENDIF
IF USED('rul_temp')
USE IN rul_temp
ENDIF
IF USED('rul_temp_obinv')
USE IN rul_temp_obinv
ENDIF
ENDPROC
FUNCTION NnirOraCount
LPARAMETERS tcSql
LOCAL lnVal, llOk
lnVal = -1
llOk = goExecutor.oExecuta(tcSql, 'cNnirOraCnt')
IF llOk AND USED('cNnirOraCnt') AND RECCOUNT('cNnirOraCnt') > 0
lnVal = cNnirOraCnt.cnt
ENDIF
IF USED('cNnirOraCnt')
USE IN cNnirOraCnt
ENDIF
RETURN lnVal
ENDFUNC
* verifica ca in Oracle nu s-a scris nimic dupa editarea DOAR in cursoare (echivalent Renunt)
PROCEDURE NnirVerificaOracleNeschimbat
LPARAMETERS tnCod, tnNnirVechi, tcCaz
LOCAL lnCnt, lcSql
lcSql = [select count(*) cnt from act where cod = ] + TRANSFORM(tnCod) + ;
[ and nnir = ] + TRANSFORM(tnNnirVechi)
lnCnt = NnirOraCount(lcSql)
DO NnirAssert WITH 'renunt_neschimbat', tcCaz, lnCnt > 0, ;
'ACT.NNIR in Oracle inainte de Termin ramane ' + TRANSFORM(tnNnirVechi) + ' (' + TRANSFORM(lnCnt) + ' randuri)'
ENDPROC
* replica blocul de salvare din afisjurcom.do_modifica (comun.vc2:2456-2487): scrie tact/trul/
* trul_obinv in ACT/RUL/RUL_OBINV prin oscrie_in_fisiere + pack_contafin.finalizeaza_modificare_
* nota, verifica in Oracle, apoi reface valoarea originala (revert - baza de test ramane
* neschimbata pentru rulari repetate)
PROCEDURE NnirSalveazaSiVerifica
LPARAMETERS tnCod, tnAn, tnLuna, tnIdSet, tnNnirVechi, tnNnirNou, tcCaz
PRIVATE pnAn, pnLuna, pdDataOra
LOCAL lnIdFact, lnIdfactd, llRul, lnSuccesSalvare, lcSqlFin, lnCnt, lcSql
pnAn = tnAn
pnLuna = tnLuna
pdDataOra = NULL
SELECT tact
LOCATE FOR NVL(nnir,0) = tnNnirNou
lnIdFact = NVL(id_fact, 0)
lnIdfactd = NVL(id_factd, 0)
llRul = (RECCOUNT('trul') > 0) OR (RECCOUNT('trul_obinv') > 0)
* thisform.do_deschide_tranzactie()/do_inchide_tranzactie() din afisjurcom (_frm_base.vc2:252-
* 305, mostenite, apelate pe formularul de jurnal, nu pe frm_modific2024) - echivalent direct,
* fara instanta de forma: manual pe durata scrierii, apoi commit/rollback + revenire pe auto
SQLSetProp(gnHandle, 'Transactions', 2)
* replica exact secventa din afisjurcom.do_modifica: intai STERGE nota veche (COD-ul
* original, din actactan neatins de editare), abia apoi SCRIE varianta editata
SELECT actactan
lnSuccesSalvare = oscrie_in_fisiere(2, .T., llRul)
DO NnirAssert WITH 'oscrie_in_fisiere_sterge', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
IF lnSuccesSalvare > 0
SELECT * FROM tact INTO CURSOR actactan READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN actactan
IF llRul
SELECT * FROM trul INTO CURSOR rul_temp READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp
SELECT * FROM trul_obinv INTO CURSOR rul_temp_obinv READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp_obinv
ENDIF
lnSuccesSalvare = oscrie_in_fisiere(0, .T., llRul)
DO NnirAssert WITH 'oscrie_in_fisiere', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
ENDIF
IF lnSuccesSalvare > 0
lcSqlFin = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,?pdDataOra,] + ;
TRANSFORM(tnIdSet) + [,] + TRANSFORM(tnCod) + [,] + TRANSFORM(lnIdFact) + [,] + ;
TRANSFORM(lnIdfactd) + [,?gnIdUtil); end;]
lnSuccesSalvare = IIF(goExecutor.oExecuta(lcSqlFin), 1, -1)
DO NnirAssert WITH 'finalizeaza_modificare_nota', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
ENDIF
IF lnSuccesSalvare > 0
SQLCOMMIT(gnHandle)
ELSE
SQLROLLBACK(gnHandle)
ENDIF
SQLSetProp(gnHandle, 'Transactions', 1)
* Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune curente - nu pastreaza
* COD-ul original notei editate. Verificarea si curatenia se fac dupa valoarea NNIR marcaj
* (distincta, nu poate coincide cu date reale), nu dupa COD-ul original.
lcSql = [select count(*) cnt from act where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
lnCnt = NnirOraCount(lcSql)
DO NnirAssert WITH 'oracle_act_final', tcCaz, lnCnt > 0, TRANSFORM(lnCnt) + ' randuri ACT cu nnir nou in Oracle'
IF RECCOUNT('trul') > 0
lcSql = [select count(*) cnt from rul where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
lnCnt = NnirOraCount(lcSql)
DO NnirAssert WITH 'oracle_rul_final', tcCaz, lnCnt > 0, TRANSFORM(lnCnt) + ' randuri RUL cu nnir nou in Oracle'
ENDIF
* curatenie: pasul STERGE (oscrie_in_fisiere param 2) marcheaza sters=1 pe COD-ul ORIGINAL -
* readuc nota originala activa, apoi marchez sters=1 (conventia aplicatiei) pe orice a ajuns
* sub NNIR-ul marcaj (COD nou, atribuit de pack_contafin la scriere)
goExecutor.oExecuta([update act set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul_obinv set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update act set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul_obinv set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta('commit')
ENDPROC
* varianta pt. scenariul RUL_OBINV (verifica RUL_OBINV in loc de RUL)
PROCEDURE NnirSalveazaSiVerificaObinv
LPARAMETERS tnCod, tnAn, tnLuna, tnIdSet, tnNnirVechi, tnNnirNou
PRIVATE pnAn, pnLuna, pdDataOra
LOCAL lnIdFact, lnIdfactd, llRul, lnSuccesSalvare, lcSqlFin, lnCnt, lcSql
pnAn = tnAn
pnLuna = tnLuna
pdDataOra = NULL
SELECT tact
LOCATE FOR NVL(nnir,0) = tnNnirNou
lnIdFact = NVL(id_fact, 0)
lnIdfactd = NVL(id_factd, 0)
llRul = (RECCOUNT('trul') > 0) OR (RECCOUNT('trul_obinv') > 0)
* thisform.do_deschide_tranzactie()/do_inchide_tranzactie() din afisjurcom (_frm_base.vc2:252-
* 305, mostenite, apelate pe formularul de jurnal, nu pe frm_modific2024) - echivalent direct,
* fara instanta de forma: manual pe durata scrierii, apoi commit/rollback + revenire pe auto
SQLSetProp(gnHandle, 'Transactions', 2)
* replica exact secventa din afisjurcom.do_modifica: intai STERGE nota veche (COD-ul
* original, din actactan neatins de editare), abia apoi SCRIE varianta editata
SELECT actactan
lnSuccesSalvare = oscrie_in_fisiere(2, .T., llRul)
DO NnirAssert WITH 'oscrie_in_fisiere_sterge', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
IF lnSuccesSalvare > 0
SELECT * FROM tact INTO CURSOR actactan READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN actactan
IF llRul
SELECT * FROM trul INTO CURSOR rul_temp READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp
SELECT * FROM trul_obinv INTO CURSOR rul_temp_obinv READWRITE
REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp_obinv
ENDIF
lnSuccesSalvare = oscrie_in_fisiere(0, .T., llRul)
DO NnirAssert WITH 'oscrie_in_fisiere', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
ENDIF
IF lnSuccesSalvare > 0
lcSqlFin = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,?pdDataOra,] + ;
TRANSFORM(tnIdSet) + [,] + TRANSFORM(tnCod) + [,] + TRANSFORM(lnIdFact) + [,] + ;
TRANSFORM(lnIdfactd) + [,?gnIdUtil); end;]
lnSuccesSalvare = IIF(goExecutor.oExecuta(lcSqlFin), 1, -1)
DO NnirAssert WITH 'finalizeaza_modificare_nota', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
ENDIF
IF lnSuccesSalvare > 0
SQLCOMMIT(gnHandle)
ELSE
SQLROLLBACK(gnHandle)
ENDIF
SQLSetProp(gnHandle, 'Transactions', 1)
* Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune curente - nu pastreaza
* COD-ul original notei editate. Verificarea si curatenia se fac dupa valoarea NNIR marcaj
* (distincta, nu poate coincide cu date reale), nu dupa COD-ul original.
lcSql = [select count(*) cnt from act where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
lnCnt = NnirOraCount(lcSql)
DO NnirAssert WITH 'oracle_act_final', 'OBINV', lnCnt > 0, TRANSFORM(lnCnt) + ' randuri ACT cu nnir nou in Oracle'
lcSql = [select count(*) cnt from rul_obinv where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
lnCnt = NnirOraCount(lcSql)
DO NnirAssert WITH 'oracle_rul_obinv_final', 'OBINV', lnCnt > 0, TRANSFORM(lnCnt) + ' randuri RUL_OBINV cu nnir nou in Oracle'
* curatenie: pasul STERGE (oscrie_in_fisiere param 2) marcheaza sters=1 pe COD-ul ORIGINAL -
* readuc nota originala activa, apoi marchez sters=1 (conventia aplicatiei) pe orice a ajuns
* sub NNIR-ul marcaj (COD nou, atribuit de pack_contafin la scriere)
goExecutor.oExecuta([update act set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul_obinv set sters = 0 where cod = ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update act set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta([update rul_obinv set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
goExecutor.oExecuta('commit')
ENDPROC

View File

@@ -0,0 +1,11 @@
-- verif_nnir_cod.sql - NNIR distinct pe ACT/RUL/RUL_OBINV pentru un COD dat
-- Rulare: sqlplus -L -S MARIUSM_AUTO/<parola>@ROA_CENTRAL @verif_nnir_cod.sql <cod>
set pagesize 200 linesize 200 trimspool on feedback off
define v_cod = &1
prompt ==ACT==
select cod, an, luna, id_set, nnir from act where cod = &v_cod;
prompt ==RUL_NNIR_DISTINCT==
select an, luna, nnir, count(*) cnt from rul where cod = &v_cod group by an, luna, nnir;
prompt ==RUL_OBINV_NNIR_DISTINCT==
select an, luna, nnir, count(*) cnt from rul_obinv where cod = &v_cod group by an, luna, nnir;
exit;

View File

@@ -0,0 +1,302 @@
* test_init_env_auto_roagest.prg
* Varianta ROAGEST a test_init_env_auto.prg (acel fisier e specializat pe ROACONT -
* gcAppPath/clase/proceduri hardcodate D:\ROA\ROACONT\ - nu poate initializa mediul ROAGEST).
* Initializare completa de mediu FARA interactiune, pentru vfp9.exe -A -T.
*
* Utilizare:
* DO test_init_env_auto_roagest WITH 'CENTRAL', 'MARIUSM_AUTO', 'parola'
* IF gnHandle <= 0 ... eroare conectare
*
* Dupa apel sunt disponibile: goConn/goExecutor/goApp/goLog/goApi, goFirma/goCalendar,
* gnAn/gnLuna/gcS/gnIdFirma etc., SET PATH/CLASSLIB/PROCEDURE ca in roagest.prg,
* pachetele Oracle de sesiune setate (pack_sesiune/pack_contafin).
* ATENTIE: mentine lista de SET CLASSLIB/PROCEDURE sincronizata cu Programe\roagest.prg.
LPARAMETERS tcHost, tcSchema, tcPassword, tnAn, tnLuna
tcHost = IIF(EMPTY(tcHost), 'CENTRAL', tcHost)
tcSchema = IIF(EMPTY(tcSchema), 'MARIUSM_AUTO', tcSchema)
tcPassword = IIF(EMPTY(tcPassword), 'ROMFASTSOFT', tcPassword)
SET DELETED ON
SET ANSI ON
SET EXACT ON
SET SAFETY OFF
CLOSE DATABASES
SET CENTURY ON
SET DATE DMY
SET NULLDISPLAY TO ''
SET DECIMALS TO 4
SET POINT TO '.'
PUBLIC CT_SUCCES, CT_INSUCCES, crlf, gnAn, gnLuna, gnIdUtil, glEMama, gnIdFirma, gcCondSucursala, ;
gnIdSucursala, gcS, gcFirma, gcUserName, gcUserNameApp, gcNumeProgram, gcAppName, glLunaInchisa, ;
buton, gnButon, pnButon, gl406, gcAcces, gnIdProgram, gnId_Prg_Owner
CT_SUCCES = 1
CT_INSUCCES = -1
crlf = CHR(13) + CHR(10)
gnAn = IIF(EMPTY(tnAn), YEAR(DATE()), tnAn)
gnLuna = IIF(EMPTY(tnLuna), MONTH(DATE()), tnLuna)
gnIdUtil = -3
gnIdProgram = 0
gnId_Prg_Owner = 0
gnIdFirma = 110
gcCondSucursala = []
gnIdSucursala = m.gnIdFirma
gcS = UPPER(ALLTRIM(tcSchema))
gcFirma = m.gcS
gcUserName = m.gcS
gcUserNameApp = [MARIUS M]
gcNumeProgram = [ROAGEST]
gcAppName = [ROAGEST]
glLunaInchisa = .F.
glEMama = .F.
gl406 = .F.
* PUBLIC, nu Declare: nrcrt() (oproceduri_comune.prg) citeste NROR din ControlSource-uri
* de grid mult dupa ce acest program s-a terminat (Declare ar muri la RETURN)
PUBLIC nror(65000)
buton = 1
gnButon = 1
pnButon = 1
LOCAL lcPath
PUBLIC gcAppPath, DIRGEN, gcDirMare, gcBasePath, gcTempPath, gcGeneralIniFile, gcSettingsFile, ;
gcSecurityPath, gcSecurityFile
gcAppPath = [D:\ROA\ROAGEST\]
Set Default To (gcAppPath)
lcPath = gcAppPath + 'Date;' + ;
gcAppPath + 'Include;' + ;
gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + ;
gcAppPath + 'CLASE;' + ;
gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + ;
gcAppPath + 'RAPOARTE;' + ;
gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + ;
gcAppPath + 'COMUN\FERESTRE;' + ;
gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + ;
gcAppPath + 'COMUN\RAPOARTE;' + ;
gcAppPath + 'COMUN\MENIURI;' + ;
gcAppPath + 'COMUN\UTILE\GRIDEXTRAS;' + ;
gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + ;
gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + ;
gcAppPath + 'COMUN\UTILE\EXCEL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + ;
Addbs(Substr(gcAppPath,1,Rat([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
Local lcMainClassLib
lcMainClassLib = gcAppPath + "comun\clase\appwiz"
SET CLASSLIB TO (lcMainClassLib) ADDITIVE
SET CLASSLIB TO GESTIUNI ADDITIVE
SET CLASSLIB TO CAUT ADDITIVE
SET CLASSLIB TO BAZA ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO stocuri.vcx ADDITIVE
SET CLASSLIB TO rulaje.vcx ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO ointroduceri_web ADDITIVE
SET CLASSLIB TO ointroduceri_depozit ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO ferestre_cere_date.vcx ADDITIVE
SET CLASSLIB TO configurare.vcx ADDITIVE
SET CLASSLIB TO serii_numere.vcx ADDITIVE
SET CLASSLIB TO omodificari.vcx ADDITIVE
SET CLASSLIB TO ocompensari.vcx ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO onote_contabile ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO bon_fisc ADDITIVE
SET CLASSLIB TO onom_articole ADDITIVE
SET CLASSLIB TO onom_retete ADDITIVE
Set Classlib To oinventar ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO orapoarte_gestiuni ADDITIVE
SET CLASSLIB TO orapoarte_parametri ADDITIVE
SET CLASSLIB TO ONOM_CURS ADDITIVE
SET CLASSLIB TO ctl32_statusbar_fals.vcx additive
SET CLASSLIB TO ctl32_common.vcx additive
SET CLASSLIB TO ctl32_structs.vcx additive
SET CLASSLIB TO ctl32_progressbar.vcx additive
SET CLASSLIB TO ctl32_balloontip.vcx additive
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO oavize.vcx ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
Set Classlib To oschimbare_pret.vcx additive
SET CLASSLIB TO wwdialogs.vcx additive
SET CLASSLIB TO oimportxml.vcx additive
SET CLASSLIB TO excelxml.vcx ADDITIVE
SET CLASSLIB TO orapoarte_obinv.vcx ADDITIVE
SET CLASSLIB TO locale ADDITIVE
SET PROCEDURE TO PROCEDURI ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO cauta_alfa ADDITIVE
SET PROCEDURE TO pmenu ADDITIVE
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO oproceduri_listari.prg ADDITIVE
SET PROCEDURE TO oproceduri_configurare.prg ADDITIVE
SET PROCEDURE TO oproceduri_articole.prg ADDITIVE
SET PROCEDURE TO oproceduri_retete.prg ADDITIVE
SET PROCEDURE TO orapoarte.prg ADDITIVE
SET PROCEDURE TO mesaje ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg additive
SET PROCEDURE TO OPROCEDURI_CURS.PRG ADDITIVE
Set procedure to orapoarte_dinamice.prg additive
SET PROCEDURE TO validare.prg additive
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.prg ADDITIVE
SET PROCEDURE TO oinainte_de.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO Ocompensari.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO oproceduri_rulaje additive
SET PROCEDURE TO oproceduri_stocuri additive
SET PROCEDURE TO OINTRODUCERI ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO proceduri_excel.PRG ADDITIVE
SET PROCEDURE TO onomenclatoare.PRG ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO orefaceri ADDITIVE
SET PROCEDURE TO ofacturare_comun.PRG ADDITIVE
SET PROCEDURE TO ofacturare_stoc.PRG ADDITIVE
SET PROCEDURE TO oproceduri_casademarcat ADDITIVE
SET PROCEDURE TO oproceduri_casa_marcat_e500 ADDITIVE
SET PROCEDURE TO oproceduri_casa_marcat_mp500 ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO odocumente.prg ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO inchidere_k ADDITIVE
Set procedure to oschimbare_pret.prg additive
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO oupdate.prg additive
SET PROCEDURE TO procese.prg additive
SET PROCEDURE TO version.prg additive
SET PROCEDURE TO xmlaccess.prg additive
SET PROCEDURE TO xmlparser.prg additive
SET PROCEDURE TO filebringer.prg additive
SET PROCEDURE TO wwcodeupdate.prg additive
SET PROCEDURE TO wwhttp.prg ADDITIVE
Set Procedure To wwApi.prg Additive
SET PROCEDURE TO xdate.prg Additive
SET PROCEDURE TO ofacturare.prg ADDITIVE
SET PROCEDURE TO oproceduri_obinv.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO email.prg ADDITIVE
Declare Integer GetPrivateProfileString In WIN32API ;
string, String, String, String @, Integer, String
Declare Integer WritePrivateProfileString In Win32Api ;
string, String, String, String
Declare Integer CopyFile In WIN32API ;
STRING lpExistingFileName, STRING lpNewFileName, INTEGER bFailIfExists
Declare Integer PathFileExists In shlwapi STRING pszPath
If Type('goApi') = 'U'
Public goApi
goApi = Newobject("wwAPI", "wwAPI.prg")
ENDIF
PUBLIC gnHandle, goExecutor, goConn, goFirma, goCalendar, poLog, goLog, goApp
DIRGEN = [D:\ROA\]
gcDirMare = DIRGEN
gcBasePath = dirgen
gcSecurityPath = DIRGEN + 'Security\'
gcSecurityFile = gcSecurityPath + 'ROA_SECURITY.TXT'
gcGeneralIniFile = DIRGEN + "settings.ini"
gcSettingsFile = m.gcGeneralIniFile
gcTempPath = Addbs(shortpath(goApi.GetTempPath())) + gcS + [\]
If !Directory(gcTempPath)
Md (gcTempPath)
Endif
gcAcces = [1;2;3;4;5;6;7;8;]
poLog = Newobject("Log_Mesaje","Log_Mesaje.prg")
goLog = poLog
goApp = Createobject("wzApplication")
gnHandle = 0
goExecutor = createobject("oExecutor")
goConn = createobject("oConn")
goConn.Connect(m.tcHost, m.tcSchema, m.tcPassword)
IF m.gnHandle <= 0
RETURN .F.
ENDIF
LOCAL llSucces, lcSql
goFirma = null
llSucces = goExecutor.oExecuta("select * from syn_v_nom_firme where schema = ?gcS", "cFirma")
IF m.llSucces
SELECT cFirma
gnIdFirma = id_firma
gnIdSucursala = null
gcFirma = ALLTRIM(firma)
SCATTER NAME goFirma
IF TYPE('goFirma.codfiscalfro') = 'U'
ADDPROPERTY(goFirma, 'codfiscalfro', ALLTRIM(STRTRAN(ALLTRIM(NVL(goFirma.cod_fiscal, '')), 'RO', '')))
ENDIF
ELSE
goFirma = CREATEOBJECT('custom')
goFirma.addproperty('cod_fiscal', '')
goFirma.addproperty('schema', m.gcS)
goFirma.addproperty('firma', m.gcS)
goFirma.addproperty('codfiscalfro', '')
ENDIF
USE IN (SELECT('cFirma'))
goCalendar = null
llSucces = goExecutor.oExecuta('SELECT anul, luna, tva_incasare FROM calendar WHERE an*12+luna = (select MAX(an*12+luna) FROM calendar)', 'cCalendar')
IF m.llSucces
SELECT cCalendar
GO TOP
IF EMPTY(m.tnAn)
gnAn = anul
gnLuna = luna
ENDIF
SCATTER NAME goCalendar
ENDIF
USE IN (SELECT('cCalendar'))
CREATE CURSOR dual (dummy c(10))
INSERT INTO dual (dummy) VALUES ("")
actualizeaza_optiuni()
Do optiuni_firma IN oinit_optiuni.prg
lcSql = [begin pack_sesiune.set_Id_Util(?gnIdUtil); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_sesiune.setluna(?gnLuna); pack_sesiune.setan(?gnAn); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_sesiune.setlunabal(?gnLuna); pack_sesiune.setanbal(?gnAn); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_contafin.SET_DATA_RON(?gcS); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_sesiune.set_data_ron(?gcS); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_contafin.set_id_sucursala(?gnIdSucursala); end;]
llSucces = goExecutor.oExecuta(lcSql)
lcSql = [begin pack_contafin.set_id_firma(?gnIdFirma); end;]
llSucces = goExecutor.oExecuta(lcSql)
RETURN .T.

View File

@@ -0,0 +1,14 @@
* watchdog_selftest.prg - caz banal pentru validarea watchdog_vfp.ps1: afiseaza un MESSAGEBOX
* nativ (OK/Cancel) si asteapta. Foloseste doar pentru testarea utilitarului, nu face parte
* din nicio suita de regresie.
SET SAFETY OFF
SET TALK OFF
LOCAL lcLog
lcLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\watchdog_selftest_log.txt'
STRTOFILE('start' + CHR(13) + CHR(10), lcLog)
= MESSAGEBOX('Mesaj de test watchdog_vfp.ps1', 1, 'Watchdog selftest')
STRTOFILE('done' + CHR(13) + CHR(10), lcLog, 1)
QUIT

View File

@@ -0,0 +1,390 @@
# watchdog_vfp.ps1 - lanseaza un test VFP headless si detecteaza dialoguri native blocante
# (mesaje Windows, "View Parameter", erori modale) care nu apar in logul scris de script si
# nu sunt prinse de ON ERROR / mock-uri - cazul clasic de proces "agatat" cu CPU~0.
#
# Ce face: sterge .fxp-ul vechi, lanseaza `vfp9.exe -A -T "<script>"`, apoi polleaza la interval
# scurt ferestrele TOP-LEVEL ale procesului (EnumWindows + GetWindowThreadProcessId). Fereastra
# principala VFP se identifica prin Process.MainWindowHandle (.NET) - NU dupa numele clasei:
# VFP inregistreaza clase diferite prefixate "vfp9..." atat pentru shell-ul principal cat si
# pentru dialogurile proprii (ex. "View Parameter"), deci clasificarea pe clasa e nesigura.
# Orice fereastra NOUA, diferita de MainWindowHandle, e tratata ca dialog blocant.
#
# Pentru fiecare dialog detectat: captura PNG (PrintWindow, fallback CopyFromScreen daca iese
# neagra) + dump text (titlu, clasa, si textul/clasa fiecarui control copil via WM_GETTEXT - se
# citesc controale native Windows chiar daca apartin unui proces strain pe alta arhitectura).
#
# INTERZIS: watchdog-ul NU are voie sa foloseasca input real de tastatura/mouse (keybd_event,
# SetForegroundWindow, SendInput, mouse_event) - masina e PARTAJATA cu utilizatorul, iar un
# ESCAPE/click injectat la nivel de sistem ajunge in orice fereastra are focus in acel moment,
# nu neaparat in dialogul tintit (verificat: a ajuns in IDE-ul VFP al utilizatorului aflat in
# lucru in paralel, intrerupandu-l). -AutoDismiss foloseste STRICT mesaje Windows tintite pe
# handle-ul dialogului: buton copil cu text Cancel/Anulare/Renunta -> BM_CLICK; altfel
# WM_COMMAND IDCANCEL -> ESCAPE ca mesaj (WM_KEYDOWN/WM_KEYUP, nu input real) -> WM_CLOSE, in
# ordine, primul care inchide fereastra castiga. Dialogurile proprii VFP owner-drawn (ex.
# "View Parameter" - butoanele sunt desenate, nu HWND-uri reale) pot sa NU raspunda la niciunul -
# atunci dismiss-ul ESUEAZA CINSTIT (ramane deschis pana la timeout), nu se cade pe input real.
# Captura (PNG+dump text) e intotdeauna de incredere, indiferent de rezultatul dismiss-ului.
# Continua polling-ul dupa fiecare dismiss reusit, ca sa prinda si eventuale dialoguri urmatoare
# (pana la -MaxDialogs). Fara -AutoDismiss: captureaza primul dialog gasit, apoi opreste
# polling-ul (nu-l atinge).
#
# Procesul e omorat mereu la iesire (finally) - nu ramane niciodata viu.
#
# Utilizare:
# powershell -ExecutionPolicy Bypass -File watchdog_vfp.ps1 -Script "D:\...\test_x.prg" -AutoDismiss
# powershell -ExecutionPolicy Bypass -File watchdog_vfp.ps1 -Script "D:\...\test_x.prg" -TimeoutSec 60 -OutDir "D:\...\out"
#
# Parametri:
# -Script cale completa la .prg de rulat (obligatoriu)
# -Vfp cale la vfp9.exe (implicit instalarea standard x86)
# -TimeoutSec timeout total de polling (implicit 90)
# -OutDir folder pentru PNG-uri + log text (implicit "<folderul scriptului>\watchdog_out")
# -AutoDismiss inchide automat dialogurile gasite (Cancel/WM_CLOSE) si continua polling-ul
# -MaxDialogs cate dialoguri succesive sa trateze cu -AutoDismiss (implicit 10)
#
# Iesire: rezumat pe stdout (numar dialoguri, textul fiecaruia, caile PNG, exit code-ul
# procesului) + acelasi continut scris in "<Script>_watchdog.log" din -OutDir.
param(
[Parameter(Mandatory=$true)][string]$Script,
[string]$Vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe',
[int]$TimeoutSec = 90,
[string]$OutDir,
[switch]$AutoDismiss,
[int]$MaxDialogs = 10
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path $Script)) { throw "Nu gasesc scriptul: $Script" }
$Script = (Resolve-Path $Script).Path
$ScriptDir = [System.IO.Path]::GetDirectoryName($Script)
$ScriptBase = [System.IO.Path]::GetFileNameWithoutExtension($Script)
if (-not $OutDir) { $OutDir = Join-Path $ScriptDir 'watchdog_out' }
if (-not (Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null }
$LogPath = Join-Path $OutDir ($ScriptBase + '_watchdog.log')
Add-Type -AssemblyName System.Drawing
Add-Type @"
using System;
using System.Text;
using System.Runtime.InteropServices;
public class WdWin32 {
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
public static extern IntPtr SendMessageText(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT { public int Left, Top, Right, Bottom; }
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint nFlags);
}
"@
$WM_GETTEXT = 0x000D
$WM_CLOSE = 0x0010
$BM_CLICK = 0x00F5
function Get-TopWindowsForPid([int]$ProcId) {
$result = New-Object System.Collections.Generic.List[IntPtr]
$cb = {
param($hWnd, $lParam)
$owner = 0
[void][WdWin32]::GetWindowThreadProcessId($hWnd, [ref]$owner)
if ($owner -eq $ProcId -and [WdWin32]::IsWindowVisible($hWnd)) { $result.Add($hWnd) }
return $true
}
[WdWin32]::EnumWindows($cb, [IntPtr]::Zero) | Out-Null
return $result
}
function Get-ChildWindowsOf([IntPtr]$hWndParent) {
$result = New-Object System.Collections.Generic.List[IntPtr]
$cb = {
param($hWnd, $lParam)
$result.Add($hWnd)
return $true
}
[WdWin32]::EnumChildWindows($hWndParent, $cb, [IntPtr]::Zero) | Out-Null
return $result
}
# WM_GETTEXT (nu GetWindowText) - citeste text de la controale ale unui proces strain, indiferent
# de arhitectura (32/64 bit); GetWindowText poate esua tacut pe controale custom VFP.
function Get-WmText([IntPtr]$hWnd, [int]$MaxLen = 1024) {
$sb = New-Object System.Text.StringBuilder $MaxLen
[WdWin32]::SendMessageText($hWnd, $WM_GETTEXT, $MaxLen, $sb) | Out-Null
return $sb.ToString()
}
function Get-WinClassName([IntPtr]$hWnd) {
$sb = New-Object System.Text.StringBuilder 256
[WdWin32]::GetClassName($hWnd, $sb, $sb.Capacity) | Out-Null
return $sb.ToString()
}
function Test-BitmapAllBlack([System.Drawing.Bitmap]$bmp) {
$w = $bmp.Width; $h = $bmp.Height
if ($w -le 0 -or $h -le 0) { return $true }
for ($i = 0; $i -lt 9; $i++) {
$x = [Math]::Min($w - 1, [int]($w * (($i % 3) + 0.5) / 3))
$y = [Math]::Min($h - 1, [int]($h * ([Math]::Floor($i / 3) + 0.5) / 3))
$px = $bmp.GetPixel($x, $y)
if ($px.R -ne 0 -or $px.G -ne 0 -or $px.B -ne 0) { return $false }
}
return $true
}
# PrintWindow direct pe handle; fallback CopyFromScreen daca iese neagra (fereastra themed/GDI+
# care nu se randeaza corect prin PrintWindow). Foloseste doar pentru dialoguri surprinse
# on-screen - nu se muta off-screen aici (spre deosebire de vfp_ui_harness.ps1), fiindca scopul
# e sa surprindem exact dialogul care blocheaza, o singura data.
function Save-DialogScreenshot([IntPtr]$hWnd, [string]$Path) {
$rect = New-Object WdWin32+RECT
[WdWin32]::GetWindowRect($hWnd, [ref]$rect) | Out-Null
$w = $rect.Right - $rect.Left
$h = $rect.Bottom - $rect.Top
if ($w -le 0 -or $h -le 0) { return $false }
$bmp = New-Object System.Drawing.Bitmap $w, $h
$g = [System.Drawing.Graphics]::FromImage($bmp)
$hdc = $g.GetHdc()
$ok = [WdWin32]::PrintWindow($hWnd, $hdc, 2)
$g.ReleaseHdc($hdc)
$g.Dispose()
if ((-not $ok) -or (Test-BitmapAllBlack $bmp)) {
$bmp.Dispose()
$bmp = New-Object System.Drawing.Bitmap $w, $h
$g2 = [System.Drawing.Graphics]::FromImage($bmp)
try { $g2.CopyFromScreen($rect.Left, $rect.Top, 0, 0, (New-Object System.Drawing.Size $w, $h)) } catch {}
$g2.Dispose()
}
$bmp.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
return $true
}
function Get-DialogDump([IntPtr]$hWnd, [System.Collections.Generic.List[IntPtr]]$children) {
$title = Get-WmText $hWnd
$class = Get-WinClassName $hWnd
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add("dialog hwnd=$hWnd class='$class' title='$title'")
foreach ($c in $children) {
$ct = (Get-WmText $c 512).Trim()
$cc = Get-WinClassName $c
if ($ct -or $cc) { $lines.Add(" child hwnd=$c class='$cc' text='$ct'") }
}
# unary comma obligatoriu: fara ea, un List[string] cu UN SINGUR element (dialog fara copii,
# ex. "View Parameter") e "descompus" de PowerShell la scalar string simplu la return, iar
# indexarea ulterioara $dumpLines[0] citeste primul CARACTER, nu primul rand - prins la testul
# pe test_page3_articole.prg (rezumatul arata titlul "d" in loc de linia intreaga)
return , $lines.ToArray()
}
function Find-DismissButton([System.Collections.Generic.List[IntPtr]]$children) {
foreach ($c in $children) {
if ((Get-WinClassName $c) -ne 'Button') { continue }
$txt = ((Get-WmText $c 256) -replace '&', '').Trim()
if ($txt -ieq 'Cancel' -or $txt -ieq 'Anulare' -or $txt -ieq 'Renunta' -or $txt -ieq 'Renunță') { return $c }
}
return [IntPtr]::Zero
}
$WM_COMMAND = 0x0111
$WM_KEYDOWN = 0x0100
$WM_KEYUP = 0x0101
$VK_ESCAPE = 0x1B
$IDCANCEL = 2
# INTERZIS: input real de tastatura/mouse (keybd_event, SetForegroundWindow, SendInput,
# mouse_event). Masina e PARTAJATA cu utilizatorul - un ESCAPE injectat la nivel de sistem
# ajunge in orice fereastra are focus in acel moment, INDIFERENT carui proces ii apartine
# (verificat: a ajuns in IDE-ul VFP al utilizatorului, aflat in lucru in paralel, intrerupandu-l
# cu o eroare + "Execution was canceled by the user"). Foloseste STRICT mesaje Windows tintite pe
# HANDLE-ul dialogului (PostMessage/SendMessage: WM_COMMAND IDCANCEL, WM_KEYDOWN/WM_KEYUP
# VK_ESCAPE, WM_CLOSE, BM_CLICK) - astea nu ating focusul/inputul global, raman izolate la
# fereastra tintita. Dialogurile native VFP proprii (ex. "View Parameter") NU au controale copil
# reale (owner-drawn) si pot sa NU raspunda la niciunul dintre mesajele de mai jos - in acel caz
# dismiss-ul ESUEAZA CINSTIT (dialogul ramane deschis, procesul e omorat la timeout de finally),
# nu se cade pe input real. Captura (PNG+dump text) ramane oricum de incredere, indiferent de
# rezultatul dismiss-ului.
function Dismiss-Dialog([IntPtr]$hWnd, [System.Collections.Generic.List[IntPtr]]$children) {
$btn = Find-DismissButton $children
if ($btn -ne [IntPtr]::Zero) {
[WdWin32]::SendMessage($btn, $BM_CLICK, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null
Start-Sleep -Milliseconds 300
if (-not [WdWin32]::IsWindow($hWnd)) { return 'click Cancel/Anulare' }
return 'NEREUSIT: BM_CLICK pe Cancel/Anulare nu a inchis dialogul'
}
[WdWin32]::SendMessage($hWnd, $WM_COMMAND, [IntPtr]$IDCANCEL, [IntPtr]::Zero) | Out-Null
Start-Sleep -Milliseconds 300
if (-not [WdWin32]::IsWindow($hWnd)) { return 'WM_COMMAND IDCANCEL' }
[WdWin32]::SendMessage($hWnd, $WM_KEYDOWN, [IntPtr]$VK_ESCAPE, [IntPtr]::Zero) | Out-Null
[WdWin32]::SendMessage($hWnd, $WM_KEYUP, [IntPtr]$VK_ESCAPE, [IntPtr]::Zero) | Out-Null
Start-Sleep -Milliseconds 300
if (-not [WdWin32]::IsWindow($hWnd)) { return 'tasta ESCAPE trimisa cu SendMessage (mesaj, nu input real)' }
[WdWin32]::SendMessage($hWnd, $WM_CLOSE, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null
Start-Sleep -Milliseconds 300
if (-not [WdWin32]::IsWindow($hWnd)) { return 'WM_CLOSE' }
$motiv = if ($children.Count -eq 0) { 'fara controale copil (owner-drawn) si niciun mesaj tintit nu a functionat' } else { 'niciun mesaj tintit (WM_COMMAND/ESCAPE mesaj/WM_CLOSE) nu a functionat' }
return "NEREUSIT: dialogul a ramas deschis ($motiv) - fara input real, per regula masinii partajate"
}
# omoara doar vfp9 lansate pe ACEST script (linia de comanda contine calea lui), nu instante straine
function Stop-VfpForScript([string]$ScriptPath) {
Get-CimInstance Win32_Process -Filter "Name='vfp9.exe'" -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.CommandLine -and $_.CommandLine.ToLower().Contains($ScriptPath.ToLower())) {
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
}
# --- pregatire ---
$Fxp = [System.IO.Path]::ChangeExtension($Script, 'fxp')
if (Test-Path $Fxp) { Remove-Item $Fxp -Force }
Stop-VfpForScript $Script
Start-Sleep -Milliseconds 300
$log = New-Object System.Collections.Generic.List[string]
function Log([string]$s) { Write-Host $s; $log.Add($s) }
Log "watchdog_vfp: lansez $Vfp -A -T `"$Script`""
$proc = Start-Process -FilePath $Vfp -ArgumentList @('-A', '-T', "`"$Script`"") -PassThru
$dialogs = New-Object System.Collections.Generic.List[object]
$exitCode = $null
try {
# Fereastra principala = Process.MainWindowHandle (.NET), latch-uita o singura data. NU se
# poate distinge dupa numele clasei: VFP inregistreaza clase diferite prefixate "vfp9..." atat
# pentru shell-ul principal ("vfp99400000") CAT SI pentru dialoguri native proprii precum
# "View Parameter" ("vfp994000002") - verificat empiric, clasificarea pe clasa a lasat
# "View Parameter" nedetectat. MainWindowHandle e acelasi mecanism folosit deja cu succes in
# vfp_ui_harness.ps1 (Wait-MainWindowHandle) pentru shell-ul VFP.
$mainHwnd = [IntPtr]::Zero
$mwDeadline = (Get-Date).AddSeconds(20)
while ($mainHwnd -eq [IntPtr]::Zero -and (Get-Date) -lt $mwDeadline) {
$proc.Refresh()
if ($proc.HasExited) { break }
if ($proc.MainWindowHandle -ne [IntPtr]::Zero) { $mainHwnd = $proc.MainWindowHandle }
else { Start-Sleep -Milliseconds 200 }
}
if ($mainHwnd -ne [IntPtr]::Zero) {
Log ("fereastra principala VFP: hwnd={0} class='{1}' title='{2}'" -f $mainHwnd, (Get-WinClassName $mainHwnd), (Get-WmText $mainHwnd))
} else {
Log "ATENTIE: MainWindowHandle nu a aparut in 20s - orice fereastra gasita va fi tratata ca dialog."
}
$knownWindows = New-Object System.Collections.Generic.HashSet[IntPtr]
if ($mainHwnd -ne [IntPtr]::Zero) { [void]$knownWindows.Add($mainHwnd) }
$deadline = (Get-Date).AddSeconds($TimeoutSec)
$stop = $false
while (-not $stop -and (Get-Date) -lt $deadline) {
$proc.Refresh()
if ($proc.HasExited) { Log "proces terminat singur (exit code $($proc.ExitCode))"; break }
# daca MainWindowHandle inca nu era prins, incearca din nou (fereastra principala poate
# aparea mai tarziu decat asteptarea initiala de 20s in cazuri lente)
if ($mainHwnd -eq [IntPtr]::Zero -and $proc.MainWindowHandle -ne [IntPtr]::Zero) {
$mainHwnd = $proc.MainWindowHandle
[void]$knownWindows.Add($mainHwnd)
Log ("fereastra principala VFP (intarziata): hwnd={0} class='{1}' title='{2}'" -f $mainHwnd, (Get-WinClassName $mainHwnd), (Get-WmText $mainHwnd))
}
$windows = Get-TopWindowsForPid $proc.Id
foreach ($w in $windows) {
if ($knownWindows.Contains($w)) { continue }
[void]$knownWindows.Add($w)
if ($w -eq $mainHwnd) { continue }
$children = Get-ChildWindowsOf $w
$dumpLines = Get-DialogDump $w $children
$idx = $dialogs.Count
$png = Join-Path $OutDir ("{0}_dialog{1}.png" -f $ScriptBase, $idx)
Save-DialogScreenshot $w $png | Out-Null
Log "=== DIALOG $idx detectat ==="
foreach ($l in $dumpLines) { Log $l }
Log " screenshot: $png"
$dismissMethod = $null
if ($AutoDismiss) {
$dismissMethod = Dismiss-Dialog $w $children
Log " dismiss: $dismissMethod"
}
$dialogs.Add([pscustomobject]@{
Index = $idx
Title = ($dumpLines[0])
Png = $png
Dismiss = $dismissMethod
DumpText = ($dumpLines -join "`r`n")
})
if ($dialogs.Count -ge $MaxDialogs) { Log "MaxDialogs ($MaxDialogs) atins."; $stop = $true; break }
if (-not $AutoDismiss) { Log "AutoDismiss oprit - opresc polling-ul dupa primul dialog."; $stop = $true; break }
}
if (-not $stop) { Start-Sleep -Milliseconds 700 }
}
if (-not $proc.HasExited -and (Get-Date) -ge $deadline) {
Log "TIMEOUT (${TimeoutSec}s) - procesul e inca viu, il opresc."
}
$proc.Refresh()
if ($proc.HasExited) { $exitCode = $proc.ExitCode }
}
finally {
if ($proc -and -not $proc.HasExited) {
try { $proc.Kill() } catch {}
}
Stop-VfpForScript $Script
}
# --- rezumat ---
Log ""
Log "=== REZUMAT ==="
Log ("dialoguri detectate: {0}" -f $dialogs.Count)
foreach ($d in $dialogs) {
Log (" [{0}] {1}" -f $d.Index, $d.Title)
Log (" png: {0}" -f $d.Png)
if ($d.Dismiss) { Log (" dismiss: {0}" -f $d.Dismiss) }
}
Log ("exit code proces: {0}" -f ($(if ($null -ne $exitCode) { $exitCode } else { '(omorat de watchdog, nu s-a terminat singur)' })))
Log ("log complet: {0}" -f $LogPath)
[System.IO.File]::WriteAllLines($LogPath, $log)

103
utile/citeste_email.ps1 Normal file
View File

@@ -0,0 +1,103 @@
# Citeste emailurile din mbox-urile Thunderbird Portable (fara conectorul Gmail).
# citeste_email.ps1 [-Cauta <text>] [-Cont <nume>] [-Ultimele <n>] -> lista mesaje
# citeste_email.ps1 -Nr <linie> [-Linii <n>] -> corpul unui mesaj
param(
[string]$Cauta = '',
[string]$Cont = '',
[int]$Ultimele = 20,
[int]$Nr = 0,
[int]$Linii = 200,
[string]$Radacina = 'D:\UTIL\portable\PortableApps\ThunderbirdPortable\Data\profile\ImapMail'
)
$ErrorActionPreference = 'Stop'
function Get-Mboxuri {
param([string]$Cont)
$c = if ($Cont) { $Cont } else { '*' }
Get-ChildItem $Radacina -Directory -Filter $c |
ForEach-Object { Join-Path $_.FullName 'INBOX' } |
Where-Object { Test-Path $_ } |
Where-Object { (Get-Item $_).LastWriteTime -gt (Get-Date).AddYears(-2) }
}
function Deschide-Fisier {
param([string]$Cale)
# Thunderbird tine fisierul deschis -> FileShare ReadWrite obligatoriu
$fs = New-Object IO.FileStream($Cale, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::ReadWrite)
New-Object IO.StreamReader($fs, [Text.Encoding]::GetEncoding(28591))
}
function Decodeaza-Subiect {
param([string]$S)
$rx = [regex]'=\?([^?]+)\?([BbQq])\?([^?]*)\?='
$rx.Replace($S, {
param($m)
$enc = [Text.Encoding]::GetEncoding($m.Groups[1].Value)
$txt = $m.Groups[3].Value
if ($m.Groups[2].Value -match '[Bb]') {
$enc.GetString([Convert]::FromBase64String($txt))
} else {
$b = New-Object Collections.Generic.List[byte]
for ($i = 0; $i -lt $txt.Length; $i++) {
if ($txt[$i] -eq '=') { $b.Add([Convert]::ToByte($txt.Substring($i + 1, 2), 16)); $i += 2 }
elseif ($txt[$i] -eq '_') { $b.Add(32) }
else { $b.Add([byte][char]$txt[$i]) }
}
$enc.GetString($b.ToArray())
}
})
}
# ---- corpul unui mesaj: de la linia data pana la urmatorul separator mbox ----
if ($Nr -gt 0) {
foreach ($f in Get-Mboxuri -Cont $Cont) {
$r = Deschide-Fisier $f
try {
$i = 0; $scris = 0; $pornit = $false
while ($null -ne ($l = $r.ReadLine())) {
$i++
if ($i -lt $Nr) { continue }
# linia ceruta trebuie sa fie inceput de mesaj, altfel e alt cont
if ($i -eq $Nr -and $l -notmatch '^From - \w\w\w \w\w\w ') { break }
if ($pornit -and $l -match '^From - \w\w\w \w\w\w ') { break }
$pornit = $true
$l
if (++$scris -ge $Linii) { "... (taiat la $Linii linii, mareste cu -Linii)"; break }
}
if ($pornit) { return }
} finally { $r.Dispose() }
}
Write-Warning "Linia $Nr nu exista in mbox-urile cautate."
return
}
# ---- lista de mesaje ----
$mesaje = @()
foreach ($f in Get-Mboxuri -Cont $Cont) {
$cont = Split-Path (Split-Path $f -Parent) -Leaf
$r = Deschide-Fisier $f
try {
$i = 0; $inAntet = $false; $m = $null
while ($null -ne ($l = $r.ReadLine())) {
$i++
if ($l -match '^From - \w\w\w \w\w\w ') {
if ($m) { $mesaje += $m }
$m = [pscustomobject]@{ Cont = $cont; Linie = $i; Data = ''; De_la = ''; Subiect = '' }
$inAntet = $true
continue
}
if (-not $inAntet -or -not $m) { continue }
if ($l -eq '') { $inAntet = $false; continue }
if ($l -like 'Date: *' -and -not $m.Data) { $m.Data = $l.Substring(6).Trim() }
elseif ($l -like 'From: *' -and -not $m.De_la) { $m.De_la = $l.Substring(6).Trim() }
elseif ($l -like 'Subject: *' -and -not $m.Subiect) { $m.Subiect = Decodeaza-Subiect $l.Substring(9).Trim() }
}
if ($m) { $mesaje += $m }
} finally { $r.Dispose() }
}
if ($Cauta) {
$mesaje = $mesaje | Where-Object { $_.Subiect -like "*$Cauta*" -or $_.De_la -like "*$Cauta*" }
}
$mesaje | Select-Object -Last $Ultimele | Format-Table -AutoSize -Wrap

View File

@@ -19,7 +19,9 @@ if (-not $TranscriptPath) {
try { $TranscriptPath = (ConvertFrom-Json $stdin).transcript_path } catch { }
}
}
if (-not $TranscriptPath -or -not (Test-Path $TranscriptPath)) {
# la primul mesaj al unei sesiuni noi transcriptul inca nu e creat: fara fallback, ca sa nu raporteze alta sesiune
if ($TranscriptPath -and -not (Test-Path $TranscriptPath)) { exit 0 }
if (-not $TranscriptPath) {
$dir = Join-Path $env:USERPROFILE ".claude\projects\$((Get-Location).Path -replace '[:\\/]','-')"
if (Test-Path $dir) {
$f = Get-ChildItem "$dir\*.jsonl" | Sort-Object LastWriteTime -Descending | Select-Object -First 1

View File

@@ -42,8 +42,8 @@ function Adauga($cale, $tipare, $recursiv, $director) {
$docs = Join-Path $ProjectRoot 'docs'
$teste = @((Join-Path $comun 'utile\Teste'), (Join-Path $ProjectRoot 'utile\Teste')) | Where-Object { Test-Path $_ }
# patch-uri de review, handoff-uri, planuri de runda
Adauga $docs @('diff_runda*.patch', 'handoff*.md', 'plan_runda*.md', 'runda*.md') $false $false
# patch-uri de review, handoff-uri, planuri de runda, propuneri implementate
Adauga $docs @('diff_runda*.patch', 'handoff*.md', 'plan_runda*.md', 'runda*.md', 'propuneri_*.md') $false $false
# backup-uri de runda si de cache text
Adauga $ProjectRoot @('*.pre_runda*.bak') $true $false
Adauga $CacheRoot @('*.pre_runda*.bak', '*.vc2.bak', '*.sc2.bak') $true $false

529
utile/diag_actualizare.ps1 Normal file
View File

@@ -0,0 +1,529 @@
# diag_actualizare.ps1 - depanare PACK_UPDATE (actualizare ROA) pe serverul unui client.
# Urmareste pasii din COMUN\docs\depanare-pack-update.md: test conexiune, UPD_ISTORIC, UPD_LOG,
# script_master.log/script_master2.log (UTL_FILE pe directorul Oracle DMPDIR), versiuni aplicate
# pe fiecare schema, spatiu tablespace (detaliu + cat mai poate creste + top segmente pe cele
# blocate), spatiu disc pe server (optional, -Disc), jobul UPDATEROA_ZILNIC.
# STRICT READ-ONLY: doar select si UTL_FILE in mod 'R'. Nu apeleaza IncheiereActualizare, nu
# relanseaza actualizarea, nu face DDL/DML. Comenzile de deblocare/marire sunt doar AFISATE ca
# sugestie. Singura exceptie e -Disc: scrie un .ps1 temporar in DMPDIR pe server (prin
# sys.ExecuteScriptOS) ca sa citeasca spatiul liber pe discuri, si il sterge la final.
# Parola implicita (ROMFASTSOFT) e cea de dezvoltare, aceeasi folosita si pe serverele de client.
#
# Utilizare:
# powershell -File COMUN\utile\diag_actualizare.ps1 -Alias ROA_SIGMA
# powershell -File COMUN\utile\diag_actualizare.ps1 -Alias ROA_ROMCONSTRUCT -Tail 120
# powershell -File COMUN\utile\diag_actualizare.ps1 -Alias ROA_SIGMA -User contafin_oracle -Password ...
# powershell -File COMUN\utile\diag_actualizare.ps1 -Alias ROA_SIGMA -DoarLog # doar script_master.log
# powershell -File COMUN\utile\diag_actualizare.ps1 -Alias ROA_SIGMA -Disc # + spatiu liber pe discurile serverului
param(
[Parameter(Mandatory=$true)][string]$Alias,
[string]$User = 'contafin_oracle',
[string]$Password = 'ROMFASTSOFT',
[int]$Tail = 60,
[string]$SqlPlus = 'D:\ROA\instantclient_19_18\sqlplus.exe',
[switch]$DoarLog,
[switch]$Disc
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path $SqlPlus)) {
Write-Output ('EROARE: nu gasesc sqlplus la ' + $SqlPlus)
exit 1
}
$env:TNS_ADMIN = Split-Path $SqlPlus -Parent
$ConnStr = $User + '/' + $Password + '@' + $Alias
$TempDir = Join-Path $env:TEMP ('diag_actualizare_' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
function Remove-TempDir {
if (Test-Path $TempDir) { Remove-Item -LiteralPath $TempDir -Recurse -Force -ErrorAction SilentlyContinue }
}
function Invoke-Sql {
param([string]$Sql)
$sqlFile = Join-Path $TempDir ('q_' + [guid]::NewGuid().ToString('N') + '.sql')
[System.IO.File]::WriteAllText($sqlFile, $Sql, [System.Text.Encoding]::ASCII)
try {
$out = & $SqlPlus -L -S $ConnStr ('@' + $sqlFile) 2>&1
$code = $LASTEXITCODE
} catch {
$out = 'EROARE lansare sqlplus: ' + $_.Exception.Message
$code = -1
}
Remove-Item -LiteralPath $sqlFile -Force -ErrorAction SilentlyContinue
[PSCustomObject]@{ Text = ($out -join "`n"); Code = $code }
}
function Show-Section {
param([string]$Title, [string]$Text)
Write-Output ''
Write-Output ('===== ' + $Title + ' =====')
Write-Output $Text
if ($Text -match 'ORA-00942|ORA-01031') {
Write-Output '[AVERTISMENT] lipsesc probabil drepturi de acces (ORA-00942/ORA-01031) - pasul de mai sus poate fi incomplet cu acest utilizator.'
}
}
function Wait-RemoteFile {
# asteapta aparitia unui fisier scris de sys.ExecuteScriptOS (asincron) - polling, nu instant
param([string]$Directory, [string]$FileName, [int]$TimeoutSec = 60)
$deadline = (Get-Date).AddSeconds($TimeoutSec)
while ((Get-Date) -lt $deadline) {
$r = Invoke-Sql -Sql @"
set pagesize 0 linesize 100 trimspool on feedback off heading off
select dbms_lob.fileexists(bfilename('$Directory','$FileName')) from dual;
exit
"@
if ($r.Text -match '1') { return $true }
Start-Sleep -Seconds 2
}
return $false
}
# ---------- 1. Test conexiune ----------
Write-Output '===== 1. TEST CONEXIUNE ====='
Write-Output ('Alias=' + $Alias + ' User=' + $User + ' TNS_ADMIN=' + $env:TNS_ADMIN)
$r1 = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'CONEXIUNE_OK' from dual;
select 'VERSIUNE DB: ' || banner from v`$version where rownum = 1;
select 'SCHEMA CONECTATA: ' || sys_context('userenv','session_user') || ' DB: ' || sys_context('userenv','db_name') from dual;
exit
"@
Write-Output $r1.Text
if ($r1.Code -ne 0 -or $r1.Text -notmatch 'CONEXIUNE_OK') {
Write-Output ''
Write-Output 'EROARE: conexiunea a esuat. Verifica:'
Write-Output ' - tunelul SSH pe 1521 e deschis?'
Write-Output (' - aliasul TNS ' + $Alias + ' exista in ' + $env:TNS_ADMIN + '\tnsnames.ora si tinteste 127.0.0.1?')
Write-Output ' - user/parola corecte? (implicit contafin_oracle/ROMFASTSOFT)'
Remove-TempDir
exit 1
}
# ---------- 2. UPD_ISTORIC ----------
if (-not $DoarLog) {
$r2 = Invoke-Sql -Sql @"
set pagesize 200 linesize 200 trimspool on feedback off
column dataora_start format a19
column dataora_end format a30
column stare_text format a26
select * from (
select to_char(dataora_start,'yyyy-mm-dd hh24:mi:ss') dataora_start,
nvl(to_char(dataora_end,'yyyy-mm-dd hh24:mi:ss'), '<<< NEINCHEIATA >>>') dataora_end,
decode(stare, 0,'0-pornire', 1,'1-descarcare aplicatii', 2,'2-generare scripturi',
3,'3-aplicare scripturi', 4,'4-incheiat', 'necunoscuta(' || stare || ')') stare_text
from upd_istoric
order by dataora_start desc
) where rownum <= 10;
exit
"@
Show-Section -Title '2. UPD_ISTORIC (ultimele 10 rulari)' -Text $r2.Text
# ---------- 3. UPD_LOG (rularea curenta) ----------
$r3 = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off long 32000 longchunksize 32000
select 'AVERTISMENT: UPD_LOG se goleste la fiecare rulare; erorile din etapa 3 (aplicare scripturi in SQL*Plus extern) NU ajung aici - vezi script_master.log mai jos.' from dual;
select '-------------------------------------------' from dual;
select 'SECV ' || secventa || ' SCHEMA=' || nvl(schema,'-') || ' SCRIPT=' || nvl(script,'-') ||
' ' || to_char(dataora,'yyyy-mm-dd hh24:mi:ss') || chr(10) ||
nvl(explicatie,'(fara explicatie)') || chr(10) || '-------------------------------------------'
from upd_log
where dataora_start = (select max(dataora_start) from upd_log)
order by secventa;
exit
"@
Show-Section -Title '3. UPD_LOG (rularea curenta)' -Text $r3.Text
}
# ---------- 4. script_master.log / script_master2.log (UTL_FILE pe DMPDIR) ----------
foreach ($logFile in @('script_master.log', 'script_master2.log')) {
$r4 = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
ln_n pls_integer := $Tail;
la_buf dbms_sql.varchar2a;
ln_idx pls_integer := 0;
ln_cnt pls_integer := 0;
lc_line varchar2(32767);
lf utl_file.file_type;
lc_path all_directories.directory_path%type;
begin
begin
select directory_path into lc_path from all_directories where directory_name = 'DMPDIR';
exception when no_data_found then lc_path := '(directorul Oracle DMPDIR nu exista)';
end;
dbms_output.put_line('Director DMPDIR -> ' || lc_path || ' fisier: $logFile');
lf := utl_file.fopen('DMPDIR', '$logFile', 'R', 32767);
begin
loop
utl_file.get_line(lf, lc_line, 32767);
ln_idx := mod(ln_cnt, ln_n) + 1;
la_buf(ln_idx) := lc_line;
ln_cnt := ln_cnt + 1;
end loop;
exception when no_data_found then null;
end;
utl_file.fclose(lf);
dbms_output.put_line('total linii citite: ' || ln_cnt || ' (ultimele ' || ln_n || ' afisate mai jos)');
dbms_output.put_line('-------------------------------------------');
if ln_cnt <= ln_n then
for i in 1 .. ln_cnt loop dbms_output.put_line(la_buf(i)); end loop;
else
for i in 0 .. ln_n - 1 loop dbms_output.put_line(la_buf(mod(ln_cnt + i, ln_n) + 1)); end loop;
end if;
exception
when others then
if utl_file.is_open(lf) then utl_file.fclose(lf); end if;
if sqlcode = -29280 then
dbms_output.put_line('EROARE: directorul Oracle DMPDIR nu exista sau alias gresit (ORA-29280).');
elsif sqlcode = -29283 then
dbms_output.put_line('EROARE: fisierul $logFile nu exista in DMPDIR sau nu poate fi citit (ORA-29283). Normal daca actualizarea nu a ajuns inca la etapa 3, sau pentru script_master2.log daca rularea a picat inainte de pasii finali.');
else
dbms_output.put_line('EROARE: ' || sqlerrm);
end if;
end;
/
exit
"@
Show-Section -Title ('4. ' + $logFile) -Text $r4.Text
}
if ($DoarLog) { Remove-TempDir; exit 0 }
# ---------- 5. Versiuni per schema ----------
$rSchemas = Invoke-Sql -Sql @"
set pagesize 0 linesize 200 trimspool on feedback off heading off
select owner from all_tables where table_name = 'VERSIUNE' order by owner;
exit
"@
$schemas = @($rSchemas.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_ -match '^[A-Z_][A-Z0-9_]*$' })
if ($schemas.Count -eq 0) {
Show-Section -Title '5. VERSIUNI PE SCHEMA' -Text ('Nu am gasit nicio schema cu tabela VERSIUNE (all_tables).' + "`n" + $rSchemas.Text)
} else {
$sb = New-Object System.Text.StringBuilder
[void]$sb.AppendLine('set pagesize 0 linesize 250 trimspool on feedback off heading off')
foreach ($sch in $schemas) {
$prefix = if ($sch -eq 'CONTAFIN_ORACLE') { 'CO' } else { 'FF' }
[void]$sb.AppendLine(@"
select 'ULTIMA [$sch] ' || tip_script || ' data=' || to_char(data_script,'yyyy-mm-dd') || ' seq=' || seq_script
from (select tip_script, data_script, seq_script from $sch.VERSIUNE order by data_script desc, seq_script desc)
where rownum = 1;
"@)
[void]$sb.AppendLine(@"
select 'CANDIDAT [$sch] ' || msg from (
select msg, ord from (
select script_name || ' (data=' || to_char(script_date,'yyyy-mm-dd') || ' seq=' || script_seq || ')' msg, 1 ord
from (
select d.script_name, d.script_date, d.script_seq
from upd_database d,
(select data_script mx_date, seq_script mx_seq from (
select data_script, seq_script from $sch.VERSIUNE order by data_script desc, seq_script desc
) where rownum = 1) w
where d.script_name like '$prefix\_%' escape '\'
and (d.script_date > w.mx_date or (d.script_date = w.mx_date and d.script_seq > w.mx_seq))
order by d.script_date, d.script_seq
) where rownum = 1
union all
select '(la zi - niciun script $prefix neaplicat gasit dupa ultima versiune)' msg, 2 ord from dual
) order by ord
) where rownum = 1;
"@)
}
[void]$sb.AppendLine('exit')
$r5 = Invoke-Sql -Sql $sb.ToString()
Show-Section -Title '5. VERSIUNI PE SCHEMA (ultima aplicata / prima neaplicata - candidat)' -Text $r5.Text
}
# ---------- 6. Spatiu tablespace: detaliu pe datafile + cat mai poate creste ----------
$r6 = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column tablespace_name format a15
column file_name format a55
column autoext format a4
select f.tablespace_name, f.file_name,
round(f.bytes/1048576) mb_curent,
round(f.maxbytes/1048576) mb_max,
f.autoextensible autoext,
round(f.increment_by * t.block_size / 1048576) mb_increment
from dba_data_files f, dba_tablespaces t
where f.tablespace_name = t.tablespace_name
order by f.tablespace_name, f.file_name;
column tablespace_name format a15
column stare format a26
with ts_free as (
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
), agg as (
select f.tablespace_name, sum(f.bytes) alocat_bytes, sum(f.maxbytes) max_bytes,
sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
from dba_data_files f
group by f.tablespace_name
)
select a.tablespace_name,
round(a.alocat_bytes/1048576) mb_alocat,
round(a.max_bytes/1048576) mb_max,
round(nvl(tf.free_bytes,0)/1048576) mb_liber,
round((nvl(tf.free_bytes,0) + a.creste_bytes)/1048576) mb_poate_creste,
case when a.max_bytes > 0 and (nvl(tf.free_bytes,0) + a.creste_bytes) < 1048576
then 'ATENTIE: MAXBYTES ATINS' end stare
from agg a, ts_free tf
where a.tablespace_name = tf.tablespace_name(+)
order by a.tablespace_name;
exit
"@
Show-Section -Title '6. SPATIU TABLESPACE (detaliu pe datafile + cat mai poate creste)' -Text ('mb_poate_creste = liber curent + (maxbytes - alocat) - spatiul real disponibil inainte de ORA-01653, nu doar liberul de acum.' + "`n`n" + $r6.Text)
# tablespace-urile cu maxbytes efectiv atins - identificate separat, pentru top segmente mai jos
$r6m = Invoke-Sql -Sql @"
set pagesize 0 linesize 100 trimspool on feedback off heading off
with ts_free as (
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
), agg as (
select f.tablespace_name, sum(f.maxbytes) max_bytes, sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
from dba_data_files f
group by f.tablespace_name
)
select 'TS_ATENTIE|' || a.tablespace_name
from agg a, ts_free tf
where a.tablespace_name = tf.tablespace_name(+)
and a.max_bytes > 0
and (nvl(tf.free_bytes,0) + a.creste_bytes) < 1048576;
exit
"@
$tsProblema = @($r6m.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('TS_ATENTIE|') } | ForEach-Object { $_.Substring(11) } | Where-Object { $_ -match '^[A-Z0-9_]+$' })
if ($tsProblema.Count -gt 0) {
$sbSeg = New-Object System.Text.StringBuilder
[void]$sbSeg.AppendLine('set pagesize 0 linesize 250 trimspool on feedback off heading off')
foreach ($ts in $tsProblema) {
[void]$sbSeg.AppendLine("select 'Tablespace $ts - top 15 segmente:' from dual;")
[void]$sbSeg.AppendLine(@"
select rpad(owner,20) || rpad(segment_name,35) || rpad(segment_type,18) || round(bytes/1048576) || ' MB'
from (select owner, segment_name, segment_type, bytes from dba_segments where tablespace_name = '$ts' order by bytes desc)
where rownum <= 15;
"@)
if ($ts -eq 'SYSTEM') {
[void]$sbSeg.AppendLine("select 'NOTA: privilegiile ANY (ex. DROP ANY TABLE/TRUNCATE ANY TABLE) nu se aplica pe obiecte din schema SYS cand O7_DICTIONARY_ACCESSIBILITY=FALSE - curatarea unui tabel din SYS cere conectare SYSDBA, nu contafin_oracle.' from dual;")
}
}
[void]$sbSeg.AppendLine('exit')
$r6s = Invoke-Sql -Sql $sbSeg.ToString()
Write-Output ''
Write-Output ('--- Top segmente pe tablespace-urile marcate ATENTIE (' + ($tsProblema -join ', ') + ') ---')
Write-Output $r6s.Text
}
# ---------- 7. Spatiu disc pe server (optional, scrie un .ps1 temporar in DMPDIR) ----------
Write-Output ''
Write-Output '===== 7. SPATIU DISC (server) ====='
if (-not $Disc) {
Write-Output 'Sarit implicit - ruleaza cu -Disc pentru spatiul liber pe discurile fizice ale serverului.'
Write-Output 'Este singura parte a scriptului care NU e strict read-only: scrie un .ps1 temporar in DMPDIR (prin sys.ExecuteScriptOS) si il sterge la final.'
} else {
$rPaths = Invoke-Sql -Sql @"
set pagesize 0 linesize 300 trimspool on feedback off heading off
select 'DATAFILE_PATH|' || file_name from dba_data_files order by file_name;
exit
"@
$datafilePaths = @($rPaths.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('DATAFILE_PATH|') } | ForEach-Object { $_.Substring(14) })
$psTemplate = @'
$dOut = 'C:\DMPDIR\diag_disc_out.txt'
Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
$pct = 0
if ($_.Size -gt 0) { $pct = [math]::Round($_.FreeSpace/$_.Size*100,1) }
"DISC {0} {1} {2} {3}" -f $_.DeviceID, [math]::Round($_.Size/1GB,2), [math]::Round($_.FreeSpace/1GB,2), $pct
} | Out-File -Encoding ascii $dOut
__DATAFILES__
'@
$fileLines = foreach ($p in $datafilePaths) {
$escaped = $p.Replace("'", "''")
'Get-Item ''' + $escaped + ''' -ErrorAction SilentlyContinue | ForEach-Object { "FISIER {0} {1}" -f $_.FullName, $_.Length } | Out-File -Encoding ascii -Append $dOut'
}
$psScript = $psTemplate.Replace('__DATAFILES__', ([string]::Join("`n", $fileLines)))
$psScriptSql = $psScript.Replace("'", "''")
$rLaunch = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
lcPS server_info.value%type;
begin
select value into lcPS from server_info where upper(name) = 'POWERSHELLPATH';
begin pack_utils_file.filedelete('DMPDIR','diag_disc_out.txt'); exception when others then null; end;
begin pack_utils_file.filedelete('DMPDIR','diag_disc.ps1'); exception when others then null; end;
pack_utils_file.clob2fileX('$psScriptSql', 'DMPDIR', 'diag_disc.ps1');
sys.ExecuteScriptOS(lcPS, 'C:\DMPDIR\diag_disc.ps1');
dbms_output.put_line('Lansat pe server (' || lcPS || '), astept rezultatul...');
exception when others then
dbms_output.put_line('EROARE la lansare: ' || sqlerrm);
end;
/
exit
"@
Write-Output $rLaunch.Text
if ($rLaunch.Text -notmatch 'EROARE la lansare') {
$gata = Wait-RemoteFile -Directory 'DMPDIR' -FileName 'diag_disc_out.txt' -TimeoutSec 60
if (-not $gata) {
Write-Output 'EROARE: rezultatul nu a aparut in 60s. Posibile cauze: server_info.POWERSHELLPATH gresit, politica de executie PowerShell blocheaza scriptul, sau sys.ExecuteScriptOS nu are drept de executie. Verifica manual C:\DMPDIR\diag_disc.ps1 pe server.'
} else {
$rRead = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
lf utl_file.file_type;
lc_line varchar2(32767);
begin
lf := utl_file.fopen('DMPDIR','diag_disc_out.txt','R',32767);
begin
loop
utl_file.get_line(lf, lc_line, 32767);
dbms_output.put_line(lc_line);
end loop;
exception when no_data_found then null;
end;
utl_file.fclose(lf);
begin pack_utils_file.filedelete('DMPDIR','diag_disc_out.txt'); exception when others then null; end;
begin pack_utils_file.filedelete('DMPDIR','diag_disc.ps1'); exception when others then null; end;
exception when others then
dbms_output.put_line('EROARE citire: ' || sqlerrm);
end;
/
exit
"@
$discLines = @()
$fileLinesOut = @()
foreach ($line in ($rRead.Text -split "`r?`n")) {
if ($line -match '^DISC\s+(\S+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)') {
$discLines += (' disc {0}: total {1} GB, liber {2} GB ({3}%)' -f $Matches[1], $Matches[2], $Matches[3], $Matches[4])
} elseif ($line -match '^FISIER\s+(\S+)\s+(\d+)') {
$mb = [math]::Round(([double]$Matches[2]) / 1048576, 1)
$fileLinesOut += (' {0}: {1} MB pe disc' -f $Matches[1], $mb)
} elseif ($line -match '\S') {
$discLines += (' ' + $line)
}
}
Write-Output 'Discuri fixe:'
Write-Output ($discLines -join "`n")
Write-Output 'Dimensiune reala pe disc a datafile-urilor:'
Write-Output ($fileLinesOut -join "`n")
}
}
}
# ---------- 8. Job UPDATEROA_ZILNIC ----------
$r8 = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column log_date format a20
column additional_info format a90 word_wrapped
select * from (
select to_char(log_date,'yyyy-mm-dd hh24:mi:ss') log_date, status, additional_info
from dba_scheduler_job_run_details
where job_name = 'UPDATEROA_ZILNIC'
order by log_date desc
) where rownum <= 10;
exit
"@
Show-Section -Title '8. JOB UPDATEROA_ZILNIC (ultimele 10 rulari)' -Text ('AVERTISMENT: additional_info e frecvent falsa - la orice esec se apeleaza EmailLog, iar daca SMTP-ul e picat ridica ORA-20000 care masca eroarea reala. Cauza adevarata e in UPD_LOG / script_master.log de mai sus.' + "`n`n" + $r8.Text)
# ---------- 9. Verdict ----------
$r9 = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
ln_stare upd_istoric.stare%type;
ld_end upd_istoric.dataora_end%type;
ld_start upd_istoric.dataora_start%type;
lc_stare_text varchar2(50);
lc_line varchar2(32767);
lf utl_file.file_type;
lc_errs varchar2(4000);
ln_errcnt pls_integer := 0;
lb_spatiu boolean := false;
lc_tspatiu varchar2(100);
lc_match varchar2(200);
lc_datafile varchar2(400);
begin
select stare, dataora_end, dataora_start into ln_stare, ld_end, ld_start
from (select stare, dataora_end, dataora_start from upd_istoric order by dataora_start desc)
where rownum = 1;
lc_stare_text := case ln_stare
when 0 then '0-pornire' when 1 then '1-descarcare aplicatii' when 2 then '2-generare scripturi'
when 3 then '3-aplicare scripturi' when 4 then '4-incheiat cu succes'
else 'necunoscuta(' || ln_stare || ')' end;
dbms_output.put_line('Ultima rulare: ' || to_char(ld_start,'yyyy-mm-dd hh24:mi:ss') || ' stare=' || lc_stare_text ||
case when ld_end is null then ' <<< NEINCHEIATA >>>' else ' incheiata ' || to_char(ld_end,'yyyy-mm-dd hh24:mi:ss') end);
if ld_end is null and ln_stare = 3 then
dbms_output.put_line('Rularea a ramas la aplicarea scripturilor (etapa 3, SQL*Plus extern). Cauza reala e in script_master.log, NU in UPD_LOG.');
elsif ld_end is null then
dbms_output.put_line('Rularea nu s-a incheiat (stare ' || lc_stare_text || ').');
else
dbms_output.put_line('Ultima rulare s-a incheiat normal.');
end if;
begin
lf := utl_file.fopen('DMPDIR', 'script_master.log', 'R', 32767);
begin
loop
utl_file.get_line(lf, lc_line, 32767);
if instr(lc_line,'ORA-06512') = 0 and (instr(upper(lc_line), 'ORA-') > 0 or instr(lc_line, 'ERROR') > 0) then
ln_errcnt := ln_errcnt + 1;
lc_errs := lc_errs || chr(10) || lc_line;
if regexp_like(lc_line, 'ORA-016[0-9][0-9]|ORA-30036') then
lb_spatiu := true;
lc_match := regexp_substr(upper(lc_line), 'TABLESPACE [A-Z0-9_]+', 1, 1);
if lc_match is not null then lc_tspatiu := ltrim(substr(lc_match, 11)); end if;
end if;
end if;
end loop;
exception when no_data_found then null;
end;
utl_file.fclose(lf);
exception when others then
if utl_file.is_open(lf) then utl_file.fclose(lf); end if;
end;
if ln_errcnt > 0 then
dbms_output.put_line('script_master.log contine erori (' || ln_errcnt || '):' || lc_errs);
else
dbms_output.put_line('Nu s-a gasit "ORA-"/"ERROR" in script_master.log.');
end if;
if lb_spatiu then
dbms_output.put_line('=== PROBLEMA DE SPATIU, NU DE SQL === tablespace implicat: ' || nvl(lc_tspatiu,'necunoscut'));
if lc_tspatiu is not null then
begin
select file_name into lc_datafile
from (select file_name from dba_data_files where tablespace_name = lc_tspatiu order by file_name)
where rownum = 1;
dbms_output.put_line('Sugestie (NU se executa automat): ALTER DATABASE DATAFILE ''' || lc_datafile ||
''' AUTOEXTEND ON NEXT 50M MAXSIZE <valoare mai mare>;');
exception when no_data_found then null;
end;
end if;
dbms_output.put_line('Pe XE limita de 11GB e pe datele utilizator, nu pe SYSTEM - un maxbytes mic pe SYSTEM (sau alt tablespace de sistem) e o setare de instalare, se poate mari.');
end if;
dbms_output.put_line('Vezi sectiunea 4 pentru context complet in log, sectiunea 5 pentru scriptul candidat per schema, sectiunea 6 pentru spatiul pe tablespace/segmente.');
dbms_output.put_line('Daca rularea a ramas blocata (stare < 4 de peste o ora) si problema de mai sus e reparata, deblocarea (NU se executa automat de acest script):');
dbms_output.put_line(' exec contafin_oracle.pack_update.IncheiereActualizare;');
end;
/
exit
"@
Show-Section -Title '9. VERDICT' -Text $r9.Text
if ($r9.Text -match 'PROBLEMA DE SPATIU' -and -not $Disc) {
Write-Output 'Sugestie: reruleaza cu -Disc pentru spatiul liber pe discurile fizice ale serverului (poate lipsi spatiu pe disc pentru crestere, nu doar maxbytes).'
}
Remove-TempDir
exit 0

672
utile/diag_spatiu.ps1 Normal file
View File

@@ -0,0 +1,672 @@
# diag_spatiu.ps1 - diagnostic de spatiu pe serverul Oracle al unui client ROA.
# Raspunde "cat spatiu mai am si ce ocupa unde": tablespace/datafile (cat mai poate creste),
# plafonul de date al editiei XE, audit Oracle (tabele + fisiere .aud), alert log/trace/ADR,
# archivelog/FRA, spatiu pe discurile
# fizice ale serverului, si alti mancatori de spatiu (recyclebin, UNDO, istoric statistici/
# scheduler, TEMP, top segmente generic - fara nume de tabele ROA hardcodate).
# STRICT READ-ONLY pe baza: doar select/agregate si UTL_FILE in mod 'R'. Actiunile de curatare
# din verdict sunt doar AFISATE ca sugestie, niciodata executate (niciun purge/truncate/alter).
# Singura scriere e sub -Disc: un .ps1 temporar in DMPDIR pe server (prin sys.ExecuteScriptOS),
# sters la final cu verificare.
# -SysPassword e optional, fara valoare implicita, nesalvat nicaieri (parola SYS difera per
# server). Sectiunile care o cer (MAX_PDB_STORAGE din CDB$ROOT, audit intern sys.aud$/fga_log$,
# recyclebin la nivel de baza) se sar curat, cu mesaj, daca nu e data - diagnosticul de baza
# merge complet fara ea.
#
# Utilizare:
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -Disc
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -SysPassword ...
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -Top 30 -Disc
param(
[Parameter(Mandatory=$true)][string]$Alias,
[string]$User = 'contafin_oracle',
[string]$Password = 'ROMFASTSOFT',
[string]$SysPassword,
[string]$SqlPlus = 'D:\ROA\instantclient_19_18\sqlplus.exe',
[switch]$Disc,
[int]$Top = 20
)
$ErrorActionPreference = 'Stop'
# praguri de alerta, aceleasi ca in PACK_DIAG_SPATIU (jobul zilnic de la clienti): tablespace-ul
# intra in atentie sub pragul absolut SAU sub procentul din maximul lui, ca sa existe timp de reactie
$PragTsMb = 2048
$PragTsPct = 15
$PragFraPct = 75
if (-not (Test-Path $SqlPlus)) {
Write-Output ('EROARE: nu gasesc sqlplus la ' + $SqlPlus)
exit 1
}
$env:TNS_ADMIN = Split-Path $SqlPlus -Parent
$ConnStr = $User + '/' + $Password + '@' + $Alias
$ConnStrSys = if ($SysPassword) { 'sys/' + $SysPassword + '@' + $Alias + ' as sysdba' } else { $null }
$TempDir = Join-Path $env:TEMP ('diag_spatiu_' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
function Remove-TempDir {
if (Test-Path $TempDir) { Remove-Item -LiteralPath $TempDir -Recurse -Force -ErrorAction SilentlyContinue }
}
function Invoke-SqlAs {
param([string]$Sql, [string]$Connect)
$sqlFile = Join-Path $TempDir ('q_' + [guid]::NewGuid().ToString('N') + '.sql')
[System.IO.File]::WriteAllText($sqlFile, $Sql, [System.Text.Encoding]::ASCII)
try {
$out = & $SqlPlus -L -S $Connect ('@' + $sqlFile) 2>&1
$code = $LASTEXITCODE
} catch {
$out = 'EROARE lansare sqlplus: ' + $_.Exception.Message
$code = -1
}
Remove-Item -LiteralPath $sqlFile -Force -ErrorAction SilentlyContinue
[PSCustomObject]@{ Text = ($out -join "`n"); Code = $code }
}
function Invoke-Sql {
param([string]$Sql)
Invoke-SqlAs -Sql $Sql -Connect $ConnStr
}
function Invoke-SqlSys {
# ruleaza doar daca -SysPassword a fost dat; altfel intoarce $null (apelantul trebuie sa verifice)
param([string]$Sql)
if (-not $ConnStrSys) { return $null }
Invoke-SqlAs -Sql $Sql -Connect $ConnStrSys
}
function Show-Section {
param([string]$Title, [string]$Text)
Write-Output ''
Write-Output ('===== ' + $Title + ' =====')
Write-Output $Text
if ($Text -match 'ORA-00942|ORA-01031') {
Write-Output '[AVERTISMENT] lipsesc probabil drepturi de acces (ORA-00942/ORA-01031) - pasul de mai sus poate fi incomplet cu acest utilizator.'
}
}
function Wait-RemoteFile {
# asteapta aparitia unui fisier scris de sys.ExecuteScriptOS (asincron) - polling, nu instant
param([string]$Directory, [string]$FileName, [int]$TimeoutSec = 60)
$deadline = (Get-Date).AddSeconds($TimeoutSec)
while ((Get-Date) -lt $deadline) {
$r = Invoke-Sql -Sql @"
set pagesize 0 linesize 100 trimspool on feedback off heading off
select dbms_lob.fileexists(bfilename('$Directory','$FileName')) from dual;
exit
"@
if ($r.Text -match '1') { return $true }
Start-Sleep -Seconds 2
}
return $false
}
# ---------- 1. Test conexiune + versiune + CDB/PDB ----------
Write-Output '===== 1. TEST CONEXIUNE ====='
Write-Output ('Alias=' + $Alias + ' User=' + $User + ' TNS_ADMIN=' + $env:TNS_ADMIN)
$r1 = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'CONEXIUNE_OK' from dual;
select 'VERSIUNE DB: ' || banner from v`$version where rownum = 1;
select 'SCHEMA CONECTATA: ' || sys_context('userenv','session_user') || ' DB: ' || sys_context('userenv','db_name') from dual;
exit
"@
Write-Output $r1.Text
if ($r1.Code -ne 0 -or $r1.Text -notmatch 'CONEXIUNE_OK') {
Write-Output ''
Write-Output 'EROARE: conexiunea a esuat. Verifica:'
Write-Output ' - tunelul SSH pe 1521 e deschis?'
Write-Output (' - aliasul TNS ' + $Alias + ' exista in ' + $env:TNS_ADMIN + '\tnsnames.ora si tinteste 127.0.0.1?')
Write-Output ' - user/parola corecte? (implicit contafin_oracle/ROMFASTSOFT)'
Remove-TempDir
exit 1
}
$verMajor = 0
if ($r1.Text -match 'Release\s+(\d+)\.') { $verMajor = [int]$Matches[1] }
elseif ($r1.Text -match 'Database\s+(\d+)[gc]\b') { $verMajor = [int]$Matches[1] }
if ($verMajor -eq 0) {
Write-Output '[AVERTISMENT] nu am putut determina versiunea majora din banner - presupun 11 (fara facilitati 12c+).'
$verMajor = 11
}
$ver12plus = ($verMajor -ge 12)
$ver11plus = ($verMajor -ge 11)
Write-Output ('Versiune majora detectata: ' + $verMajor + ' (CDB/PDB si unified_audit_trail: ' + $(if ($ver12plus) {'da'} else {'nu, sarite mai jos'}) + ')')
if ($ver12plus) {
$rCdb = Invoke-Sql -Sql @"
set pagesize 0 linesize 200 trimspool on feedback off heading off
select 'CDB=' || cdb from v`$database;
select 'CONTAINER ' || con_id || ' ' || name || ' ' || open_mode from v`$containers order by con_id;
exit
"@
Show-Section -Title '1b. CDB/PDB' -Text $rCdb.Text
} else {
Write-Output ''
Write-Output '===== 1b. CDB/PDB ====='
Write-Output 'Sarit - baza sub versiunea 12c (CDB/PDB nu se aplica pe 10.2/11g).'
}
# ---------- 2. Tablespace / datafile ----------
$r2 = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column tablespace_name format a15
column file_name format a55
column autoext format a4
select f.tablespace_name, f.file_name,
round(f.bytes/1048576) mb_curent,
round(f.maxbytes/1048576) mb_max,
f.autoextensible autoext,
round(f.increment_by * t.block_size / 1048576) mb_increment
from dba_data_files f, dba_tablespaces t
where f.tablespace_name = t.tablespace_name
order by f.tablespace_name, f.file_name;
column tablespace_name format a15
column stare format a26
with ts_free as (
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
), agg as (
select f.tablespace_name, sum(f.bytes) alocat_bytes, sum(f.maxbytes) max_bytes,
sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
from dba_data_files f
group by f.tablespace_name
)
select a.tablespace_name,
round(a.alocat_bytes/1048576) mb_alocat,
round(a.max_bytes/1048576) mb_max,
round(nvl(tf.free_bytes,0)/1048576) mb_liber,
round((nvl(tf.free_bytes,0) + a.creste_bytes)/1048576) mb_poate_creste,
case when a.max_bytes > 0 and (nvl(tf.free_bytes,0) + a.creste_bytes) <
greatest($PragTsMb * 1048576, a.max_bytes * $PragTsPct / 100)
then 'ATENTIE: APROAPE FARA LOC' end stare
from agg a, ts_free tf
where a.tablespace_name = tf.tablespace_name(+)
order by a.tablespace_name;
exit
"@
Show-Section -Title '2. SPATIU TABLESPACE (detaliu pe datafile + cat mai poate creste)' -Text ('mb_poate_creste = liber curent + (maxbytes - alocat) - spatiul real disponibil inainte de ORA-01653, nu doar liberul de acum.' + "`n" + ('Prag de atentie: sub ' + $PragTsMb + ' MB ramasi sau sub ' + $PragTsPct + '% din maximul tablespace-ului.') + "`n`n" + $r2.Text)
# tablespace-urile care au trecut pragul de atentie - top segmente acolo
$r2m = Invoke-Sql -Sql @"
set pagesize 0 linesize 100 trimspool on feedback off heading off
with ts_free as (
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
), agg as (
select f.tablespace_name, sum(f.maxbytes) max_bytes, sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
from dba_data_files f
group by f.tablespace_name
)
select 'TS_ATENTIE|' || a.tablespace_name
from agg a, ts_free tf
where a.tablespace_name = tf.tablespace_name(+)
and a.max_bytes > 0
and (nvl(tf.free_bytes,0) + a.creste_bytes) <
greatest($PragTsMb * 1048576, a.max_bytes * $PragTsPct / 100);
exit
"@
$tsProblema = @($r2m.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('TS_ATENTIE|') } | ForEach-Object { $_.Substring(11) } | Where-Object { $_ -match '^[A-Z0-9_]+$' })
if ($tsProblema.Count -gt 0) {
$sbSeg = New-Object System.Text.StringBuilder
[void]$sbSeg.AppendLine('set pagesize 0 linesize 250 trimspool on feedback off heading off')
foreach ($ts in $tsProblema) {
[void]$sbSeg.AppendLine("select 'Tablespace $ts - top $Top segmente:' from dual;")
[void]$sbSeg.AppendLine(@"
select rpad(owner,20) || rpad(segment_name,35) || rpad(segment_type,18) || round(bytes/1048576) || ' MB'
from (select owner, segment_name, segment_type, bytes from dba_segments where tablespace_name = '$ts' order by bytes desc)
where rownum <= $Top;
"@)
if ($ts -eq 'SYSTEM') {
[void]$sbSeg.AppendLine("select 'NOTA: privilegiile ANY (ex. DROP ANY TABLE/TRUNCATE ANY TABLE) nu se aplica pe obiecte din schema SYS cand O7_DICTIONARY_ACCESSIBILITY=FALSE - curatarea unui tabel din SYS cere conectare SYSDBA, nu contafin_oracle.' from dual;")
}
}
[void]$sbSeg.AppendLine('exit')
$r2s = Invoke-Sql -Sql $sbSeg.ToString()
Write-Output ''
Write-Output ('--- Top segmente pe tablespace-urile marcate ATENTIE (' + ($tsProblema -join ', ') + ') ---')
Write-Output $r2s.Text
}
# MAX_PDB_STORAGE - doar daca CDB si -SysPassword dat
Write-Output ''
Write-Output '===== 2b. MAX_PDB_STORAGE (CDB$ROOT) ====='
if (-not $ver12plus) {
Write-Output 'Sarit - baza sub versiunea 12c, nu are CDB/PDB.'
} elseif (-not $ConnStrSys) {
Write-Output 'Sarit - necesita -SysPassword (conectare SYSDBA + alter session set container=CDB$ROOT; contafin_oracle nu vede limita din PDB).'
} else {
$rPdb = Invoke-SqlSys -Sql @"
set serveroutput on size 1000000
set feedback off
begin
execute immediate 'alter session set container = CDB`$ROOT';
for r in (select con_id, name, open_mode from v`$pdbs order by con_id) loop
dbms_output.put_line('PDB con_id=' || r.con_id || ' name=' || r.name || ' open_mode=' || r.open_mode);
end loop;
begin
for r in (select p.con_id, p.name, round(nvl(c.max_size,0)/1048576) mb_max
from v`$pdbs p, v`$containers c
where p.con_id = c.con_id(+)
order by p.con_id) loop
dbms_output.put_line(' ' || r.name || ' MAX_PDB_STORAGE(MB)=' || case when r.mb_max = 0 then 'nelimitat/necunoscut' else to_char(r.mb_max) end);
end loop;
exception when others then
dbms_output.put_line('MAX_PDB_STORAGE: interogare v`$containers.max_size esuata (' || sqlerrm || ').');
dbms_output.put_line('Verifica manual: ALTER PLUGGABLE DATABASE <pdb> STORAGE; sau interogheaza dba_pdbs/v`$pdbs direct pe server.');
end;
exception
when others then
if sqlcode = -1031 then
dbms_output.put_line('EROARE la comutarea pe CDB`$ROOT: ORA-01031 (privilegii insuficiente). Aliasul TNS dat tinteste probabil un serviciu de PDB (ex. XEPDB1), nu serviciul radacina al CDB - de pe un serviciu de PDB, SYSDBA nu poate comuta pe CDB`$ROOT. Necesita un alias/serviciu separat care tinteste radacina (de obicei numele instantei, nu al PDB-ului).');
else
dbms_output.put_line('EROARE la comutarea pe CDB`$ROOT: ' || sqlerrm);
end if;
end;
/
exit
"@
Write-Output $rPdb.Text
}
# ---------- 2c. Plafonul de date al editiei XE ----------
# limita editiei, independenta de maxbytes-ul tablespace-urilor: extinderea poate fi refuzata cu
# ORA-12952 desi tablespace-ul mai are loc
Write-Output ''
Write-Output '===== 2c. PLAFON DE DATE XE ====='
$xeCritic = $false
if ($r1.Text -notmatch 'Express Edition') {
Write-Output 'Sarit - editia nu e Express Edition, nu exista plafon de date pe editie.'
} else {
$xePlafonGb = if ($verMajor -le 10) { 4 } elseif ($verMajor -eq 11) { 11 } else { 12 }
$rXe = Invoke-Sql -Sql @"
set pagesize 0 linesize 200 trimspool on feedback off heading off
select 'XEFOLOSIT|' || round(nvl(sum(f.bytes),0)/1048576, 2)
from dba_data_files f
where f.tablespace_name not in ('SYSTEM','SYSAUX')
and f.tablespace_name not in (select t.tablespace_name from dba_tablespaces t
where t.contents in ('UNDO','TEMPORARY'));
exit
"@
$xeFolositMb = $null
foreach ($line in ($rXe.Text -split "`r?`n")) {
if ($line.Trim() -match '^XEFOLOSIT\|([\d.]+)$') { $xeFolositMb = [double]$Matches[1] }
}
if ($null -eq $xeFolositMb) {
Write-Output 'Nu am putut masura datele de utilizator (dba_data_files) - vezi erorile de mai sus.'
Write-Output $rXe.Text
} else {
$xePlafonMb = $xePlafonGb * 1024
$xeLiberMb = $xePlafonMb - $xeFolositMb
$xePragMb = [math]::Max($PragTsMb, $xePlafonMb * $PragTsPct / 100)
$xeCritic = ($xeLiberMb -lt $xePragMb)
Write-Output ('Editie Express, plafon de date ' + $xePlafonGb + ' GB (masurat pe dba_data_files, fara SYSTEM/SYSAUX/UNDO/TEMP).')
Write-Output (' folosit = ' + [math]::Round($xeFolositMb/1024, 2) + ' GB liber pana la plafon = ' + [math]::Round($xeLiberMb, 0) + ' MB')
if ($xeCritic) {
Write-Output ('[ATENTIE] sub pragul de ' + [math]::Round($xePragMb, 0) + ' MB. Cand plafonul e atins, baza refuza extinderea cu ORA-12952 si nu se mai poate face nimic din baza - elibereaza date sau treci pe alta editie.')
}
}
}
# ---------- 3. Audit Oracle ----------
$r3 = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'AUD`$ (contafin_oracle): ' || count(*) from sys.aud`$;
select 'FGA_LOG`$ (contafin_oracle): ' || count(*) from sys.fga_log`$;
select 'audit_file_dest = ' || value from v`$parameter where name = 'audit_file_dest';
select 'audit_trail = ' || value from v`$parameter where name = 'audit_trail';
exit
"@
Show-Section -Title '3. AUDIT ORACLE (tabele, din contafin_oracle)' -Text $r3.Text
if ($ver12plus) {
$r3u = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'unified_audit_trail: ' || count(*) || ' randuri' from unified_audit_trail;
exit
"@
Show-Section -Title '3b. UNIFIED AUDIT TRAIL' -Text $r3u.Text
} else {
Write-Output ''
Write-Output '===== 3b. UNIFIED AUDIT TRAIL ====='
Write-Output 'Sarit - baza sub versiunea 12c, nu are unified auditing.'
}
if (-not $ConnStrSys) {
Write-Output ''
Write-Output '===== 3c. AUDIT INTERN (SYSDBA) ====='
Write-Output 'Sarit - necesita -SysPassword. sys.aud$/fga_log$ sunt obiecte SYS: privilegiile ANY nu se aplica pe ele (O7_DICTIONARY_ACCESSIBILITY=FALSE), deci contafin_oracle poate primi ORA-01031 mai sus chiar daca are rol DBA.'
} else {
$r3s = Invoke-SqlSys -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'AUD`$ (sysdba): ' || count(*) from sys.aud`$;
select 'FGA_LOG`$ (sysdba): ' || count(*) from sys.fga_log`$;
exit
"@
Show-Section -Title '3c. AUDIT INTERN (rezultat garantat, conectat SYSDBA)' -Text $r3s.Text
}
Write-Output 'Fisierele fizice .aud din audit_file_dest (numar + MB reale): vezi sectiunea 6 (-Disc).'
Write-Output 'Curatare (doar sugestie, niciodata executata automat): oprire viitoare = alter system set audit_trail=NONE scope=spfile (cere restart instanta); golire sys.aud$/fga_log$ = DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL sau delete direct, ambele SYSDBA; fisierele .aud se pot sterge direct de pe disc (independente de dictionar).'
# ---------- 4. Alert log / trace / ADR ----------
Write-Output ''
Write-Output '===== 4. ALERT LOG / TRACE / ADR (cai) ====='
$diagPaths = @()
if ($ver11plus) {
$r4 = Invoke-Sql -Sql @"
set pagesize 0 linesize 300 trimspool on feedback off heading off
select 'DIAG|' || name || '|' || value from v`$diag_info where name in ('Diag Trace','Diag Alert','Diag Incident','Diag Cdump');
exit
"@
Write-Output $r4.Text
$diagPaths = @($r4.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('DIAG|') } | ForEach-Object {
$parts = $_.Substring(5) -split '\|', 2
[PSCustomObject]@{ Label = ('DIAG_' + ($parts[0] -replace '[^A-Za-z0-9]','_')).ToUpper(); Path = $parts[1] }
})
} else {
$r4 = Invoke-Sql -Sql @"
set pagesize 0 linesize 300 trimspool on feedback off heading off
select 'DIAG|BACKGROUND|' || value from v`$parameter where name = 'background_dump_dest';
select 'DIAG|USER|' || value from v`$parameter where name = 'user_dump_dest';
select 'DIAG|CORE|' || value from v`$parameter where name = 'core_dump_dest';
exit
"@
Write-Output '(baza sub 11g - fara ADR/diagnostic_dest, foloseste background_dump_dest/user_dump_dest/core_dump_dest)'
Write-Output $r4.Text
$diagPaths = @($r4.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('DIAG|') } | ForEach-Object {
$parts = $_.Substring(5) -split '\|', 2
[PSCustomObject]@{ Label = ('DIAG_' + $parts[0]); Path = $parts[1] }
})
}
Write-Output 'Marimea reala a acestor foldere (alert log, trace, incident, cdump): vezi sectiunea 6 (-Disc) - SQL nu vede sistemul de fisiere.'
Write-Output 'Curatare (doar sugestie): adrci exec="set homepath <path>; purge -age <minute> -type ALERT/INCIDENT/TRACE" rulat ca proces extern (prin ExecuteScriptOS) - purjeaza doar diagnostic vechi, nu afecteaza baza.'
# ---------- 5. Archivelog / Fast Recovery Area ----------
$r5 = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'log_mode = ' || log_mode from v`$database;
select 'db_recovery_file_dest = ' || nvl(value,'(neconfigurat)') from v`$parameter where name = 'db_recovery_file_dest';
select 'db_recovery_file_dest_size(MB) = ' || round(to_number(value)/1048576) from v`$parameter where name = 'db_recovery_file_dest_size';
exit
"@
Show-Section -Title '5. ARCHIVELOG / FAST RECOVERY AREA' -Text $r5.Text
$r5b = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column name format a60
select round(space_limit/1048576) mb_limita, round(space_used/1048576) mb_folosit,
round(space_reclaimable/1048576) mb_recuperabil, number_of_files
from v`$recovery_file_dest;
column file_type format a20
select file_type, percent_space_used, percent_space_reclaimable, number_of_files
from v`$flash_recovery_area_usage
order by percent_space_used desc;
exit
"@
Show-Section -Title '5b. FRA - utilizare pe tip de fisier' -Text $r5b.Text
# linie separata, fara ambiguitate de coloane, doar pentru pragul de alarma (nu pentru afisare)
$r5c = Invoke-Sql -Sql @"
set pagesize 0 linesize 100 trimspool on feedback off heading off
select 'FRAPCT|' || round(space_used*100/nullif(space_limit,0),1) from v`$recovery_file_dest;
exit
"@
$fraCritic = $false
foreach ($line in ($r5c.Text -split "`r?`n")) {
if ($line.Trim() -match '^FRAPCT\|([\d.]+)$') {
if ([double]$Matches[1] -ge $PragFraPct) { $fraCritic = $true }
}
}
if ($fraCritic) {
Write-Output ''
Write-Output ('[ATENTIE] FRA peste ' + $PragFraPct + '% din spatiul alocat. Daca log_mode=ARCHIVELOG si FRA se umple complet, baza se blocheaza pe scriere (ORA-19809/ORA-00257).')
Write-Output 'Ce se poate face fara backup: marire db_recovery_file_dest_size (daca discul are loc) - imediat, fara pierdere.'
Write-Output 'Ce NU se face fara backup real: sterge archivelog-uri neaplicate-la-backup ar rupe recuperarea (RMAN DELETE ARCHIVELOG ... BACKED UP 1 TIMES TO DISK, doar daca exista backup real configurat).'
}
# ---------- 6. Spatiu pe discurile serverului (optional, scrie un .ps1 temporar in DMPDIR) ----------
Write-Output ''
Write-Output '===== 6. SPATIU DISC (server) ====='
if (-not $Disc) {
Write-Output 'Sarit implicit - ruleaza cu -Disc pentru spatiul liber pe discurile fizice si marimea reala a folderelor oradata/audit/diag/DMPDIR/FRA.'
Write-Output 'Este singura parte a scriptului care NU e strict read-only: scrie un .ps1 temporar in DMPDIR (prin sys.ExecuteScriptOS) si il sterge la final.'
} else {
$rFolders = Invoke-Sql -Sql @"
set pagesize 0 linesize 300 trimspool on feedback off heading off
select 'ORADATA|' || substr(file_name,1,instr(file_name,'\',-1)-1)
from (select distinct substr(file_name,1,instr(file_name,'\',-1)-1) file_name from dba_data_files);
select 'AUDITDIR|' || value from v`$parameter where name = 'audit_file_dest';
select 'DMPDIR|' || directory_path from all_directories where directory_name = 'DMPDIR';
select 'FRADIR|' || value from v`$parameter where name = 'db_recovery_file_dest' and value is not null;
exit
"@
$folders = New-Object System.Collections.ArrayList
$seen = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase)
foreach ($line in ($rFolders.Text -split "`r?`n")) {
$line = $line.Trim()
foreach ($prefix in @('ORADATA','AUDITDIR','DMPDIR','FRADIR')) {
if ($line.StartsWith($prefix + '|')) {
$p = $line.Substring($prefix.Length + 1).Trim()
if ($p -and $seen.Add($prefix + '::' + $p.ToUpper())) {
[void]$folders.Add([PSCustomObject]@{ Label = $prefix; Path = $p })
}
}
}
}
foreach ($dp in $diagPaths) {
if ($dp.Path -and $seen.Add($dp.Label + '::' + $dp.Path.ToUpper())) {
[void]$folders.Add($dp)
}
}
$psTemplate = @'
$dOut = 'C:\DMPDIR\diag_spatiu_out.txt'
Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
$pct = 0
if ($_.Size -gt 0) { $pct = [math]::Round($_.FreeSpace/$_.Size*100,1) }
"DISC {0} {1} {2} {3}" -f $_.DeviceID, [math]::Round($_.Size/1GB,2), [math]::Round($_.FreeSpace/1GB,2), $pct
} | Out-File -Encoding ascii $dOut
__FOLDERS__
'@
$folderLines = foreach ($f in $folders) {
$escaped = $f.Path.Replace("'", "''")
$lbl = $f.Label
@"
if (Test-Path -LiteralPath '$escaped') {
`$items = Get-ChildItem -LiteralPath '$escaped' -Recurse -File -ErrorAction SilentlyContinue
`$cnt = @(`$items).Count
`$sum = (`$items | Measure-Object -Property Length -Sum).Sum
if (-not `$sum) { `$sum = 0 }
"FOLDER $lbl|$escaped|{0}|{1}" -f `$cnt, [math]::Round(`$sum/1MB,1) | Out-File -Encoding ascii -Append `$dOut
`$aud = @(`$items | Where-Object { `$_.Extension -ieq '.aud' })
if (`$aud.Count -gt 0) {
`$audSum = (`$aud | Measure-Object -Property Length -Sum).Sum
"AUDFILES $lbl|{0}|{1}" -f `$aud.Count, [math]::Round(`$audSum/1MB,1) | Out-File -Encoding ascii -Append `$dOut
}
} else {
"FOLDER $lbl|$escaped|MISSING" | Out-File -Encoding ascii -Append `$dOut
}
"@
}
$psScript = $psTemplate.Replace('__FOLDERS__', ([string]::Join("`n", $folderLines)))
$psScriptSql = $psScript.Replace("'", "''")
$rLaunch = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
lcPS server_info.value%type;
begin
select value into lcPS from server_info where upper(name) = 'POWERSHELLPATH';
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu_out.txt'); exception when others then null; end;
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
pack_utils_file.clob2fileX('$psScriptSql', 'DMPDIR', 'diag_spatiu.ps1');
sys.ExecuteScriptOS(lcPS, 'C:\DMPDIR\diag_spatiu.ps1');
dbms_output.put_line('Lansat pe server (' || lcPS || '), astept rezultatul...');
exception when others then
dbms_output.put_line('EROARE la lansare: ' || sqlerrm);
end;
/
exit
"@
Write-Output $rLaunch.Text
if ($rLaunch.Text -notmatch 'EROARE la lansare') {
$gata = Wait-RemoteFile -Directory 'DMPDIR' -FileName 'diag_spatiu_out.txt' -TimeoutSec 60
if (-not $gata) {
Write-Output 'EROARE: rezultatul nu a aparut in 60s. Posibile cauze: server_info.POWERSHELLPATH gresit, politica de executie PowerShell blocheaza scriptul, sys.ExecuteScriptOS nu are drept de executie, sau serverul nu e Windows (DMPDIR pe cale Linux - mecanismul ExecuteScriptOS e specific Windows/PowerShell). Verifica manual C:\DMPDIR\diag_spatiu.ps1 pe server.'
Invoke-Sql -Sql @"
set feedback off
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
/
exit
"@ | Out-Null
Write-Output 'Curatare: am incercat oricum stergerea diag_spatiu.ps1 din DMPDIR (best-effort, fara confirmare de succes daca serverul nu a raspuns).'
} else {
$rRead = Invoke-Sql -Sql @"
set serveroutput on size 1000000
set feedback off
declare
lf utl_file.file_type;
lc_line varchar2(32767);
begin
lf := utl_file.fopen('DMPDIR','diag_spatiu_out.txt','R',32767);
begin
loop
utl_file.get_line(lf, lc_line, 32767);
dbms_output.put_line(lc_line);
end loop;
exception when no_data_found then null;
end;
utl_file.fclose(lf);
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu_out.txt'); exception when others then null; end;
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
exception when others then
dbms_output.put_line('EROARE citire: ' || sqlerrm);
end;
/
exit
"@
$discLines = @()
$folderLinesOut = @()
foreach ($line in ($rRead.Text -split "`r?`n")) {
if ($line -match '^DISC\s+(\S+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)') {
$discLines += (' disc {0}: total {1} GB, liber {2} GB ({3}%)' -f $Matches[1], $Matches[2], $Matches[3], $Matches[4])
} elseif ($line -match '^FOLDER\s+(\S+)\|(.+)\|MISSING\s*$') {
$folderLinesOut += (' {0} ({1}): nu exista pe server' -f $Matches[1], $Matches[2])
} elseif ($line -match '^FOLDER\s+(\S+)\|(.+)\|(\d+)\|([\d.]+)\s*$') {
$folderLinesOut += (' {0} ({1}): {2} fisiere, {3} MB' -f $Matches[1], $Matches[2], $Matches[3], $Matches[4])
} elseif ($line -match '^AUDFILES\s+(\S+)\|(\d+)\|([\d.]+)\s*$') {
$folderLinesOut += (' din care .aud: {0} fisiere, {1} MB' -f $Matches[2], $Matches[3])
} elseif ($line -match '\S') {
$discLines += (' ' + $line)
}
}
Write-Output 'Discuri fixe:'
Write-Output ($discLines -join "`n")
Write-Output 'Foldere (oradata / audit / diag / DMPDIR / FRA):'
Write-Output ($folderLinesOut -join "`n")
}
}
}
# ---------- 7. Alti mancatori de spatiu ----------
Write-Output ''
Write-Output '===== 7. ALTI MANCATORI DE SPATIU ====='
$r7a = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'user_recyclebin (schema ' || sys_context('userenv','session_user') || '): ' || count(*) || ' obiecte, ' ||
round(sum(space)*8192/1048576) || ' MB (aprox, space in blocuri)'
from user_recyclebin;
exit
"@
Show-Section -Title '7a. RECYCLEBIN (schema conectata)' -Text $r7a.Text
if ($ConnStrSys) {
$r7as = Invoke-SqlSys -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'dba_recyclebin (toata baza): ' || count(*) || ' obiecte, ' ||
round(sum(space)*8192/1048576) || ' MB (aprox)'
from dba_recyclebin;
exit
"@
Show-Section -Title '7a-bis. RECYCLEBIN (toata baza, SYSDBA)' -Text $r7as.Text
} else {
Write-Output 'RECYCLEBIN la nivel de baza (dba_recyclebin): sarit - necesita -SysPassword.'
}
$r7b = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'UNDO tablespace = ' || value from v`$parameter where name = 'undo_tablespace';
select 'UNDO alocat(MB) = ' || round(sum(bytes)/1048576)
from dba_data_files
where tablespace_name = (select value from v`$parameter where name = 'undo_tablespace');
select 'tranzactii active = ' || count(*) from v`$transaction;
exit
"@
Show-Section -Title '7b. UNDO' -Text ($r7b.Text + "`nResize UNDO poate da ORA-03297 daca extenturile nu au expirat inca - de incercat doar dupa ce activitatea scade, niciodata automat.")
$r7c = Invoke-Sql -Sql @"
set pagesize 0 linesize 250 trimspool on feedback off heading off
select 'dba_tab_stats_history: ' || count(*) || ' randuri, cel mai vechi = ' || to_char(min(stats_update_time),'yyyy-mm-dd')
from dba_tab_stats_history;
select 'dba_scheduler_job_run_details: ' || count(*) || ' randuri, cel mai vechi = ' || to_char(min(log_date),'yyyy-mm-dd')
from dba_scheduler_job_run_details;
exit
"@
Show-Section -Title '7c. ISTORIC STATISTICI / SCHEDULER' -Text ($r7c.Text + "`nCuratare (doar sugestie): DBMS_STATS.PURGE_STATS(<data>); DBMS_SCHEDULER.PURGE_LOG(log_history => <zile>).")
$r7d = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column tablespace_name format a20
select tablespace_name, round(sum(bytes)/1048576) mb_alocat from dba_temp_files group by tablespace_name;
column tablespace_name format a20
select tablespace_name, round(sum(bytes_used)/1048576) mb_folosit, round(sum(bytes_free)/1048576) mb_liber
from v`$temp_space_header group by tablespace_name;
exit
"@
Show-Section -Title '7d. TEMP (alocat vs folosit)' -Text $r7d.Text
$r7e = Invoke-Sql -Sql @"
set pagesize 100 linesize 250 trimspool on feedback off
column owner format a20
column segment_name format a35
column segment_type format a18
column tablespace_name format a15
select * from (
select owner, segment_name, segment_type, tablespace_name, round(bytes/1048576) mb
from dba_segments
order by bytes desc
) where rownum <= $Top;
exit
"@
Show-Section -Title ('7e. TOP ' + $Top + ' SEGMENTE DIN TOATA BAZA (generic, fara nume hardcodate)') -Text $r7e.Text
# ---------- 8. Verdict ----------
Write-Output ''
Write-Output '===== 8. VERDICT ====='
if ($tsProblema.Count -gt 0) {
Write-Output ('Tablespace-uri aproape fara loc: ' + ($tsProblema -join ', ') + '. Vezi sectiunea 2 pentru top segmente acolo - candidatii de curatare/crestere maxbytes sunt acolo.')
} else {
Write-Output ('Niciun tablespace sub pragul de atentie (' + $PragTsMb + ' MB sau ' + $PragTsPct + '% din maxim, sectiunea 2).')
}
if ($xeCritic) {
Write-Output ('Plafonul de date al editiei XE e aproape atins (sectiunea 2c) - la ORA-12952 nu se mai poate face nimic din baza. Prioritate maxima: eliberare de date sau trecere pe alta editie.')
}
if ($fraCritic) {
Write-Output ('FRA peste ' + $PragFraPct + '% din spatiul alocat (sectiunea 5b) - risc de blocaj pe scriere daca log_mode=ARCHIVELOG. Prioritate: verifica arhivarea/backup-ul inainte sa se umple complet.')
}
Write-Output 'Ordine tipica de curatare (cea mai sigura primul): fisiere .aud vechi din audit_file_dest (sters direct pe disc, fara privilegii DB) -> adrci purge pe alert/trace/incident vechi -> istoric statistici/scheduler (DBMS_STATS.PURGE_STATS / DBMS_SCHEDULER.PURGE_LOG) -> recyclebin -> resize UNDO dupa ce scade activitatea -> curatare SYS.aud$/fga_log$ sau alte tabele interne (cere SYSDBA) -> ca ultima solutie, recreare PDB (export/import).'
if (-not $ConnStrSys) {
Write-Output 'Fara -SysPassword: sectiunile 2b (MAX_PDB_STORAGE), 3c (audit intern sys.aud$/fga_log$) si 7a-bis (dba_recyclebin) au fost sarite - ruleaza cu -SysPassword daca ai parola SYS a acestui client pentru imaginea completa.'
}
if (-not $Disc) {
Write-Output 'Fara -Disc: marimile reale pe disc (audit_file_dest, alert/trace/ADR, oradata, FRA, discuri fizice) nu au fost masurate - ruleaza cu -Disc pentru ele.'
}
Remove-TempDir
exit 0

406
utile/livrare.ps1 Normal file
View File

@@ -0,0 +1,406 @@
<#
.SYNOPSIS
Lantul complet de dinaintea si din timpul unui commit: sync text VFP, curatenie,
verificari de livrare, stare repo-uri, commit + push.
.DESCRIPTION
1. Sincronizare, aleasa dupa starea arborelui (git status --porcelain) in AMBELE repo-uri:
- tree curat (inceput de sesiune, nimic necomis) -> COMUN\scripts\roa_sync.ps1 -ProjectRoot
<root>: svn update (inclusiv externalul COMUN) + git_sync (texte .??2) + commit
"sync SVN rN" + reconciliere cu origin. Prinde aici non-fast-forward-ul cu origin (nu abia
la push, pasul 5). Daca roa_sync.ps1 lipseste, fallback pe git_sync.ps1 (doar text, fara
SVN), cu avertisment.
- tree murdar (cazul normal la livrare, cu modificari necomise pe disc) -> DOAR git_sync.ps1:
roa_sync ar face `git add -A` + commit "sync SVN" pe main peste munca in curs, inglobind-o
intr-un commit etichetat gresit (fluxul_svn_git.md: "sync pe main doar din stare curata").
Iesire nenula -> opreste tot. Se sare cu -FaraSync; doar partea SVN se sare cu -FaraSvn
(roa_sync -GitOnly, aplicabil doar cand tree-ul e curat). NU ruleaza nimic in -DryRun (roa_sync
face svn update real si poate comite/impinge) - doar anunta ce s-ar alege si de ce.
2. curatenie.ps1 -ProjectRoot <root> - sterge artefactele de lucru (neurmarite de git).
3. Verificari de livrare (avertismente, neblocante): changelog neatins, fisiere de runda
ramase, binare VFP fara perechea text in modificari, fisiere ce urmeaza sa intre in git
dar sunt necunoscute SVN-ului ("?" la svn status - munca reala trebuie sa treaca intai
prin SVN, vezi fluxul_svn_git.md).
4. Stare repo proiect si repo COMUN (separat, partajat de toate aplicatiile ROA): git fetch +
compara HEAD cu origin/<ramura> (semnaleaza daca ramura locala e in urma), apoi
git status --short + git diff --stat.
5. Commit + push. Proiectul implicit; COMUN doar cu -Comun explicit (altfel doar raportat).
Push respins non-fast-forward (frecvent pe COMUN, comun tuturor aplicatiilor ROA): fetch +
rebase peste origin + reincercare o singura data. Conflicte la rebase -> rebase --abort,
mesaj clar, exit nenul (nu lasa repo-ul in rebase in curs). Niciodata push --force
(nici --force-with-lease). Comite pe ramura curenta, nu creeaza alta.
6. -DryRun: ruleaza pasii 2-4 (curatenia in -DryRun; pasul 1 doar anuntat, nu executat) si se
opreste inainte de commit.
.PARAMETER ProjectRoot
Radacina proiectului (implicit dedus, ca la curatenie.ps1 - doua nivele deasupra acestui script).
.PARAMETER Mesaj
Mesajul de commit. Obligatoriu la o rulare reala (fara -DryRun).
.PARAMETER Comun
Comite si impinge si repo-ul COMUN (implicit doar proiectul).
.PARAMETER FaraSync
Sare peste tot pasul 1 (roa_sync/git_sync) - util cand nu s-a atins niciun binar VFP si nici
SVN-ul nu trebuie adus la zi.
.PARAMETER FaraSvn
Cand tree-ul e curat (altfel se ruleaza oricum doar git_sync): ruleaza roa_sync.ps1 -GitOnly,
fara svn update si fara regenerarea textelor, doar commit sync + reconciliere origin +
inchidere branch-uri claude/*. Util cand SVN nu e disponibil sau nu s-a atins nimic in SVN.
Ignorat daca roa_sync.ps1 lipseste (fallback-ul pe git_sync.ps1 nu are oricum pas SVN).
.PARAMETER FaraPush
Doar commit local, fara push.
.PARAMETER DryRun
Nu modifica nimic - arata ce s-ar comite si unde. Pasul 1 nu se executa (roa_sync ar face svn
update real si poate comite/impinge) - doar anunta ce s-ar alege (roa_sync sau git_sync) si de ce.
.EXAMPLE
powershell -File COMUN\utile\livrare.ps1 -DryRun
.EXAMPLE
powershell -File COMUN\utile\livrare.ps1 -Mesaj "achizitie import: rebindare ControlSource"
.EXAMPLE
powershell -File COMUN\utile\livrare.ps1 -Mesaj "conventie noua in COMUN" -Comun
.EXAMPLE
powershell -File COMUN\utile\livrare.ps1 -Mesaj "doar .prg, fara binare" -FaraSync -FaraPush
.EXAMPLE
powershell -File COMUN\utile\livrare.ps1 -Mesaj "SVN indisponibil acum" -FaraSvn
#>
param(
[string]$ProjectRoot,
[string]$Mesaj,
[switch]$Comun,
[switch]$FaraSync,
[switch]$FaraSvn,
[switch]$FaraPush,
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
if (-not $ProjectRoot) { $ProjectRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent }
$comunPath = Join-Path $ProjectRoot 'COMUN'
$roaSync = Join-Path $ProjectRoot 'COMUN\scripts\roa_sync.ps1'
$gitSync = 'D:\ROA\UTIL\foxbin2prg\git_sync.ps1'
$curatenie = Join-Path $PSScriptRoot 'curatenie.ps1'
if (-not $DryRun -and -not $Mesaj) {
Write-Output 'livrare: -Mesaj este obligatoriu (sau ruleaza cu -DryRun)'
exit 1
}
Write-Output ('livrare: ProjectRoot=' + $ProjectRoot)
# --- tree curat in ambele repo-uri? roa_sync e unealta de inceput de sesiune (stare curata),
# nu de livrare cu modificari necomise pe disc (fluxul_svn_git.md) ---
function Test-TreeCurat($repoPath) {
if (-not (Test-Path (Join-Path $repoPath '.git'))) { return $true }
return (@(& git -C $repoPath status --porcelain).Count -eq 0)
}
$treeCurat = (Test-TreeCurat $ProjectRoot) -and (Test-TreeCurat $comunPath)
function Ruleaza-GitSync {
if (-not (Test-Path $gitSync)) {
Write-Output ('[1] git_sync: NU s-a gasit ' + $gitSync)
exit 2
}
& powershell -ExecutionPolicy Bypass -File $gitSync -ProjectRoot $ProjectRoot
if ($LASTEXITCODE -ne 0) {
Write-Output ('[1] git_sync: ESUAT (cod ' + $LASTEXITCODE + ') - opresc tot, nu se comite')
exit 2
}
Write-Output '[1] git_sync: OK'
}
# --- pas 1: tree curat -> roa_sync (fallback git_sync daca lipseste); tree murdar -> doar git_sync ---
if ($FaraSync) {
Write-Output '[1] sincronizare: sarita (-FaraSync)'
} elseif ($DryRun) {
# roa_sync face svn update real si poate comite/impinge (chiar si cu -GitOnly) - nu ruleaza in -DryRun.
if (-not $treeCurat) {
Write-Output ('[1] sincronizare: sarita (-DryRun) - modificari necomise, ar rula doar ' + $gitSync + ' (roa_sync ar ingloba munca in curs intr-un commit "sync SVN")')
} elseif (Test-Path $roaSync) {
$variantaGO = if ($FaraSvn) { ' -GitOnly' } else { '' }
Write-Output ('[1] sincronizare: sarita (-DryRun) - tree curat, ar rula ' + $roaSync + $variantaGO)
} else {
Write-Output ('[1] sincronizare: sarita (-DryRun) - tree curat, roa_sync.ps1 lipseste, ar rula fallback ' + $gitSync)
}
} elseif (-not $treeCurat) {
Write-Output '[1] sincronizare: modificari necomise -> rulez doar git_sync (roa_sync ar ingloba munca in curs intr-un commit "sync SVN")'
Ruleaza-GitSync
} elseif (Test-Path $roaSync) {
$rsArgs = @('-ProjectRoot', $ProjectRoot)
if ($FaraSvn) { $rsArgs += '-GitOnly' }
& powershell -ExecutionPolicy Bypass -File $roaSync @rsArgs
if ($LASTEXITCODE -ne 0) {
Write-Output ('[1] roa_sync: ESUAT (cod ' + $LASTEXITCODE + ') - opresc tot, nu se comite')
exit 2
}
Write-Output '[1] roa_sync: OK'
} else {
Write-Output ('[1] roa_sync: NU s-a gasit (' + $roaSync + ') - fallback pe git_sync.ps1')
Ruleaza-GitSync
}
# --- pas 2: curatenie ---
$curArgs = @('-ProjectRoot', $ProjectRoot)
if ($DryRun) { $curArgs += '-DryRun' }
Write-Output '[2] curatenie:'
& powershell -ExecutionPolicy Bypass -File $curatenie @curArgs | ForEach-Object { Write-Output (' ' + $_) }
if ($LASTEXITCODE -ne 0) {
Write-Output ('[2] curatenie: cod neasteptat ' + $LASTEXITCODE + ' (continui)')
}
# --- fisiere modificate per repo (dupa curatenie) ---
function Get-ChangedFiles($repoPath) {
if (-not (Test-Path (Join-Path $repoPath '.git'))) { return @() }
$rezultat = New-Object System.Collections.ArrayList
foreach ($linie in (& git -C $repoPath status --porcelain --untracked-files=all)) {
if (-not $linie) { continue }
$cale = $linie.Substring(3)
if ($cale -match ' -> ') { $cale = ($cale -split ' -> ')[1] }
$cale = $cale.Trim('"')
[void]$rezultat.Add($cale)
}
return $rezultat
}
$modifProiect = Get-ChangedFiles $ProjectRoot
$modifComun = Get-ChangedFiles $comunPath
# --- pas 3: verificari de livrare (avertismente, neblocante) ---
$avertismente = New-Object System.Collections.ArrayList
# fisiere din $modif care apar cu "?" (necunoscut) la svn status - munca reala trebuie sa treaca
# intai prin SVN (fluxul_svn_git.md). Fara svn sau folder ce nu e working copy -> tacere.
function Get-SvnNeurmarite($repoPath, $modif) {
if ($modif.Count -eq 0) { return @() }
if (-not (Get-Command svn -ErrorAction SilentlyContinue)) { return @() }
$ErrorActionPreference = 'Continue'
$iesire = & svn status $repoPath 2>$null
if ($LASTEXITCODE -ne 0) { return @() }
$necunoscute = New-Object System.Collections.Generic.HashSet[string] ([StringComparer]::OrdinalIgnoreCase)
foreach ($linie in $iesire) {
if ($linie -match '^\?\s+(.+)$') {
$cale = $Matches[1].Trim()
if ($cale.StartsWith($repoPath, [System.StringComparison]::OrdinalIgnoreCase)) {
$cale = $cale.Substring($repoPath.Length).TrimStart('\', '/')
}
[void]$necunoscute.Add(($cale -replace '\\', '/'))
}
}
return @($modif | Where-Object { $necunoscute.Contains($_) })
}
function Verifica-Livrare($modif, $repoPath, $eticheta) {
$codExt = @('.prg', '.vc2', '.sc2', '.ps1')
$areCod = $modif | Where-Object { $ext = [System.IO.Path]::GetExtension($_).ToLower(); $codExt -contains $ext }
$areChangelog = $modif | Where-Object { $_ -match 'changelog.*\.txt$' }
if ($areCod -and -not $areChangelog -and $eticheta -eq 'proiect') {
[void]$script:avertismente.Add('changelog neatins (' + $eticheta + ') desi s-a modificat cod')
}
foreach ($f in $modif) {
$ext = [System.IO.Path]::GetExtension($f).ToLower()
if ($ext -eq '.vcx') { $pereche = [System.IO.Path]::ChangeExtension($f, '.vc2') }
elseif ($ext -eq '.scx') { $pereche = [System.IO.Path]::ChangeExtension($f, '.sc2') }
else { continue }
if ($modif -notcontains $pereche) {
[void]$script:avertismente.Add('binar fara text sincronizat in modificari (' + $eticheta + '): ' + $f)
}
}
$docsPath = Join-Path $repoPath 'docs'
if (Test-Path $docsPath) {
$ramase = Get-ChildItem -Path $docsPath -Include @('propuneri_*.md', 'handoff*.md', 'runda*.md') -Recurse -ErrorAction SilentlyContinue
foreach ($r in $ramase) {
[void]$script:avertismente.Add('fisier de runda ramas (' + $eticheta + '): docs\' + $r.Name)
}
}
$neurmarite = Get-SvnNeurmarite $repoPath $modif
foreach ($f in $neurmarite) {
[void]$script:avertismente.Add('fisier necunoscut SVN (' + $eticheta + '), fa svn add + svn commit intai: ' + $f)
}
}
Verifica-Livrare $modifProiect $ProjectRoot 'proiect'
Verifica-Livrare $modifComun $comunPath 'COMUN'
Write-Output '[3] verificari de livrare:'
if ($avertismente.Count -eq 0) {
Write-Output ' fara avertismente'
} else {
foreach ($a in $avertismente) { Write-Output (' ATENTIE: ' + $a) }
}
# --- ramura locala vs origin (fetch + numarare ahead/behind) ---
function Get-StareFetch($repoPath) {
# ErrorActionPreference local 'Continue': altfel 2>$null pe un exe extern (chiar la iesire 0,
# git scrie mesaje normale pe stderr) devine NativeCommandError terminal sub preferinta 'Stop'.
$ErrorActionPreference = 'Continue'
if (-not (Test-Path (Join-Path $repoPath '.git'))) { return $null }
$remote = & git -C $repoPath remote
if (-not $remote) { return @{ AreRemote = $false } }
& git -C $repoPath fetch --quiet 2>$null | Out-Null
$fetchOk = ($LASTEXITCODE -eq 0)
$upstream = (& git -C $repoPath rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>$null)
if ($LASTEXITCODE -ne 0 -or -not $upstream) {
return @{ AreRemote = $true; FetchOk = $fetchOk; AreUpstream = $false }
}
$numere = (& git -C $repoPath rev-list --left-right --count "$upstream...HEAD" 2>$null) -split '\s+' | Where-Object { $_ -ne '' }
return @{ AreRemote = $true; FetchOk = $fetchOk; AreUpstream = $true; Upstream = $upstream; Behind = [int]$numere[0]; Ahead = [int]$numere[1] }
}
function Scrie-StareFetch($stare) {
if (-not $stare) { return }
if (-not $stare.AreRemote) { return }
if (-not $stare.FetchOk) { Write-Output ' (fetch esuat, sar verificarea fata de origin)'; return }
if (-not $stare.AreUpstream) { return }
if ($stare.Behind -gt 0) {
Write-Output (' ramura locala e in urma cu ' + $stare.Behind + ' commit-uri fata de ' + $stare.Upstream)
}
}
# --- pas 4: stare repo-uri ---
Write-Output '[4] stare repo proiect:'
$stareProiect = Get-StareFetch $ProjectRoot
Scrie-StareFetch $stareProiect
& git -C $ProjectRoot status --short | ForEach-Object { Write-Output (' ' + $_) }
& git -C $ProjectRoot diff --stat HEAD | ForEach-Object { Write-Output (' ' + $_) }
Write-Output '[4] stare repo COMUN:'
if (Test-Path (Join-Path $comunPath '.git')) {
$stareComun = Get-StareFetch $comunPath
Scrie-StareFetch $stareComun
& git -C $comunPath status --short | ForEach-Object { Write-Output (' ' + $_) }
& git -C $comunPath diff --stat HEAD | ForEach-Object { Write-Output (' ' + $_) }
} else {
Write-Output ' (fara repo git in COMUN)'
}
if ($DryRun) {
Write-Output '[5] commit/push: sarit (-DryRun)'
if ($modifProiect.Count -gt 0) {
Write-Output (' ar comite in proiect (' + $modifProiect.Count + ' fisiere)')
} else {
Write-Output ' proiect: nimic de comis'
}
if ($modifComun.Count -gt 0) {
if ($Comun) {
Write-Output (' ar comite in COMUN (' + $modifComun.Count + ' fisiere)')
} else {
Write-Output (' COMUN are ' + $modifComun.Count + ' fisiere necomise - nu se comite fara -Comun')
}
} else {
Write-Output ' COMUN: nimic de comis'
}
exit 0
}
# --- pas 5: commit + push ---
$exitCode = 0
# push, si daca e respins non-fast-forward: fetch + rebase peste upstream + o singura reincercare.
# Conflicte la rebase -> rebase --abort (nu lasa repo-ul in rebase in curs) + esec, fara push --force.
function Invoke-PushCuRebaseRetry($repoPath, $eticheta) {
# ErrorActionPreference local 'Continue': vezi motivul in Get-StareFetch.
$ErrorActionPreference = 'Continue'
# | Out-Null pe fiecare apel git: stdout-ul lui n-ar trebui sa ajunga in valoarea
# intoarsa de functie (rezultatul e capturat de apelant) - vezi Comite-Si-Impinge.
& git -C $repoPath push | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host ('[5] ' + $eticheta + ': push OK')
return 0
}
& git -C $repoPath fetch --quiet 2>$null | Out-Null
$upstream = (& git -C $repoPath rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>$null)
if ($LASTEXITCODE -ne 0 -or -not $upstream) {
Write-Host ('[5] ' + $eticheta + ': PUSH ESUAT (fara upstream de comparat)')
return 1
}
$numere = (& git -C $repoPath rev-list --left-right --count "$upstream...HEAD" 2>$null) -split '\s+' | Where-Object { $_ -ne '' }
$behind = [int]$numere[0]
if ($behind -eq 0) {
Write-Host ('[5] ' + $eticheta + ': PUSH ESUAT (nu e in urma fata de ' + $upstream + ', alta cauza)')
return 1
}
Write-Host ('[5] ' + $eticheta + ': push respins, ramura in urma cu ' + $behind + ' fata de ' + $upstream + ' - rebase')
& git -C $repoPath rebase $upstream | Out-Null
if ($LASTEXITCODE -ne 0) {
& git -C $repoPath rebase --abort 2>$null | Out-Null
Write-Host ('[5] ' + $eticheta + ': REBASE CU CONFLICTE - abort facut, e nevoie de interventie manuala')
return 1
}
Write-Host ('[5] ' + $eticheta + ': rebase OK, reincerc push')
& git -C $repoPath push | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host ('[5] ' + $eticheta + ': PUSH ESUAT si dupa rebase')
return 1
}
Write-Host ('[5] ' + $eticheta + ': push OK dupa rebase')
return 0
}
function Comite-Si-Impinge($repoPath, $eticheta, $faraPush, $mesajFile) {
# mesajele folosesc Write-Host (nu Write-Output): functia e apelata cu rezultatul
# capturat intr-o variabila, iar Write-Output ar ajunge in valoarea returnata.
if (-not (Test-Path (Join-Path $repoPath '.git'))) {
Write-Host ('[5] ' + $eticheta + ': fara repo git, sarit')
return 0
}
& git -C $repoPath add -A | Out-Null
& git -C $repoPath diff --cached --quiet
if ($LASTEXITCODE -eq 0) {
Write-Host ('[5] ' + $eticheta + ': nimic de comis')
return 0
}
$ramura = (& git -C $repoPath rev-parse --abbrev-ref HEAD)
# -F <fisier>, nu -m $Mesaj: PowerShell 5.1 nu escapeaza ghilimele/backtick/$ cand paseaza
# argumente catre un exe nativ - un mesaj cu ghilimele duble ("sync SVN") sparge -m $Mesaj.
& git -C $repoPath commit -F $mesajFile | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host ('[5] ' + $eticheta + ': COMMIT ESUAT pe ramura ' + $ramura)
return 1
}
Write-Host ('[5] ' + $eticheta + ': commit OK pe ramura ' + $ramura)
if ($faraPush) {
Write-Host ('[5] ' + $eticheta + ': push sarit (-FaraPush)')
return 0
}
return (Invoke-PushCuRebaseRetry $repoPath $eticheta)
}
# mesajul de commit trece printr-un fisier temporar (nu ca argument -m): singurul mod sigur
# de a duce prin PowerShell->exe nativ un text cu ghilimele/backtick/$/linii multiple/"-" la
# inceput de linie fara sa fie interpretat sau trunchiat. Sters mereu, inclusiv pe esec.
$mesajDir = $null
try {
$mesajDir = Join-Path ([System.IO.Path]::GetTempPath()) ('livrare_' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $mesajDir | Out-Null
$mesajFile = Join-Path $mesajDir 'mesaj_commit.txt'
# UTF8Encoding($false): fara BOM - Out-File -Encoding utf8 scrie BOM in PS 5.1, iar git
# il baga in mesajul de commit ca prim caracter (U+FEFF) daca-l citim cu -F.
[System.IO.File]::WriteAllText($mesajFile, $Mesaj, (New-Object System.Text.UTF8Encoding $false))
$exitCode += (Comite-Si-Impinge $ProjectRoot 'proiect' $FaraPush $mesajFile)
if ($Comun) {
$exitCode += (Comite-Si-Impinge $comunPath 'COMUN' $FaraPush $mesajFile)
} elseif ($modifComun.Count -gt 0) {
Write-Output ('[5] COMUN: ' + $modifComun.Count + ' fisiere necomise - nu se comite fara -Comun')
}
} finally {
if ($mesajDir -and (Test-Path $mesajDir)) { Remove-Item -LiteralPath $mesajDir -Recurse -Force -ErrorAction SilentlyContinue }
}
if ($exitCode -gt 0) { exit 3 }
Write-Output 'livrare: OK'
exit 0

View File

@@ -0,0 +1,689 @@
# publicare_scripturi.ps1 - publica scripturile de migrare .sql catre clientii ROA.
# Doi pasi, exact ca formularul din tasks.exe (clase\generare_script.vcx):
# 1. import - scrie fiecare .sql in CONTAFIN_ORACLE.UPD_DATABASE de pe ROA_CENTRAL
# (script_order = 0, un rand = un script intreg); daca script_name exista deja,
# face update pe id, ca sa se republice continutul corectat;
# 2. arhiva - regenereaza database_<luna>.zip / databasen_<luna>.zip si indexii
# roa_database.xml / roa_databasen.xml in Y:\ROAUPDATE\_UPDATE.
# Continutul din arhiva se citeste INAPOI din baza, nu de pe disc, si se compara octet cu octet cu
# fisierul sursa - deci arhiva contine exact ce vor primi clientii. Optional (implicit pornit),
# arhiva generata se citeste inapoi prin zip_util_pkg, cititorul Oracle al clientului.
#
# Configurarea se citeste din settings.ini-ul lui tasks.exe (aceleasi chei pe care le foloseste
# formularul): [connection] host_database/username_database/password_database, [folder]
# script_folder (\SCRIPTURI\ -> \SCRIPTURI_CLAR\), roa_output (+ _UPDATE) si sqlplus_exe, [script]
# prefixele valide. Aliasul TNS se ia din DSN-ul ODBC numit in host_database (cheia ServerName din
# registri). Orice parametru dat explicit are prioritate fata de ini.
#
# Utilizare:
# powershell -File COMUN\utile\publicare_scripturi.ps1 -DryRun
# powershell -File COMUN\utile\publicare_scripturi.ps1 -Fisier a.sql,b.sql
# powershell -File COMUN\utile\publicare_scripturi.ps1 -Luna 2026-08
# powershell -File COMUN\utile\publicare_scripturi.ps1 -Luna 2026-08 -DoarArhiva
param(
[string[]]$Fisier,
[string]$Luna,
[string]$Settings = 'D:\PROIECTE\fox\tasks\settings.ini',
[string]$DirScripturi,
[string]$ZipPath,
[string]$BackupPath,
[switch]$DoarImport,
[switch]$DoarArhiva,
[switch]$Toate,
[switch]$FaraVerificareZip,
[switch]$DryRun,
[switch]$PastreazaTemp,
[string]$Alias,
[string]$User,
[string]$Password,
[string]$SqlPlus
)
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.IO.Compression.FileSystem
# octeti per bucata trimisa/citita ca hexazecimal (2 caractere per octet, sub limita de linie sqlplus)
$BUCATA = 900
# bucati per bloc PL/SQL (sursa unui bloc trebuie sa ramana sub ~64k)
$BUCATI_PER_BLOC = 15
function Scrie-Titlu {
param([string]$Text)
Write-Output ''
Write-Output ('===== ' + $Text + ' =====')
}
function Opreste {
param([string]$Mesaj)
Write-Output ''
Write-Output ('EROARE: ' + $Mesaj)
Curata-Temp
exit 1
}
function Curata-Temp {
if ($PastreazaTemp) {
if (Test-Path $TempDir) { Write-Output ('Temp pastrat: ' + $TempDir) }
return
}
if (Test-Path $TempDir) { Remove-Item -LiteralPath $TempDir -Recurse -Force -ErrorAction SilentlyContinue }
}
function Invoke-SqlPlus {
# ruleaza un script sqlplus; intoarce textul si codul de iesire (whenever sqlerror => cod <> 0)
param([string]$Sql, [string]$Nume = 'q')
$f = Join-Path $TempDir ($Nume + '_' + [guid]::NewGuid().ToString('N') + '.sql')
$antet = "whenever sqlerror exit failure rollback`r`nwhenever oserror exit failure`r`nset define off`r`nset feedback off`r`n"
[System.IO.File]::WriteAllText($f, ($antet + $Sql), [System.Text.Encoding]::ASCII)
try {
$out = & $SqlPlus -L -S $ConnStr ('@' + $f) 2>&1
$cod = $LASTEXITCODE
} catch {
$out = 'EROARE lansare sqlplus: ' + $_.Exception.Message
$cod = -1
}
if (-not $PastreazaTemp) { Remove-Item -LiteralPath $f -Force -ErrorAction SilentlyContinue }
$text = ($out | ForEach-Object { [string]$_ }) -join "`n"
[PSCustomObject]@{ Text = $text; Cod = $cod }
}
function Test-Rezultat {
param($R, [string]$Context)
if ($R.Cod -ne 0 -or $R.Text -match 'ORA-\d{5}|SP2-\d{4}|PLS-\d{5}') {
Write-Output $R.Text
Opreste ($Context + ' - sqlplus a raportat eroare (cod ' + $R.Cod + ').')
}
}
function ConvertTo-Hex {
param([byte[]]$Octeti)
if ($Octeti.Length -eq 0) { return '' }
[System.BitConverter]::ToString($Octeti).Replace('-', '')
}
function ConvertFrom-Hex {
param([string]$Hex)
$n = [int]($Hex.Length / 2)
$b = New-Object byte[] $n
for ($i = 0; $i -lt $n; $i++) { $b[$i] = [Convert]::ToByte($Hex.Substring($i * 2, 2), 16) }
,$b
}
function Citeste-Ini {
param([string]$Cale)
$ini = @{}
$sectiune = ''
foreach ($linie in [System.IO.File]::ReadAllLines($Cale, [System.Text.Encoding]::GetEncoding(1252))) {
$linie = $linie.Trim()
if (-not $linie -or $linie.StartsWith(';') -or $linie.StartsWith('#')) { continue }
if ($linie -match '^\[(.+)\]$') {
$sectiune = $Matches[1].ToLower()
if (-not $ini.ContainsKey($sectiune)) { $ini[$sectiune] = @{} }
continue
}
$p = $linie.IndexOf('=')
if ($p -lt 1 -or -not $sectiune) { continue }
$ini[$sectiune][$linie.Substring(0, $p).Trim().ToLower()] = $linie.Substring($p + 1).Trim()
}
$ini
}
function Ia-Cheie {
param($Ini, [string]$Sectiune, [string]$Cheie)
$s = $Sectiune.ToLower()
$c = $Cheie.ToLower()
if ($Ini.ContainsKey($s) -and $Ini[$s].ContainsKey($c)) { return $Ini[$s][$c] }
''
}
function Rezolva-Alias {
# numele din host_database e un DSN ODBC; aliasul TNS e in cheia ServerName a DSN-ului
param([string]$Dsn)
foreach ($radacina in @('HKCU:\SOFTWARE\ODBC\ODBC.INI', 'HKLM:\SOFTWARE\ODBC\ODBC.INI', 'HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI')) {
$cale = Join-Path $radacina $Dsn
if (Test-Path $cale) {
$v = (Get-ItemProperty -Path $cale -Name 'ServerName' -ErrorAction SilentlyContinue).ServerName
if ($v) { return $v }
}
}
# nu e DSN ODBC - il tratam ca alias TNS direct
$Dsn
}
function Compara-Octeti {
param([byte[]]$A, [byte[]]$B)
if ($null -eq $A -or $null -eq $B) { return $false }
if ($A.Length -ne $B.Length) { return $false }
for ($i = 0; $i -lt $A.Length; $i++) { if ($A[$i] -ne $B[$i]) { return $false } }
$true
}
function Split-Hex {
# taie un sir hexazecimal in bucati de $BUCATA octeti
param([string]$Hex)
$l = New-Object System.Collections.ArrayList
$pas = $BUCATA * 2
for ($i = 0; $i -lt $Hex.Length; $i += $pas) {
[void]$l.Add($Hex.Substring($i, [Math]::Min($pas, $Hex.Length - $i)))
}
,$l
}
function Parseaza-NumeScript {
# <prefix>_YYYY_MM_DD_NN_<tip>.sql -> obiect cu elementele componente (ca parsescriptname din VFP)
param([string]$Cale)
$stem = [System.IO.Path]::GetFileNameWithoutExtension($Cale)
if ($stem -notmatch '^([A-Za-z]+)_(\d{4})_(\d{2})_(\d{2})_(\d+)(?:_(.+))?$') { return $null }
$an = [int]$Matches[2]; $luna = [int]$Matches[3]; $zi = [int]$Matches[4]
try { $data = Get-Date -Year $an -Month $luna -Day $zi -Hour 0 -Minute 0 -Second 0 } catch { return $null }
$tip = ''
if ($Matches[6]) { $tip = $Matches[6].ToUpper() }
[PSCustomObject]@{
Cale = $Cale
NumeScript = ($stem.ToUpper() + '.SQL')
Stem = $stem.ToUpper()
Prefix = $Matches[1].ToUpper()
Data = $data
DataYmd = $data.ToString('yyyyMMdd')
Secventa = [int]$Matches[5]
Tip = $tip
}
}
function Citeste-MetadateLuna {
# metadatele scripturilor intregi (script_order = 0) din luna, in ordinea din arhiva
param([datetime]$Inceput, [datetime]$Sfarsit)
$sql = @"
set pagesize 0 linesize 600 trimspool on heading off
select 'M|' || id || '|' || script_name || '|' || script_type || '|' || to_char(script_date,'yyyymmdd') ||
'|' || to_char(script_seq) || '|' || to_char(script_order) || '|' || nvl(script_appver,'') ||
'|' || nvl(length(script_content),0)
from upd_database
where script_order = 0
and script_date between to_date('$($Inceput.ToString('yyyyMMdd'))','yyyymmdd') and to_date('$($Sfarsit.ToString('yyyyMMdd'))','yyyymmdd')
order by script_name, id;
exit
"@
$r = Invoke-SqlPlus -Sql $sql -Nume 'meta'
Test-Rezultat -R $r -Context 'citire metadate din UPD_DATABASE'
$l = New-Object System.Collections.ArrayList
foreach ($linie in ($r.Text -split "`r?`n")) {
$linie = $linie.Trim()
if (-not $linie.StartsWith('M|')) { continue }
$c = $linie.Substring(2) -split '\|'
if ($c.Count -lt 8) { continue }
[void]$l.Add([PSCustomObject]@{
Id = [int]$c[0]
NumeScript = $c[1].Trim()
Stem = [System.IO.Path]::GetFileNameWithoutExtension($c[1].Trim())
Tip = $c[2].Trim()
DataYmd = $c[3].Trim()
Secventa = [int]$c[4]
Ordine = [int]$c[5]
AppVer = $c[6].Trim()
Lungime = [int]$c[7]
})
}
,$l
}
function Citeste-Continut {
# citeste inapoi CLOB-urile ca octeti CP1252 (hexazecimal), pentru toate id-urile date
param($Metadate)
$rezultat = @{}
if ($Metadate.Count -eq 0) { return $rezultat }
$maxBucati = 1
foreach ($m in $Metadate) {
$rezultat[$m.Id] = New-Object System.Text.StringBuilder
$b = [Math]::Ceiling($m.Lungime / $BUCATA)
if ($b -gt $maxBucati) { $maxBucati = [int]$b }
}
$toateId = @($Metadate | ForEach-Object { $_.Id })
$grupuri = New-Object System.Collections.ArrayList
for ($i = 0; $i -lt $toateId.Count; $i += 500) {
[void]$grupuri.Add('c.id in (' + (($toateId[$i..([Math]::Min($i + 499, $toateId.Count - 1))]) -join ',') + ')')
}
$ids = $grupuri -join ' or '
$sql = @"
set pagesize 0 linesize 32767 long 2000000000 longchunksize 32767 trimspool on heading off arraysize 100
select '#' || c.id || '#' || lpad(to_char(l.n),7,'0') || '#' ||
rawtohex(utl_i18n.string_to_raw(dbms_lob.substr(c.script_content, $BUCATA, (l.n-1)*$BUCATA+1), 'WE8MSWIN1252'))
from upd_database c,
(select level n from dual connect by level <= $maxBucati) l
where ($ids)
and (l.n-1)*$BUCATA < nvl(length(c.script_content),0)
order by c.id, l.n;
exit
"@
$r = Invoke-SqlPlus -Sql $sql -Nume 'citire'
Test-Rezultat -R $r -Context 'citire continut scripturi din UPD_DATABASE'
foreach ($linie in ($r.Text -split "`r?`n")) {
$linie = $linie.Trim()
if (-not $linie.StartsWith('#')) { continue }
$c = $linie.Substring(1) -split '#', 3
if ($c.Count -lt 3) { continue }
$id = [int]$c[0]
if ($rezultat.ContainsKey($id)) { [void]$rezultat[$id].Append($c[2]) }
}
$final = @{}
foreach ($k in $rezultat.Keys) { $final[$k] = ConvertFrom-Hex $rezultat[$k].ToString() }
$final
}
function Importa-Script {
# insert sau update pe script_name existent; continutul se trimite hexazecimal, bucata cu bucata
param($Info, [byte[]]$Octeti)
$hex = ConvertTo-Hex $Octeti
$bucati = Split-Hex $hex
$sb = New-Object System.Text.StringBuilder
[void]$sb.AppendLine('set serveroutput on size 1000000')
[void]$sb.AppendLine('variable b_id number')
[void]$sb.AppendLine('declare')
[void]$sb.AppendLine(' l_id number;')
[void]$sb.AppendLine('begin')
[void]$sb.AppendLine(" select max(id) into l_id from upd_database where script_name = '$($Info.NumeScript)';")
[void]$sb.AppendLine(' if l_id is null then')
[void]$sb.AppendLine(' insert into upd_database')
[void]$sb.AppendLine(' (script_name, script_type, script_date, script_seq, script_content, script_order, script_appver)')
[void]$sb.AppendLine(" values ('$($Info.NumeScript)', '$($Info.Tip)', to_date('$($Info.DataYmd)','yyyymmdd'), $($Info.Secventa), empty_clob(), 0, null)")
[void]$sb.AppendLine(' returning id into l_id;')
[void]$sb.AppendLine(' else')
[void]$sb.AppendLine(' update upd_database')
[void]$sb.AppendLine(" set script_type = '$($Info.Tip)',")
[void]$sb.AppendLine(" script_date = to_date('$($Info.DataYmd)','yyyymmdd'),")
[void]$sb.AppendLine(" script_seq = $($Info.Secventa),")
[void]$sb.AppendLine(' script_content = empty_clob(),')
[void]$sb.AppendLine(' script_order = 0,')
[void]$sb.AppendLine(' script_appver = null')
[void]$sb.AppendLine(' where id = l_id;')
[void]$sb.AppendLine(' end if;')
[void]$sb.AppendLine(' :b_id := l_id;')
[void]$sb.AppendLine(' commit;')
[void]$sb.AppendLine(" dbms_output.put_line('IDSCRIPT=' || l_id);")
[void]$sb.AppendLine('end;')
[void]$sb.AppendLine('/')
for ($i = 0; $i -lt $bucati.Count; $i += $BUCATI_PER_BLOC) {
[void]$sb.AppendLine('declare s varchar2(32767); l clob;')
[void]$sb.AppendLine('begin')
[void]$sb.AppendLine(' select script_content into l from upd_database where id = :b_id for update;')
for ($j = $i; $j -lt [Math]::Min($i + $BUCATI_PER_BLOC, $bucati.Count); $j++) {
[void]$sb.AppendLine(" s := utl_i18n.raw_to_char(hextoraw('$($bucati[$j])'),'WE8MSWIN1252'); dbms_lob.writeappend(l, length(s), s);")
}
[void]$sb.AppendLine(' commit;')
[void]$sb.AppendLine('end;')
[void]$sb.AppendLine('/')
}
[void]$sb.AppendLine('exit')
$r = Invoke-SqlPlus -Sql $sb.ToString() -Nume ('imp_' + $Info.Stem)
Test-Rezultat -R $r -Context ('import ' + $Info.NumeScript)
if ($r.Text -notmatch 'IDSCRIPT=(\d+)') { Opreste ('import ' + $Info.NumeScript + ' - nu am primit id-ul randului.') }
[int]$Matches[1]
}
function Scrie-XmlArhiva {
# acelasi format ca CURSORTOXML din genereazadatabasexml2: Windows-1252, CRLF, tab-uri,
# script_appver doar cand e completat, script_content gol (continutul e in fisierul separat)
param($Metadate, [string]$Cale)
$sb = New-Object System.Text.StringBuilder
[void]$sb.Append("<?xml version = `"1.0`" encoding=`"Windows-1252`" standalone=`"yes`"?>`r`n")
[void]$sb.Append("<VFPData>`r`n")
foreach ($m in $Metadate) {
[void]$sb.Append("`t<crsxml>`r`n")
[void]$sb.Append("`t`t<id>$($m.Id)</id>`r`n")
[void]$sb.Append("`t`t<script_name>$([System.Security.SecurityElement]::Escape($m.NumeScript))</script_name>`r`n")
[void]$sb.Append("`t`t<script_type>$([System.Security.SecurityElement]::Escape($m.Tip))</script_type>`r`n")
[void]$sb.Append("`t`t<script_date>$($m.DataYmd)</script_date>`r`n")
[void]$sb.Append("`t`t<script_seq>$($m.Secventa)</script_seq>`r`n")
[void]$sb.Append("`t`t<script_order>$($m.Ordine)</script_order>`r`n")
if ($m.AppVer) {
[void]$sb.Append("`t`t<script_appver>$([System.Security.SecurityElement]::Escape($m.AppVer))</script_appver>`r`n")
}
[void]$sb.Append("`t`t<script_extra_file>$($m.Stem).sql</script_extra_file>`r`n")
[void]$sb.Append("`t`t<script_content></script_content>`r`n")
[void]$sb.Append("`t</crsxml>`r`n")
}
[void]$sb.Append("</VFPData>`r`n")
[System.IO.File]::WriteAllText($Cale, $sb.ToString(), [System.Text.Encoding]::GetEncoding(1252))
}
function Scrie-Arhiva {
# xml-ul primul, apoi scripturile in ordinea din xml (ca ZipOpen/ZipFile din VFP)
param([string]$CaleZip, [string]$CaleXml, $Fisiere)
if (Test-Path $CaleZip) { Remove-Item -LiteralPath $CaleZip -Force }
$z = [System.IO.Compression.ZipFile]::Open($CaleZip, 'Create')
try {
[void][System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($z, $CaleXml, [System.IO.Path]::GetFileName($CaleXml), 'Optimal')
foreach ($f in $Fisiere) {
[void][System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($z, $f, [System.IO.Path]::GetFileName($f), 'Optimal')
}
} finally {
$z.Dispose()
}
}
function Scrie-IndexArhive {
# roa_database.xml / roa_databasen.xml - lista arhivelor existente, sortata dupa nume de fisier
param([string]$Prefix, [string]$Cale)
$arhive = @(Get-ChildItem -LiteralPath $ZipPath -Filter ($Prefix + '_*.zip') -File |
Where-Object { $_.Name -like ($Prefix + '_*.zip') } | Sort-Object Name)
$sb = New-Object System.Text.StringBuilder
[void]$sb.Append("<?xml version = `"1.0`" encoding=`"Windows-1252`" standalone=`"yes`"?>`r`n")
[void]$sb.Append("<VFPData>`r`n")
foreach ($a in $arhive) {
$parti = [System.IO.Path]::GetFileNameWithoutExtension($a.Name) -split '_'
if ($parti.Count -lt 3) { continue }
[void]$sb.Append("`t<crsxml>`r`n")
[void]$sb.Append("`t`t<url>|BASEPATH|/$($a.Name)</url>`r`n")
[void]$sb.Append("`t`t<data1>$($parti[1])</data1>`r`n")
[void]$sb.Append("`t`t<data2>$($parti[2])</data2>`r`n")
[void]$sb.Append("`t</crsxml>`r`n")
}
[void]$sb.Append("</VFPData>`r`n")
[System.IO.File]::WriteAllText($Cale, $sb.ToString(), [System.Text.Encoding]::GetEncoding(1252))
}
function Verifica-ArhivaPrinOracle {
# citeste arhiva inapoi cu cititorul clientului (pack_utils.decodebase64 + zip_util_pkg.get_file)
# si compara lungimea + MD5 al fiecarui fisier extras cu cel de pe disc
param([string]$CaleZip, $FisiereAsteptate)
$octeti = [System.IO.File]::ReadAllBytes($CaleZip)
$b64 = [Convert]::ToBase64String($octeti)
$sb = New-Object System.Text.StringBuilder
[void]$sb.AppendLine('set serveroutput on size unlimited')
[void]$sb.AppendLine('set pagesize 0 linesize 400 trimspool on heading off')
[void]$sb.AppendLine('variable b_z clob')
[void]$sb.AppendLine('begin dbms_lob.createtemporary(:b_z, true); end;')
[void]$sb.AppendLine('/')
# bucati multiplu de 4, ca sirul base64 sa ramana valid oriunde s-ar taia
$pas = 1920
for ($i = 0; $i -lt $b64.Length; $i += $pas * $BUCATI_PER_BLOC) {
[void]$sb.AppendLine('declare s varchar2(32767);')
[void]$sb.AppendLine('begin')
for ($j = $i; $j -lt [Math]::Min($i + $pas * $BUCATI_PER_BLOC, $b64.Length); $j += $pas) {
$bucata = $b64.Substring($j, [Math]::Min($pas, $b64.Length - $j))
[void]$sb.AppendLine(" s := '$bucata'; dbms_lob.writeappend(:b_z, length(s), s);")
}
[void]$sb.AppendLine('end;')
[void]$sb.AppendLine('/')
}
[void]$sb.AppendLine('declare')
[void]$sb.AppendLine(' l_zip blob; l_f blob;')
[void]$sb.AppendLine('begin')
[void]$sb.AppendLine(' l_zip := pack_utils.decodebase64(:b_z);')
[void]$sb.AppendLine(" dbms_output.put_line('ZIP|' || dbms_lob.getlength(l_zip));")
foreach ($f in $FisiereAsteptate) {
[void]$sb.AppendLine(" l_f := zip_util_pkg.get_file(l_zip, '$f');")
[void]$sb.AppendLine(" if l_f is null then dbms_output.put_line('LIPSA|$f');")
[void]$sb.AppendLine(" else dbms_output.put_line('FIS|$f|' || dbms_lob.getlength(l_f) || '|' || rawtohex(dbms_crypto.hash(l_f, 2))); end if;")
}
[void]$sb.AppendLine('end;')
[void]$sb.AppendLine('/')
[void]$sb.AppendLine('exit')
$r = Invoke-SqlPlus -Sql $sb.ToString() -Nume 'verifzip'
Test-Rezultat -R $r -Context ('verificare arhiva ' + [System.IO.Path]::GetFileName($CaleZip))
$citite = @{}
foreach ($linie in ($r.Text -split "`r?`n")) {
$linie = $linie.Trim()
if ($linie -match '^FIS\|([^|]+)\|(\d+)\|([0-9A-F]+)$') {
$citite[$Matches[1]] = [PSCustomObject]@{ Lungime = [int]$Matches[2]; Md5 = $Matches[3] }
} elseif ($linie -match '^LIPSA\|(.+)$') {
Opreste ('verificare arhiva - zip_util_pkg nu gaseste ' + $Matches[1] + ' in ' + $CaleZip)
}
}
$md5 = [System.Security.Cryptography.MD5]::Create()
$erori = 0
foreach ($f in $FisiereAsteptate) {
if (-not $citite.ContainsKey($f)) { Write-Output (' LIPSA ' + $f); $erori++; continue }
$local = Join-Path $TempDir $f
$b = [System.IO.File]::ReadAllBytes($local)
$h = (ConvertTo-Hex $md5.ComputeHash($b))
if ($citite[$f].Lungime -eq $b.Length -and $citite[$f].Md5 -eq $h) {
Write-Output (' ok ' + $f + ' (' + $b.Length + ' octeti)')
} else {
Write-Output (' DIFERIT ' + $f + ' - disc ' + $b.Length + '/' + $h + ', extras ' + $citite[$f].Lungime + '/' + $citite[$f].Md5)
$erori++
}
}
$md5.Dispose()
if ($erori -gt 0) { Opreste ('verificare arhiva - ' + $erori + ' fisiere nu se citesc corect prin zip_util_pkg.') }
}
# ---------- pregatire ----------
$TempDir = Join-Path $env:TEMP ('publicare_scripturi_' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
if (-not (Test-Path -LiteralPath $Settings)) { Opreste ('nu gasesc settings.ini la ' + $Settings + ' - da caile cu -DirScripturi/-ZipPath/-Alias/-User/-Password sau alt -Settings.') }
$ini = Citeste-Ini $Settings
# parametrii dati explicit bat ini-ul
if (-not $PSBoundParameters.ContainsKey('User')) { $User = Ia-Cheie $ini 'connection' 'username_database' }
if (-not $PSBoundParameters.ContainsKey('Password')) { $Password = Ia-Cheie $ini 'connection' 'password_database' }
if (-not $PSBoundParameters.ContainsKey('Alias')) {
$dsn = Ia-Cheie $ini 'connection' 'host_database'
if ($dsn) { $Alias = Rezolva-Alias $dsn }
}
if (-not $PSBoundParameters.ContainsKey('DirScripturi')) {
$f = Ia-Cheie $ini 'folder' 'script_folder'
if ($f) { $DirScripturi = ($f.TrimEnd('\') -replace '\\SCRIPTURI$', '\SCRIPTURI_CLAR') }
}
if (-not $PSBoundParameters.ContainsKey('ZipPath')) {
$f = Ia-Cheie $ini 'folder' 'roa_output'
if ($f) { $ZipPath = (Join-Path $f '_UPDATE') }
}
if (-not $PSBoundParameters.ContainsKey('SqlPlus')) { $SqlPlus = Ia-Cheie $ini 'folder' 'sqlplus_exe' }
foreach ($p in @(@('User', $User), @('Password', $Password), @('Alias', $Alias), @('DirScripturi', $DirScripturi), @('ZipPath', $ZipPath), @('SqlPlus', $SqlPlus))) {
if (-not $p[1]) { Opreste ('lipseste ' + $p[0] + ' - nu e in ' + $Settings + ' si nu a fost dat ca parametru.') }
}
# prefixele valide (o schema tinta per prefix), pentru validarea numelor de scripturi
$prefixe = @()
if ($ini.ContainsKey('script')) { $prefixe = @($ini['script'].Values | ForEach-Object { $_.TrimEnd('_').ToUpper() }) }
if (-not (Test-Path $SqlPlus)) { Opreste ('nu gasesc sqlplus la ' + $SqlPlus) }
$env:TNS_ADMIN = Split-Path $SqlPlus -Parent
$ConnStr = $User + '/' + $Password + '@' + $Alias
if ($DoarImport -and $DoarArhiva) { Opreste '-DoarImport si -DoarArhiva se exclud reciproc.' }
# ---------- 1. ce se publica ----------
Scrie-Titlu '1. SCRIPTURI DE PUBLICAT'
$candidati = New-Object System.Collections.ArrayList
if ($Fisier) {
foreach ($f in $Fisier) {
$cale = $f
if (-not [System.IO.Path]::IsPathRooted($cale)) {
$cale = (Resolve-Path -LiteralPath $f -ErrorAction SilentlyContinue)
if (-not $cale) { Opreste ('nu gasesc fisierul ' + $f) }
$cale = $cale.Path
}
if (-not (Test-Path -LiteralPath $cale)) { Opreste ('nu gasesc fisierul ' + $cale) }
$info = Parseaza-NumeScript $cale
if (-not $info) { Opreste ('nume de script neconform (<prefix>_YYYY_MM_DD_NN_<tip>.sql): ' + $cale) }
[void]$candidati.Add($info)
}
$luni = @($candidati | ForEach-Object { $_.Data.ToString('yyyy-MM') } | Sort-Object -Unique)
if ($luni.Count -gt 1) { Opreste ('scripturile date sunt din luni diferite (' + ($luni -join ', ') + ') - ruleaza cate o luna.') }
if (-not $Luna) { $Luna = $luni[0] }
} else {
if (-not $Luna) { $Luna = (Get-Date).ToString('yyyy-MM') }
}
if ($Luna -notmatch '^(\d{4})-(\d{2})$') { Opreste ('-Luna trebuie in formatul YYYY-MM (primit: ' + $Luna + ')') }
$anLuna = [int]$Matches[1]
$lunaLuna = [int]$Matches[2]
$dataInceput = Get-Date -Year $anLuna -Month $lunaLuna -Day 1 -Hour 0 -Minute 0 -Second 0
$dataSfarsit = $dataInceput.AddMonths(1).AddDays(-1)
$etichetaLuna = $dataInceput.ToString('yyyyMMdd') + '_' + $dataSfarsit.ToString('yyyyMMdd')
$dirLuna = Join-Path (Join-Path $DirScripturi $dataInceput.ToString('yyyy')) $dataInceput.ToString('MM')
if (-not $Fisier -and -not $DoarArhiva) {
if (-not (Test-Path -LiteralPath $dirLuna)) { Opreste ('nu gasesc directorul lunii: ' + $dirLuna) }
foreach ($f in (Get-ChildItem -LiteralPath $dirLuna -Filter '*.sql' -File | Sort-Object Name)) {
$info = Parseaza-NumeScript $f.FullName
if (-not $info) { Write-Output (' [sarit] nume neconform: ' + $f.Name); continue }
[void]$candidati.Add($info)
}
}
Write-Output ('Luna: ' + $Luna + ' arhiva: ' + $etichetaLuna)
Write-Output ('Configurare: ' + $Settings)
Write-Output ('Baza: ' + $User + '@' + $Alias + ' (' + $SqlPlus + ')')
Write-Output ('Scripturi: ' + $dirLuna)
Write-Output ('Arhive: ' + $ZipPath)
foreach ($c in $candidati) {
if ($prefixe.Count -gt 0 -and $prefixe -notcontains $c.Prefix) {
Write-Output (' [atentie] prefix necunoscut "' + $c.Prefix + '" in ' + [System.IO.Path]::GetFileName($c.Cale) + ' (in ini: ' + ($prefixe -join ', ') + ')')
}
$octeti = [System.IO.File]::ReadAllBytes($c.Cale)
if ($octeti.Length -eq 0) { Opreste ('fisier gol: ' + $c.Cale) }
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($octeti)
if ($text -match "(?<!`r)`n") { Opreste ('sfarsituri de linie LF in ' + $c.Cale + ' - scripturile trebuie salvate cu CRLF (parsarea pe client se face pe CHR(13)+CHR(10)).') }
Add-Member -InputObject $c -NotePropertyName Octeti -NotePropertyValue $octeti
}
# ---------- 2. starea din baza ----------
Scrie-Titlu '2. STAREA DIN UPD_DATABASE'
$metadate = Citeste-MetadateLuna -Inceput $dataInceput -Sfarsit $dataSfarsit
Write-Output ('In baza, pentru luna ' + $Luna + ': ' + $metadate.Count + ' scripturi.')
$dupaNume = @{}
foreach ($m in $metadate) { $dupaNume[$m.NumeScript] = $m }
$deImportat = New-Object System.Collections.ArrayList
if (-not $DoarArhiva) {
$existente = @($candidati | Where-Object { $dupaNume.ContainsKey($_.NumeScript) })
$continuturi = @{}
if ($existente.Count -gt 0) {
$continuturi = Citeste-Continut -Metadate @($existente | ForEach-Object { $dupaNume[$_.NumeScript] })
}
foreach ($c in $candidati) {
if (-not $dupaNume.ContainsKey($c.NumeScript)) {
Write-Output (' NOU ' + $c.NumeScript + ' (' + $c.Octeti.Length + ' octeti)')
[void]$deImportat.Add($c)
continue
}
$m = $dupaNume[$c.NumeScript]
$inBaza = $continuturi[$m.Id]
$identic = Compara-Octeti -A $inBaza -B $c.Octeti
if ($identic -and -not $Toate) {
Write-Output (' publicat ' + $c.NumeScript + ' (id ' + $m.Id + ', identic)')
} elseif ($identic) {
Write-Output (' REPUBLIC ' + $c.NumeScript + ' (id ' + $m.Id + ', identic, fortat cu -Toate)')
[void]$deImportat.Add($c)
} else {
Write-Output (' MODIFICAT ' + $c.NumeScript + ' (id ' + $m.Id + ', in baza ' + $(if ($inBaza) { $inBaza.Length } else { 0 }) + ' octeti, pe disc ' + $c.Octeti.Length + ')')
[void]$deImportat.Add($c)
}
}
}
# ---------- 3. import ----------
if (-not $DoarArhiva) {
Scrie-Titlu '3. IMPORT IN UPD_DATABASE'
if ($deImportat.Count -eq 0) {
Write-Output 'Nimic de importat - toate scripturile din luna sunt deja publicate cu acelasi continut.'
} elseif ($DryRun) {
Write-Output ('DryRun - as importa ' + $deImportat.Count + ' scripturi (vezi lista de mai sus).')
} else {
foreach ($c in $deImportat) {
$id = Importa-Script -Info $c -Octeti $c.Octeti
Write-Output (' importat ' + $c.NumeScript + ' -> id ' + $id)
}
$metadate = Citeste-MetadateLuna -Inceput $dataInceput -Sfarsit $dataSfarsit
$dupaNume = @{}
foreach ($m in $metadate) { $dupaNume[$m.NumeScript] = $m }
$verif = Citeste-Continut -Metadate @($deImportat | ForEach-Object { $dupaNume[$_.NumeScript] })
$erori = 0
foreach ($c in $deImportat) {
$m = $dupaNume[$c.NumeScript]
$inBaza = $verif[$m.Id]
if (Compara-Octeti -A $inBaza -B $c.Octeti) {
Write-Output (' verificat ' + $c.NumeScript + ' (' + $c.Octeti.Length + ' octeti, identic cu fisierul)')
} else {
Write-Output (' DIFERIT ' + $c.NumeScript + ' - continutul din baza nu coincide cu fisierul!')
$erori++
}
}
if ($erori -gt 0) { Opreste ($erori + ' scripturi nu s-au scris corect in baza - nu generez arhiva.') }
}
}
if ($DoarImport) {
Scrie-Titlu 'GATA (doar import)'
Write-Output 'Arhiva NU a fost regenerata - clientii primesc scripturile abia dupa pasul de arhiva.'
Curata-Temp
exit 0
}
# ---------- 4. arhiva lunara ----------
Scrie-Titlu '4. ARHIVA LUNARA'
if (-not (Test-Path -LiteralPath $ZipPath)) { Opreste ('nu gasesc directorul arhivelor: ' + $ZipPath) }
if ($DryRun) {
Write-Output ('DryRun - as regenera database_' + $etichetaLuna + '.zip si databasen_' + $etichetaLuna + '.zip din ' + $metadate.Count + ' scripturi.')
Curata-Temp
exit 0
}
$metadate = Citeste-MetadateLuna -Inceput $dataInceput -Sfarsit $dataSfarsit
if ($metadate.Count -eq 0) { Opreste ('nu exista scripturi in UPD_DATABASE pentru luna ' + $Luna + ' - nu am ce arhiva.') }
$continuturi = Citeste-Continut -Metadate $metadate
$fisiereSql = New-Object System.Collections.ArrayList
foreach ($m in $metadate) {
$b = $continuturi[$m.Id]
if (-not $b -or $b.Length -ne $m.Lungime) {
Opreste ('citire incompleta pentru ' + $m.NumeScript + ' (asteptat ' + $m.Lungime + ' octeti, citit ' + $(if ($b) { $b.Length } else { 0 }) + ').')
}
$numeFis = $m.Stem + '.sql'
[System.IO.File]::WriteAllBytes((Join-Path $TempDir $numeFis), $b)
[void]$fisiereSql.Add($numeFis)
}
Write-Output ('Extrase din baza: ' + $fisiereSql.Count + ' scripturi.')
$numeFisiere = @($fisiereSql)
$rezultat = @()
foreach ($prefix in @('database', 'databasen')) {
$numeXml = $prefix + '_' + $etichetaLuna + '.xml'
$caleXml = Join-Path $TempDir $numeXml
Scrie-XmlArhiva -Metadate $metadate -Cale $caleXml
$caleZip = Join-Path $TempDir ($prefix + '_' + $etichetaLuna + '.zip')
Scrie-Arhiva -CaleZip $caleZip -CaleXml $caleXml -Fisiere @($numeFisiere | ForEach-Object { Join-Path $TempDir $_ })
Write-Output ('Generat ' + [System.IO.Path]::GetFileName($caleZip) + ' (' + (Get-Item -LiteralPath $caleZip).Length + ' octeti)')
$rezultat += [PSCustomObject]@{ Zip = $caleZip; Xml = $numeXml }
}
# ---------- 5. verificare cu cititorul clientului ----------
if (-not $FaraVerificareZip) {
Scrie-Titlu '5. VERIFICARE ARHIVA PRIN ZIP_UTIL_PKG'
Verifica-ArhivaPrinOracle -CaleZip $rezultat[0].Zip -FisiereAsteptate (@($rezultat[0].Xml) + $numeFisiere)
} else {
Scrie-Titlu '5. VERIFICARE ARHIVA PRIN ZIP_UTIL_PKG'
Write-Output 'Sarit (-FaraVerificareZip).'
}
# ---------- 6. publicare in _UPDATE ----------
Scrie-Titlu '6. PUBLICARE IN _UPDATE'
if (-not $BackupPath) { $BackupPath = Join-Path $ZipPath ('_backup\' + (Get-Date).ToString('yyyyMMdd_HHmmss')) }
New-Item -ItemType Directory -Force -Path $BackupPath | Out-Null
foreach ($n in @(($rezultat | ForEach-Object { [System.IO.Path]::GetFileName($_.Zip) }) + 'roa_database.xml' + 'roa_databasen.xml')) {
$tinta = Join-Path $ZipPath $n
if (Test-Path -LiteralPath $tinta) {
Copy-Item -LiteralPath $tinta -Destination (Join-Path $BackupPath $n) -Force
Write-Output (' salvat ' + $n + ' -> ' + $BackupPath)
}
}
foreach ($r in $rezultat) {
Copy-Item -LiteralPath $r.Zip -Destination (Join-Path $ZipPath ([System.IO.Path]::GetFileName($r.Zip))) -Force
Write-Output (' publicat ' + [System.IO.Path]::GetFileName($r.Zip))
}
Scrie-IndexArhive -Prefix 'database' -Cale (Join-Path $ZipPath 'roa_database.xml')
Scrie-IndexArhive -Prefix 'databasen' -Cale (Join-Path $ZipPath 'roa_databasen.xml')
Write-Output ' publicat roa_database.xml, roa_databasen.xml'
Scrie-Titlu 'GATA'
Write-Output ('Luna ' + $Luna + ': ' + $metadate.Count + ' scripturi in arhiva, ' + $deImportat.Count + ' importate acum.')
Write-Output ('Backup-ul fisierelor inlocuite: ' + $BackupPath)
Curata-Temp
exit 0