achizitie import: TVA DVI cu valuta proprie, discount financiar, cote multiple
- TVA-ul de pe DVI poate avea valuta si curs proprii, diferite de ale facturii (rand "protejat": rand_dvi/valuta_proprie pe introdc, sparge_tva_protejat). - Discount financiar pe factura: rand tip_rand='G' (401 = 767), TVA calculat pe baza diminuata, marfa si preturile articolelor pe valoarea integrala. - Factura multi-cota: randurile S, G si T se sparg pe cotele articolelor, cu explicatia TVA din familia coloanei si alinierea T -> S. - Teste noi in utile/Teste/achizitie_import (discount, DVI, cote, e2e). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U9uDgDfUQXbh2Neib36CN8
This commit is contained in:
@@ -108,6 +108,26 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
|
||||
programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la
|
||||
ea. De aceea SQL-ul lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau
|
||||
concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
|
||||
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate
|
||||
arunca eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA
|
||||
instructiune a metodei, nu pe linia vinovata** - simptom complet derutant. Se exclude prin
|
||||
diagnostic: aceeasi expresie merge normal la nivel de program, in alta clasa, intr-o
|
||||
subclasa cu metoda noua, si pe instanta virgina - deci nu tine de tipul datelor, de context
|
||||
sau de clasa parinte. Reper practic: linii preexistente >200 caractere intr-o clasa mare
|
||||
functioneaza pana la ~250; pragul real e in jur de 255, ca la literalii de string. Remediu:
|
||||
sparge expresia in pasi cu variabile locale. Verificare (comparat intre fisierul curent si
|
||||
un backup anterior):
|
||||
```powershell
|
||||
$l=[IO.File]::ReadAllLines($p,[Text.Encoding]::GetEncoding(28591))
|
||||
for($i=0;$i -lt $l.Length;$i++){ if($l[$i].Length -gt 200){ "{0}: len={1}" -f ($i+1), $l[$i].Length } }
|
||||
```
|
||||
- **Un UDF care citeste campul curent (`Nvl(camp,0)=1` sau similar) nu e de incredere intr-o
|
||||
clauza de filtrare** (`SELECT ... WHERE`, `LOCATE FOR`, `SCAN FOR`, `DELETE FOR`) - pointerul
|
||||
nu e garantat pe randul evaluat la fiecare apel, deci filtrul devine practic o valoare
|
||||
constanta (fie nu se declanseaza niciodata, fie loveste tot). Simptome vazute: o comasare de
|
||||
randuri care nu se mai producea deloc; un test agatat. Remediu: in clauze de filtrare
|
||||
foloseste expresia INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod
|
||||
procedural (`If`, `Replace` pe randul curent), unde pointerul e garantat pozitionat.
|
||||
|
||||
## 7. Capcane la SCRIEREA scriptului de test
|
||||
|
||||
|
||||
@@ -10,11 +10,21 @@ in IDE. `txt2vcx.ps1` cu `-CacheRoot` = `-ProjectRoot` (implicit). Pasul 0 de ma
|
||||
rularea `git_sync.ps1`; restul pasilor raman la fel. Fluxul cu cache extern (`vcx2txt.ps1` +
|
||||
`-CacheRoot` separat) ramane doar pentru proiectele nemigrate.
|
||||
|
||||
**Capcana: `git_sync.ps1` cu `-ProjectRoot` pe COMUN direct.** Lista implicita
|
||||
`-RoundtripExempt` are cai de forma `COMUN\clase\<f>.vcx` (raportate la radacina unei aplicatii,
|
||||
unde COMUN e subfolder) si se lipeste de `-ProjectRoot`. Cand radacina E chiar COMUN, caile nu
|
||||
mai potrivesc si clasele scutite (FFC/third-party cu `#INCLUDE`, ex. `oinventar.vcx`) raporteaza
|
||||
fals `roundtrip text1 != text2`. Ruleaza atunci cu lista rebazata:
|
||||
`git_sync.ps1 -ProjectRoot 'D:\ROA\ROAGEST\COMUN' -RoundtripExempt @('clase\accessibility.vcx',
|
||||
'clase\oinventar.vcx','clase\_gdiplus.vcx','clase\_reportlistener.vcx',
|
||||
'utile\foxcharts\foxcharts.vcx','utile\web\_webview.vcx')` - si apeleaza scriptul cu `&`, nu cu
|
||||
`powershell -File` (acolo lista nu se leaga ca array).
|
||||
|
||||
## Parametri per proiect (nemigrate, cache extern)
|
||||
|
||||
- **ROAGEST**: `-Project 'D:\ROA\ROAGEST\roagest.pjx' -ProjectRoot 'D:\ROA\ROAGEST'
|
||||
-CacheRoot 'D:\ROA\_vfp_textcache\roagest'`; procese de verificat inainte de write-back:
|
||||
`vfp9`, `roagest`; patch-uri de review in `docs/diff_runda<N>_<subiect>.patch`.
|
||||
-CacheRoot 'D:\ROA\_vfp_textcache\roagest'`; patch-uri de review in
|
||||
`docs/diff_runda<N>_<subiect>.patch`.
|
||||
|
||||
## Pasii unei runde
|
||||
|
||||
@@ -37,7 +47,10 @@ rularea `git_sync.ps1`; restul pasilor raman la fel. Fluxul cu cache extern (`vc
|
||||
dintr-un cursor in loc de Scan manual; butoane din cmd_butoane.vcx in loc de butoane ad-hoc).
|
||||
Inventarul comunelor: COMUN\docs\inventar-comun.md - se consulta si la pasul de plan/arhitectura,
|
||||
inainte de a scrie cod nou.
|
||||
4. Preconditie write-back: niciun proces vfp9/<exe proiect> (tin lock pe binar); nu se omoara.
|
||||
4. Preconditie write-back: binarul tinta sa nu fie blocat. `txt2vcx.ps1` verifica singur
|
||||
(`Test-ExclusiveAccess` pe `.vcx`+`.vct`) si refuza cu mesaj clar daca e lock. NU conteaza
|
||||
existenta altor instante `vfp9` — utilizatorul poate lucra in paralel in alt proiect VFP —
|
||||
si NU se omoara procese: cand lock-ul exista, se cere utilizatorului sa inchida sesiunea.
|
||||
5. Write-back: `txt2vcx.ps1 -TextFile <vc2> -ProjectRoot <root> -CacheRoot <cache>`
|
||||
(+ `-AllowComun` cu aprobare explicita pentru tinte COMUN — afecteaza toate aplicatiile ROA).
|
||||
Succes = fidelity-check trecut: binar cu mtime nou; `vcx2txt.ps1` ulterior il vede la zi.
|
||||
@@ -68,3 +81,8 @@ rularea `git_sync.ps1`; restul pasilor raman la fel. Fluxul cu cache extern (`vc
|
||||
fluxul text->bin punctual pe binarul vizat.
|
||||
- Subagentii delegati primesc regulile 2-5 in prompt si raporteaza unicitatea sirurilor
|
||||
inlocuite + rezultatul fidelity-check-ului.
|
||||
- Fisierele `.vc2`/`.sc2` sunt CRLF, dar here-string-urile PowerShell (`"...`r`n..."` sau
|
||||
`@"..."@`) produc LF simplu pe orice linie noua inserata daca nu incluzi explicit `` `r`n ``
|
||||
la fiecare capat de linie - rezultatul e un fisier cu sfarsituri de linie amestecate (CRLF pe
|
||||
continutul vechi, LF pe cel nou). Verificare finala obligatorie dupa orice scriere: numara
|
||||
octetii `0x0A` neprecedati de `0x0D` (LF izolati) - trebuie sa fie 0.
|
||||
|
||||
@@ -38,3 +38,63 @@ Regula (valabila in toate proiectele ROA/VFP): un singur subagent care duce o mi
|
||||
completeaza-l, nu repeta investigatia.
|
||||
- Orchestratorul face el insusi munca de volum -> deleaga si pastreaza-si contextul
|
||||
pentru decizii, verificari si deblocari.
|
||||
|
||||
## Disciplina de context a ORCHESTRATORULUI
|
||||
|
||||
Pragul de ~200-250k e pentru subagenti, dar orchestratorul se umple la fel de repede daca isi
|
||||
lasa in sesiune munca de CITIT. Masurat pe o runda reala (implementare + 4 rulari ale unei suite
|
||||
de 25 de teste): sesiunea principala a ajuns la ~570k desi tot codul fusese scris de subagenti.
|
||||
Consumul, in ordinea marimii: (1) citirea rezultatelor de test dupa fiecare test terminat, cu tot
|
||||
cu liniile "OK"; (2) citirea codului ca sa diagnosticheze esecurile; (3) diagnostic si fixuri
|
||||
aplicate direct in loc de delegate.
|
||||
|
||||
- **Nu citi log-uri brute.** Scripturile de raportare afiseaza DOAR esecurile plus un total
|
||||
("22 OK, 3 FAIL: <nume + linia de esec>"). Tabelul complet se citeste o singura data, la
|
||||
baseline - nu dupa fiecare rulare. Pentru suitele VFP exista deja:
|
||||
`COMUN\utile\Teste\raport_teste.ps1 -Dir <folder> [-Tot] [-Baseline <fisier>]` - fara `-Tot`
|
||||
afiseaza doar esecurile, iar cu `-Baseline` le marcheaza `[preexistent]` vs `[NOU - REGRESIE]`.
|
||||
- **Nu citi cod ca sa diagnostichezi.** Deleaga cu "adu-mi dovada, nu fisierul": agentul intoarce
|
||||
cauza + linia + citatul minim. Verifici afirmatia, nu o redescoperi.
|
||||
- **Verifica prin assert, nu prin citire.** Daca vrei sa stii ca ceva e adevarat, cere o comanda
|
||||
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.
|
||||
|
||||
## Model de lucru: backlog de story-uri mici, context mic per story
|
||||
|
||||
Impartirea pe "lane-uri" mari (o clasa, un modul) produce subagenti cu context mare si serializare
|
||||
pe fisier. Alternativa mai ieftina si mai robusta: **backlog de story-uri mici, fiecare rezolvabila
|
||||
cu context mic, rulate in bucla de agenti PROASPETI.**
|
||||
|
||||
Doua fisiere pe disc tin toata starea:
|
||||
|
||||
- `docs/handoff_<subiect>.md` - **contextul stabil**: reguli de editare, cai, ancore verificate,
|
||||
capcane confirmate, decizii luate. Il citeste fiecare agent; se actualizeaza rar.
|
||||
- `docs/backlog_<subiect>.md` - **starea vie**: story-uri cu ID, criteriu de acceptare
|
||||
VERIFICABIL, fisiere atinse, stare (`todo` / `in lucru` / `gata` / `blocat de #N`).
|
||||
|
||||
Bucla:
|
||||
1. orchestratorul ia primul story `todo` neblocat;
|
||||
2. spawneaza un agent proaspat cu prompt = trimitere la handoff + textul story-ului + criteriul
|
||||
de acceptare. **Nimic altceva** - fara istoric, fara rapoartele celorlalti agenti;
|
||||
3. agentul modifica, ruleaza verificarea din criteriu si raporteaza **verdict + ce a schimbat +
|
||||
ce a descoperit neasteptat**, atat;
|
||||
4. orchestratorul marcheaza story-ul in backlog si trece la urmatorul.
|
||||
|
||||
O story buna: are criteriu de acceptare care se poate RULA (un test, un grep, o comanda da/nu);
|
||||
atinge un singur fisier sau o singura zona (altfel story-urile se serializeaza intre ele); incape
|
||||
in 15-20 de linii de descriere; nu cere citirea intregului fisier ca sa fie inteleasa.
|
||||
|
||||
Sablon:
|
||||
|
||||
### S7 - garda pe randul protejat in recalcule
|
||||
Fisiere: COMUN\clase\<x>.vc2 (do_executa, recalc_tva_document)
|
||||
Blocat de: S4
|
||||
De facut: <2-4 propozitii>
|
||||
Acceptare: test_<y>.ps1 trece 12/12 SI `rand_protejat()` nu mai apare in nicio clauza Where
|
||||
Stare: todo
|
||||
|
||||
Cand un story pica de doua ori la rand, nu-l reincerca a treia oara cu acelasi prompt: semnul e ca
|
||||
descrierea sau criteriul e gresit, nu executia. Rescrie story-ul (mai mic, sau cu criteriul
|
||||
corectat) inainte de a mai cheltui un agent.
|
||||
@@ -7,11 +7,17 @@
|
||||
.gitignore ca `docs/diff_runda*.patch`); raman doar local, pe disc.
|
||||
Curatenie: dupa commit se sterg patch-urile de review si backup-urile de lucru
|
||||
(`*.pre_runda*.bak`).
|
||||
2. Comentarii in cod: istoricul modificarilor sta DOAR in ANTETUL fisierului, niciodata inline.
|
||||
Se aplica la fel in `.prg` si in package-urile/procedurile PL/SQL Oracle.
|
||||
In corpul codului sunt permise numai comentarii FUNCTIONALE (ce face codul si de ce, acolo
|
||||
unde nu se vede din cod) - niciodata "am adaugat / am modificat / am sters", data sau autor.
|
||||
In ANTET se tine o singura intrare CUMULATIVA per functionalitate, scurta si compacta, in stilul
|
||||
2. Comentarii in cod: minime si strict functionale - descriu comportamentul CURENT, ca si cum
|
||||
codul ar fi fost scris asa de la inceput. O linie de regula; 2-3 linii doar pentru o metoda
|
||||
cu contract nebanal (parametri, cursorul asteptat/lasat deschis, pozitionarea la iesire).
|
||||
Istoricul modificarilor sta DOAR in ANTETUL fisierului, niciodata inline; se aplica la fel
|
||||
in `.prg` si in package-urile/procedurile PL/SQL Oracle.
|
||||
INTERZIS in comentariu: nume de agent ("claude"), referinte la documente de propuneri sau la
|
||||
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. Comentariile vechi in stil jurnal nu se rescriu din oficiu - doar cand blocul e
|
||||
oricum atins, sau la cerere explicita.
|
||||
In ANTETUL fisierului se tine o singura intrare CUMULATIVA per functionalitate, in stilul
|
||||
existent (`*!* DD.MM.YYYY` / `*!* autor` / `*!* ce face, 1-2 fraze`): la revenirea pe aceeasi
|
||||
lucrare se rescrie intrarea, nu se adauga alta. Autorul e persoana care semneaza livrarea
|
||||
(ex. `marius.mutu`) - niciodata "claude" sau alt nume de agent.
|
||||
|
||||
@@ -46,13 +46,17 @@ c. **Asteptarea `ready_0`**: cu `.fxp` cald START apare in ~2s, la rece mult mai
|
||||
classlib-uri). `-ReadyTimeoutSec` generos (implicit 180s); retry NUMAI la "start ratat",
|
||||
nu la "start lent". Detectia "a pornit" se face pe mtime-ul log-ului > momentul lansarii
|
||||
(un log stale tinut de un vfp9 zombi pacaleste verificarea "log ne-gol") - omoara zombii
|
||||
inainte de fiecare lansare.
|
||||
PROPRII (filtrati pe linia de comanda, vezi punctul e) inainte de fiecare lansare.
|
||||
d. **`vfp9 -A test.prg` deschide INTERMITENT editorul** in loc sa ruleze (log gol). Lanseaza
|
||||
`.fxp`-ul PRECOMPILAT. Precompilarea (`COMPILE`+`QUIT`) atarna dupa COMPILE si, rulata in
|
||||
ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil
|
||||
izolat (`Start-Process -Wait _precompile.ps1`).
|
||||
e. **Suitele NU se ruleaza in paralel**: `_precompile.ps1` face `Get-Process vfp9 | Stop-Process
|
||||
-Force` (omoara toate instantele), deci un test lansat in paralel il ucide pe cel in curs.
|
||||
e. **Suitele NU se ruleaza in paralel** intre ele: harness-ul isi omoara instantele `vfp9`
|
||||
ramase inainte de fiecare lansare, deci un al doilea test pornit peste primul il ucide.
|
||||
Omorarea e INSA filtrata pe linia de comanda (`Win32_Process.CommandLine` care contine
|
||||
folderul de teste): instantele `vfp9` straine — sesiunea IDE a utilizatorului sau teste
|
||||
dintr-un ALT proiect VFP — nu sunt atinse si nu blocheaza rularea. Nu reintroduce
|
||||
`Get-Process vfp9 | Stop-Process -Force` fara filtru.
|
||||
f. **FARA FURT DE FOCUS (17/07/2026)**: `Graphics.CopyFromScreen` fura focus si se corupe daca
|
||||
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile se fac cu `PrintWindow`
|
||||
(user32, P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT`
|
||||
@@ -83,13 +87,35 @@ j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a surs
|
||||
valori "compuse" manual in test). Un mock incomplet lasa campuri mereu NULL sau ascunde
|
||||
pasul care se testeaza. Cand un flag global activeaza cod suplimentar (ex. `gl406`), acel
|
||||
cod cere mock-uri in plus - verifica ce apeleaza si adauga metodele lipsa din dummy.
|
||||
Cu `gl406=.T.` (SAFT), `GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni`
|
||||
(proprietate simpla nu ajunge, clasa `dummyapp` are nevoie de METODE), `goExecutor.oReset`
|
||||
(no-op e suficient), si un cursor `saft_taxtable` real (nu doar mock pe `goExecutor` -
|
||||
`update_jtva_coloane` face `USE saft_taxtable` direct pe alias). Fara ele, simptomul e un
|
||||
dialog nativ Windows "Open" (cauta `saft_taxtable.dbf`) care blocheaza headless la nesfarsit,
|
||||
fara nicio linie noua in log si CPU 0% - vezi `depanare_testare_vfp.md` pentru diagnosticul
|
||||
cu `EnumWindows`/`PrintWindow` pe fereastra ascunsa cand simptomul e "ecran gol, fara eroare".
|
||||
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
|
||||
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din
|
||||
programul PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper.
|
||||
(Cauza neclara; reproductibil.)
|
||||
Cauza confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa -
|
||||
vezi `depanare_testare_vfp.md` sectiunea 6. Remediul (constructie inline) ramane valabil
|
||||
oricum, indiferent de cauza exacta dintr-un caz punctual.
|
||||
m. **Fara `SELECT-SQL` pe cursorul legat de grid**: `SELECT ... FROM <cursor> INTO CURSOR` cat
|
||||
timp cursorul e RecordSource-ul unui grid viu poate omori procesul vfp9 silentios (fara
|
||||
eroare catchabila, fara semafor). Foloseste xBase nativ (`COUNT FOR ... TO`, `CALCULATE`,
|
||||
`LOCATE`), care nu comuta zona de lucru a grid-ului.
|
||||
n. **Wrapper-ul `.ps1` trebuie sa paseze `-SyncDir` daca `.prg`-ul isi seteaza propriul
|
||||
`gcSyncDir`** - altfel testul scrie semafoarele intr-un folder si `vfp_ui_harness.ps1` le
|
||||
asteapta in cel implicit (`uisync\`), deadlock pana la timeout. Simptom identic cu "test
|
||||
agatat", dar FARA `.ERR` si cu CPU ~0 la procesul vfp9 (nu un dialog modal - procesul chiar
|
||||
asteapta un fisier care nu vine). Timeout minim: ~30s x numarul de pasi din `-Steps`
|
||||
(auto-continue per checkpoint din `HarnessWaitContinue`), plus marja de pornire.
|
||||
o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending` + `tmrSync`,
|
||||
ex. `do_modifica_explicatie_tva` din `ointroduceri.vcx`): starea de imediat dupa actiune NU e
|
||||
observabila - `DOEVENTS FORCE` lasa timer-ul sa porneasca, iar resincronizarea rescrie ce
|
||||
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului si randurile T
|
||||
se realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare si alege un efect
|
||||
pe care resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar cand se schimba
|
||||
explicatia). Altfel testul pica fara sa fie ceva gresit in cod.
|
||||
|
||||
Reference in New Issue
Block a user