Files
roafacturare/docs/brief_r6_punct6_vfp.md
2026-08-20 22:44:52 +03:00

11 KiB

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 = <cota>, 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):

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 *<PropValue> / 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 *<DefinedPropArrayMethod>, nu doar valoarea in *<PropValue> — 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:

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)

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):

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 <staging>\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.