# Brief de implementare — runda 6, punctul 6, partea VFP Explicatia TVA in dialogul de modificare a articolului din `frm_facturi`. Proiectarea completa: `docs\propunere_runda6_punct6_plsql.md`, sectiunea "Ce ramane de facut in VFP". Acest brief e executabil: contine liniile exacte, valorile exacte si ce s-a verificat deja. ## Interdictii (citeste-le inainte de orice) - **NU rula `git_sync.ps1`, `roa_sync.bat`, `svn update`, `svn commit`, `git commit`, `git push`.** - **NU atinge alt fisier** in afara de `COMUN\clase\ofacturare_comun.vc2` (+ binarul lui prin write-back) si `docs\raport_r6_punct6_vfp.md` (raportul tau). - **NU modifica PL/SQL** — pachetul e deja aplicat pe `MARIUSM_AUTO` si verificat. - **NU schimba `Text1.ReadOnly` nicaieri**, nu atinge grid-ul de articole, nu atinge `omodificari.vc2`. - Esti **singurul scriitor** pe `ofacturare_comun.vc2`. Daca gasesti modificari necomise pe el la start, opreste-te si raporteaza. ## Starea de plecare - `svn`/`git` curate, r18025. Textele `.??2` sunt la zi (git_sync: 0 convertite, 463 la zi). - Oracle: `MARIUSM_AUTO.PACK_FACTURARE` are deja semnatura noua, verificata pe sursa vie: ``` PROCEDURE modifica_explicatie_articol(V_ID_VANZARE_DET IN NUMBER, V_EXPLICATIE IN VARCHAR2, V_ID_UTIL IN NUMBER, V_TAXCODE IN NUMBER DEFAULT NULL, V_ID_JTVA_COLOANA IN NUMBER DEFAULT NULL); ``` Al 5-lea parametru lipsa/NULL => ramura veche (se scriu doar `EXPLICATIE` si `TAXCODE`). ## Fapte verificate pe cod — nu le re-investiga 1. `crsDetalii` (`oproceduri_facturare.prg:382-400`) are: `id_vanzare`, `id_vanzare_det`, `proc_tvav`, `id_jtva_coloana`, `jtva_coloana`, `taxcode`, `taxname`, `sters`, `explicatie`. **Nu are `data_act` si nu are `id_part`.** 2. `crsfacturi` (`oproceduri_facturare.prg:339-360`) are `data_act`, `id_part`, `id_vanzare`. Randul curent din `crsfacturi` **este** antetul liniei editate: `crsDetalii` se filtreaza pe `id_vanzare=` al randului curent din `crsfacturi` (`ofacturare_comun.vc2:3621-3623`). 3. `proc_tvav` e **multiplicator** (1.19), `cota_tva` din `vjtva_coloane` e **procent** (19). Cota liniei = `Round((Nvl(poRec.proc_tvav,0) - 1) * 100, 2)`. 4. Filtrul de explicatii e cel din `caut_explicatie_tva` (`ocautare.prg:3193, 3220`): `id_jtva_coloana > 0` + `cota_tva = `, pe view-ul `vjtva_coloane`. **Nu** folosi `update_jtva_coloane` — acela adauga restrictii pe `afisat` si pe `cote_tva` de an/luna curenta, care nu sunt in proiectarea aprobata. 5. `GetTaxCodeIdPart` (`oproceduri_comune.prg:6059-6125`) e apelabila din `frm_facturi`, isi gestioneaza singura cursorul `jtva_coloane`, si **returneaza `.NULL.` daca `gl406` e `.F.`** (`:6086-6088`) — de aceea apelul se face doar sub garda `gl406`, altfel ar sterge `taxcode`-ul. 6. `tlNeexigibil` = `.F.` (parametru **omis**). Confirmat, nu presupus: calea de emitere a facturii foloseste `GetTaxCode(gnAn, gnLuna, ldDataAct, lnIdJtva, .F.)` cu ultimii trei parametri impliciti (`ofacturare.vc2:2529` si `:3101`), iar pe jurnal de vanzari (`jv`) `GetTaxCodeIdPart` degenereaza exact in acel apel (ramura `llJC` e `.F.`, `:6098-6110`). Deci butonul produce acelasi `taxcode` pe care l-ar produce emiterea. 7. `n50`/`n100` = `.F.` (parametri omisi), ca in `ointroduceri.vc2:11488`. ## Modificarile — fisier `COMUN\clase\ofacturare_comun.vc2` Ruleaza intai `vfp_symbols.ps1 -Where` ca sa confirmi domeniul fiecarei metode inainte sa editezi; numerele de linie de mai jos sunt de la starea r18025 si se pot deplasa dupa prima editare. ### M1 — `frm_facturi.do_modifica_explicatie` (~`:4642-4659`) Dupa `Scatter Name poRec Memo` si inainte de `If poRec.sters = 0`, ataseaza antetul pe `poRec` (vezi faptul 1 si 2 — campurile nu exista pe `crsDetalii`): ```foxpro AddProperty(poRec, 'data_act', crsfacturi.data_act) AddProperty(poRec, 'id_part', Nvl(crsfacturi.id_part, 0)) ``` Restul metodei ramane neschimbat (`update_saft_taxtable()` ramane unde e). ### M2 — layout `frm_modifica_articol_factura` (~`:5131`) Randul existent cu `cbo_saft` coboara, iar deasupra lui intra randul nou de explicatie TVA. Valori exacte: | obiect | proprietate | din | in | |---|---|---|---| | `frm_modifica_articol_factura` | `Height` | 370 | **431** | | `_shape3` | `Top` | 323 | **384** | | `cbo_saft` | `Top` | 329 | **390** | | `lbSaft` | `Top` | 332 | **393** | Obiecte noi (toate in `*` / `ADD OBJECT`, plus linii `*< OBJECTDATA ... >` in blocul de ZOrder de la inceputul clasei): - `_shape4` AS `_shape` OF `_baza.vcx` — `BackStyle=0, Left=13, Top=323, Height=58, Width=348` - `lbExplTva` AS `_label` OF `_baza.vcx` — `Caption="Explicatie TVA", Left=24, Top=332` (diacriticele: vezi sectiunea de encoding mai jos; textul afisat corect e `Explicație TVA`) - `cbo_expl_tva` AS `_cbbase` OF `_cb_base.vcx` — modelat dupa `cbo_saft`: `BoundColumn=3, BoundTo=.T., ColumnCount=2, ColumnWidths="400,60", Height=24, Left=110,` `Top=329, Width=238, RowSourceType=3`. **`ControlSource` ramane gol** (nu legam direct de `poRec.id_jtva_coloana` — valoarea aleasa se preia in `InteractiveChange`, ca sa putem distinge "userul a atins combo-ul" de "n-a atins"). `RowSource` se construieste in `Init` (vezi M3), nu se scrie in `ADD OBJECT`. - `lbExplTvaInfo` AS `_label` OF `_baza.vcx` — `Caption="", Left=24, Top=355, Width=324,` `Height=20, WordWrap=.T., ForeColor=RGB(128,0,0), Visible=.F.` Proprietate noua de formular: `nidjtvaales`. **Obligatoriu si intrarea `*p: nidjtvaales` in `*`, nu doar valoarea in `*`** — fara `*p:` valoarea trece fidelity-check-ul, ajunge in binar, dar VFP nu materializeaza proprietatea si orice acces cade cu eroarea 1734. Valoare initiala: `nidjtvaales = 0`. ### M3 — `frm_modifica_articol_factura.Init` La finalul metodei `Init` existente (dupa blocul care citeste `citeste_lungcampexplart`), adauga popularea combo-ului. Comportamentul cerut de proiectare, in trei ramuri: ```foxpro Local lnCota, lcSqlTva, lcCursorTva Thisform.nidjtvaales = 0 If Isnull(poRec.proc_tvav) Or Nvl(poRec.proc_tvav, 0) = 0 Thisform.cbo_expl_tva.Enabled = .F. Thisform.lbExplTvaInfo.Caption = [Cota de TVA a acestei linii nu este cunoscuta; explicatia TVA nu poate fi modificata prin acest buton.] Thisform.lbExplTvaInfo.Visible = .T. Return Endif lnCota = Round((poRec.proc_tvav - 1) * 100, 2) lcCursorTva = [crsExplTvaArt] lcSqlTva = [select id_jtva_coloana, denumire, cota_tva from vjtva_coloane where id_jtva_coloana > 0 ] + ; [and cota_tva = ] + Alltrim(Str(lnCota, 10, 2)) + [ order by denumire] If goExecutor.oExecuta(lcSqlTva, lcCursorTva) And Reccount(lcCursorTva) > 0 Thisform.cbo_expl_tva.RowSource = [select denumire, cota_tva, id_jtva_coloana from ] + lcCursorTva + [ into cursor crsExplTvaCbo] Thisform.cbo_expl_tva.Requery() Thisform.cbo_expl_tva.Value = Nvl(poRec.id_jtva_coloana, 0) Else Thisform.cbo_expl_tva.Enabled = .F. Thisform.lbExplTvaInfo.Caption = [Nu exista nicio explicatie TVA activa cu aceeasi cota ca linia facturata (cota: ] + ; Alltrim(Str(lnCota, 10, 2)) + [ %).] Thisform.lbExplTvaInfo.Visible = .T. Endif ``` Note de implementare, nu le sari: - `Alltrim(Str(lnCota,10,2))` produce `19.00`; comparatia cu `cota_tva` (NUMBER(10,0)) e corecta in Oracle. Nu formata cu virgula. - daca `Init` are `Return` propriu / `NODEFAULT`, verifica sa nu scurtcircuitezi codul existent. - inchide cursorul `crsExplTvaArt` in `Destroy` daca ramane deschis (`If Used(...) : Use In ...`). - textul mesajelor **fara diacritice** (asa sunt scrise si celelalte mesaje din aceasta clasa, ex. `:4635`) — evita complet problema de encoding pe siruri noi. ### M4 — `cbo_expl_tva.InteractiveChange` (metoda noua) ```foxpro PROCEDURE cbo_expl_tva.InteractiveChange Local lnIdJtva lnIdJtva = Nvl(This.Value, 0) If lnIdJtva <= 0 Return Endif Thisform.nidjtvaales = lnIdJtva poRec.id_jtva_coloana = lnIdJtva If Type('gl406') = 'L' And m.gl406 poRec.taxcode = GetTaxCodeIdPart(m.gnAn, m.gnLuna, poRec.data_act, m.lnIdJtva, poRec.id_part) Thisform.cbo_saft.Refresh() Endif ENDPROC ``` ### M5 — `inainte_de_do_termin` (~`:5227-5235`) Al 5-lea parametru pozitional, **literal, nu bind** — ca sa poata fi `null` curat cand userul n-a atins combo-ul (atunci procedura ramane pe ramura veche): ```foxpro Local lcParamJtva lcParamJtva = Iif(Vartype(Thisform.nidjtvaales) = 'N' And Thisform.nidjtvaales > 0, ; Alltrim(Str(Thisform.nidjtvaales)), [null]) lcSql = [begin pack_facturare.modifica_explicatie_articol(] + Alltrim(Str(poRec.id_vanzare_det)) + [,] + ; ['] + Nvl(Alltrim(OracleSpecialCharacters(poRec.explicatie)),'') + [',?gnIdUtil,?poRec.taxcode,] + lcParamJtva + [); end;] llReturn = goExecutor.oExecuta(lcSql) ``` Restul metodei (confirmarea `amessagebox`, `Return llReturn`) ramane neschimbat. Erorile `FACT-026..029` ies deja vizibil prin `goExecutor.oExecuta` — nu adauga cod de afisare. ### M6 — refresh dupa salvare **Nimic de facut.** `Thisform.actualizeaza_grid2()` din `do_modifica_explicatie` (`:4654`) e suficient: headerul nu se schimba, totalurile nu se recalculeaza. ## Encoding — capcana platita deja Fisierele `.vc2` din acest arbore au diacriticele in **cp1250, nu cp1252**. Tool-ul `Edit` le transforma in U+FFFD si strica textul din alte proprietati. - **numara octetii > 0x7F inainte si dupa fiecare editare** — trebuie sa iasa acelasi numar; - daca s-au stricat, repara cu encoding `28591`; - pentru sirurile **noi** pe care le scrii tu: **fara diacritice**, deci problema nu apare de la tine — dar poate aparea de la o rescriere a fisierului. ## Write-back si verificare 1. `txt2vcx.ps1 ... -AllowComun` — se ruleaza **direct, fara aprobare** (regula lui Marius). 2. Fidelity-check: FoxBin2Prg **nu pastreaza ordinea textuala** pentru `ADD OBJECT` multiple si proprietati custom, si sorteaza cu `_` **dupa** litere. Daca primul write-back da FAIL pe ordine: **adopta ca sursa textul regenerat din `\verify\*.vc2`**, nu incerca sa ghicesti ordinea corecta. 3. **`mtime` nu dovedeste sincronizarea text/binar** — `txt2vcx.ps1` rescrie mtime-ul textului. Dovada ceruta: reconverteste binarul intr-un cache temporar si fa `diff` cu textul din arbore; raporteaza numarul de linii diferenta (trebuie 0). ## Ce raportezi Scrie **pe disc**, la `D:\ROA\ROAFACTURARE\docs\raport_r6_punct6_vfp.md`, si raspunde in chat doar cu `GATA` + calea. In raport: - inventarul modificarilor cu `fisier:linie` (dupa write-back, deci pe numerotarea finala); - confirmarea explicita ca write-back-ul e facut si **numarul de linii diferenta** la reconversie; - numarul de octeti > 0x7F inainte si dupa; - ce n-ai putut face si de ce; - **nu comite nimic**; nu rula sincronizari. Daca te apropii de ~200-250k tokens de context, opreste-te la o stare consistenta pe disc, scrie raportul cu ce ai facut si ce ramane, si anunta — nu continua.