Cercetarile si propunerile rundelor 4-6 pe editarea facturii emise. Starea rundei 6 si ce s-a stabilit intra in progres.md. Nou: docs/conventii_mediu_oracle.md - pe dev/test se lucreaza numai cu ROA_CENTRAL si schemele CONTAFIN_ORACLE si MARIUSM_AUTO; schema ACN nu se foloseste. Scripturile de pachet sunt necalificate, deci schema tinta o decide sirul de conectare, nu fisierul. roafacturare.pj2 regenerat de git_sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gYCNE26G1G7UoGu2ju7aS
14 KiB
Runda 4 - totalul notelor, dialogul de sincronizare, explicatia TVA, codul de TVA
Diagnostic pe semnalarile din proba pe factura din aviz (document fara rulaje). Fiecare punct: constatarea, dovada (fisier:linie), propunerea.
Stare: aplicat in text si scris in binar, necomis
Decizii luate: la explicatia TVA - varianta B (dialogul caut_explicatie_tva, cu
corelarea codului SAF-T si filtrarea pe cota liniei); la punctul 2 - fara avertisment
suplimentar la salvare.
| ce | unde | write-back |
|---|---|---|
| 1. Total note se reface la orice recalculare a notei | COMUN\clase\omodificari.vc2 |
facut, .vcx la zi |
| 3. capete de coloana dinamice + labelul de explicatii eliminat | COMUN\clase\omodificari.vc2 |
facut, .vcx la zi |
| 4. codul de TVA nu mai vine ca Memo | COMUN\programe\ofacturare_editare.prg |
n/a (.prg) |
| 5. explicatia TVA pe linia de articol + corelare taxcode | ambele fisiere | facut, .vcx la zi |
| 6. salvarea liniilor existente pastreaza toate campurile editabile | COMUN\programe\ofacturare_editare.prg |
n/a (.prg) |
Diff-uri pentru review: docs\diff_runda4_omodificari.patch,
docs\diff_runda4_ofacturare_editare.patch. Necomis - nici git, nici SVN.
Verificat dupa write-back: textul reconvertit din .vcx e identic cu .vc2 (0 diferente),
zero caractere corupte.
1. "Total note" nu se actualizeaza cand modific valoarea notei
Nu e din cauza rulajelor. Bara de totaluri se recalculeaza doar din evenimente de pe partea de articole, niciodata din grila de note.
ActualizeazaBaraTotaluri (COMUN\clase\omodificari.vc2:12959) calculeaza nTotalLiniiRon
/ nTotalNetRon si apeleaza ActualizeazaVerdictActRul (:13001), care pune
This.nTotalActRon - adica exact valoarea afisata in "Total note"
(txtTotalActArt.ControlSource = "thisform.nTotalActRon", :12878-12880).
Apelurile ei in productie sunt doar acestea:
| linie | context |
|---|---|
omodificari.vc2:13488 |
calculeaza_valori_articol (editare in grila de articole) |
omodificari.vc2:14920 |
Show (o data, la deschidere) |
omodificari.vc2:16604 |
pgfArticole.PAGE3.Activate (la intrarea pe pagina Articole) |
omodificari.vc2:16698 |
txtDiscountArt.Valid |
omodificari.vc2:16946 |
frm_sincronizare_articole.inainte_de_do_termin |
ofacturare_editare.prg:1023 |
editorul de articole din nota |
Editarea sumei pe randul de nota trece prin Grid1.Column9.Text1.Valid
(omodificari.vc2:16044), care apeleaza Thisform.CalculeazaTotal() -
calculeazatotal (:13458) recalculeaza numai This.nSuma (totalul setului de note) si
face txtSuma.Refresh(). Bara de jos ramane cu valoarea de la ultimul eveniment de articol.
Bara se reimprospateaza indirect daca iesi si reintri pe pagina Articole (PAGE3.Activate) -
de aceea uneori pare ca "s-a actualizat singura".
Propunere 1 - o linie
La finalul lui calculeazatotal (omodificari.vc2:13458-13475), dupa
Select (m.lcSelect):
This.ActualizeazaBaraTotaluri()
ActualizeazaBaraTotaluri are deja garda proprie la inceput
(IF !This.lAreArticoleVanzari OR !Used('tvd') OR !Used('tvanz') OR Reccount('tvanz') = 0),
deci pe notele fara articole nu face nimic. calculeazatotal e apelata din 8 locuri
(inclusiv Show, :14878), toate momente in care bara oricum trebuie sa fie corecta.
Alternativa mai ingusta (doar Grid1.Column9.Text1.Valid) acopera doar suma, nu si
stergerea/adaugarea de randuri de nota - nu o recomand.
2. Nu a aparut mesajul de verificare la salvare
Aici da, e din cauza rulajelor - si e comportament voit.
SemnaturaDivergenteSincronizare (omodificari.vc2:14805) iese devreme cu semnatura goala
cand nu exista randuri active in trul:
*!* fara rulaje nu exista cu ce compara: propunerea ar marca toate articolele ca "Semnalare"
SELECT trul
COUNT FOR Nvl(sters,0) <> 1 TO lnRanduriRul
IF m.lnRanduriRul = 0
... RETURN m.lcSemnatura && ''
iar declansatorul de la salvare (:14449-14458) porneste dialogul numai daca semnatura e
nevida si difera de cea de la deschidere. Deci: document fara rulaje -> niciun dialog.
Acelasi lucru il spune si verdictul din bara: "nu se aplica (documentul nu are rulaje)"
(:13089).
Important, ca sa nu ramana o asteptare gresita: mecanismul de sincronizare compara
rulaje vs articole, niciodata note vs articole. Chiar daca documentul ar fi avut
rulaje, modificarea sumei de pe randul de nota nu ar fi deschis dialogul - divergenta
note/articole e semnalata exclusiv informativ, prin verdictul din bara
(ActualizeazaVerdictActRul, :13001), si acolo, la 305.00 vs 306.00, ar fi trebuit sa
scrie "divergent" imediat dupa editare. Nu a scris-o din cauza punctului 1.
Nicio schimbare de comportament aici, decis: dialogul de sincronizare n-are ce aplica fara rulaje, iar avertismentul simplu la salvare nu se face. Punctul 1, odata reparat, aduce singurul semnal care lipsea (verdictul devine "divergent" pe loc).
3. Dialogul de sincronizare: coloane clare, fara labelul de explicatii
Starea de acum (omodificari.vc2:16703 - frm_sincronizare_articole):
- capete de coloana fixe:
Cantitate veche/Cantitate noua/Pret vechi/Pret nou(:16838-16867); lblAvertisment(:16871-16882) explica ce inseamna: "Vechi = valorile care se salveaza acum; Nou = valorile din sursa aleasa mai sus...".
Semantica reala, verificata in ConstruiestePropunereSincronizare
(ofacturare_editare.prg:707-710): vechi = tinta (ce se suprascrie),
nou = sursa (de unde se preia). Directia se alege din optDirectie (:16888):
RUL_SURSA (rulajul e sursa) sau ARTICOLE_SURSA.
Propunere 3 - capete dinamice pe directie + eliminarea labelului
In ConstruiesteEnumerare (:16913), care ruleaza deja la deschidere si la fiecare
schimbare de directie, se seteaza captiunile:
| coloana | RUL_SURSA |
ARTICOLE_SURSA |
|---|---|---|
2 (cCantVecheProp) |
Cantitate in factura (se inlocuieste) |
Cantitate in rulaj (se inlocuieste) |
3 (cCantNouaProp) |
Cantitate in rulaj (se preia) |
Cantitate in factura (se preia) |
4 (cPretVechiProp) |
Pret in factura (se inlocuieste) |
Pret in rulaj (se inlocuieste) |
5 (cPretNouProp) |
Pret in rulaj (se preia) |
Pret in factura (se preia) |
Se sterge lblAvertisment; singura informatie din el care nu intra in capete este
"daca renuntati, salvarea continua neschimbata" - aceea exista deja ca ToolTip pe
But_renunt1 (:16752, "Inchide fara sa schimbe nimic - salvarea continua"). Propun sa o
mut in ToolTipText-ul gridului sau sa o las doar pe buton; spune tu care variantă.
Ajustari de layout necesare: HeaderHeight 22 -> 32 (capetele au WordWrap = .T., doua
randuri), latimile coloanelor 2-5 de la 88 la ~108, si gridul se poate inalta cu ~36 px
in locul labelului eliminat.
Atentie la write-back: frm_sincronizare_articole e clasa in omodificari.vc2, deci
modificarea e pe text + txt2vcx.ps1, nu in IDE.
4. Alegerea codului de TVA arata "Memo"
Confirmat, si cauza e exact cea spusa.
ArticoleNotaEditor.CautaCodTva (COMUN\programe\ofacturare_editare.prg:1094-1100):
lcSelect = [select taxname, procent_taxa, taxcode from vsaft_taxtable]
RETURN cauta_alfa(m.lcSelect, [1=2], [], [taxname], [taxname,procent_taxa], ;
[Alegeti codul de TVA], [Denumire,Procent], [], .F., [1=1], [taxname], 1, 0, [taxcode])
cauta_alfa trimite select-ul mai departe la gencursor (COMUN\programe\cauta_alfa.prg:151),
care il pune pe SELECTCMD-ul unui CursorAdapter legat de goConn.nHandle
(COMUN\programe\gencursor.prg:27-31) - deci e SQL Oracle, executat pe server.
taxname din view depaseste latimea declarata de 254 de caractere, iar driverul mapeaza
coloana pe Memo; grila din cauta_alfa_form afiseaza literalmente "Memo".
Latimea declarata, nu cea reala - asta e detaliul care conteaza. Definitia view-ului
(D:\ROA\DATABASE\SCRIPTURI_CLAR\2022\03\ff_2022_03_14_01_COMUN_SAFT.sql:566-582):
create or replace view vsaft_taxtable as
select ...
substr(a.taxcode || '-' || a.descriere, 1, 250) as taxname,
cu descriere VARCHAR2(250) in tabela (ff_2022_03_08_01_COMUN_SAFT.sql:28). Concatenarea
taxcode || '-' || descriere are latime declarata ~291 (NUMBER convertit implicit + 1 +
250), iar SUBSTR nu micsoreaza latimea declarata a rezultatului - ramane cea a
intrarii. De aceea substr(...,1,250) deja existent in view nu a rezolvat nimic, si de
aceea nici un substr(taxname,1,200) in clientul nostru nu ar rezolva singur: driverul tot
ar vedea o coloana > 254 si tot ar da Memo. Trebuie CAST, care e singurul care fixeaza
latimea declarata.
LEFT nu exista in Oracle - SUBSTR e idiomul folosit deja in cod
(COMUN\programe\updateserver.prg:1357, substr(a.adresa,1,250) as adresa).
Propunere 4 - CAST, in tabela derivata
Nu merge simplu la nivelul de sus: deca_baza.afisare (COMUN\clase\decabaza.vc2:36-73)
concateneaza WHERE si ORDER BY la acelasi nivel de query, iar Oracle nu accepta
aliasul de coloana in WHERE (ORA-00904). Filtrul de cautare si ordinea sunt ambele pe
taxname (parametrii 4 si 11 din apel), deci forma sigura e:
lcSelect = [select * from (select cast(substr(taxname,1,200) as varchar2(200)) as taxname, ] + ;
[procent_taxa, taxcode from vsaft_taxtable)]
Restul apelului ramane neschimbat. De testat dupa aplicare: deschiderea dialogului, cautarea
"incepe cu" pe denumire (verifica ca WHERE merge pe aliasul din tabela derivata) si
returnarea corecta a taxcode.
Varianta alternativa, doar pe client: cauta_alfa primeste ca parametru 3 o
CURSORSCHEMA (acum [], vezi apelul). Trecand
[taxname C(200), procent_taxa N(6,2), taxcode N(6)] s-ar forta tipul in cursorul VFP fara
sa se atinga SQL-ul. Merge, dar leaga apelul de structura exacta a view-ului; prefer CAST-ul.
De reparat separat, daca vrei: acelasi substr fara CAST din view il mosteneste si
typename (:569) - orice alt loc care afiseaza vsaft_taxtable.typename are aceeasi
problema. Nu am verificat unde se mai foloseste.
Nota: celelalte alegeri de taxcode (randul de nota, omodificari.vc2:3926 / :8491,
si rulajele, rulaje.vc2:5289) citesc cursorul local saft_taxtable, unde taxname e
C(250) - acolo nu apare Memo. Problema e strict pe calea Oracle din CautaCodTva.
5. Explicatia TVA in editarea articolelor
Lipseste, si se poate adauga - campul exista deja in cursor.
tvd are id_jtva_coloana I NULL de la creare (omodificari.vc2:14735) si e completat
din articol la adaugare (AdaugaLinieTvdDinArticol, :13144). Ce lipseste:
- coloana in grila
grdArticoleFactura- coloanele actuale sunt 1-15 (:12345-12454), fara nimic peid_jtva_coloana; - editorul -
ArticoleNotaEditor(ofacturare_editare.prg:1060-1090) trateaza doardenumire,nume_gestiune,nume_valsi taxcode.
Sablon existent, de copiat: randul de rulaj face exact asta -
afisare prin Iif(Seek(trul.id_jtva_coloana,'crsJtvaTemp','id_jtva'),crsJtvaTemp.denumire,'')
(omodificari.vc2:9253) si editare prin combo cu
RowSource = "select denumire, id_jtva_coloana from crsJtvaTemp order by denumire into cursor crsJtvaTempX"
(:9652-9655). Randul de nota foloseste dialogul caut_explicatie_tva
(COMUN\programe\ocautare.prg:3174), apelat din do_modifica_explicatie_tva
(omodificari.vc2:14049), care pune id_jtva_coloana, explicatie_tva si proc_tva.
Aplicat - varianta B (dialogul caut_explicatie_tva)
- Coloana
cExplicatieTvaArtingrdArticoleFactura(ColumnCount 15 -> 16), readonly, care afiseaza denumirea prinIif(Seek(Nvl(tvd.id_jtva_coloana,0),'crsJtvaTemp','id_jtva'),crsJtvaTemp.denumire,'')- acelasi tipar ca pe randul de rulaj. Coloana e ultima in grila, dupa Valoare: ordinea naturala e cea a indicilor, iar mutarea ei langa Taxcode ar fi cerutColumnOrderpe toate celelalte. Daca o vrei langa Taxcode, e o a doua iteratie, doar de asezare. - Text1.GotFocus pune explicit
Thisform.pccontrol = 'tvd.id_jtva_coloana'- coloana are ControlSource expresie, deciAlltrim(This.ControlSource)(tiparul celorlalte coloane) n-ar fi dat un nume de camp utilizabil. ArticoleNotaEditor.CautaExplicatieTvaapeleazacaut_explicatie_tvacu filtrul de cota calculat din linie:Round((Nvl(tvd.proc_tvav,0) - 1) * 100, 2)-proc_tvave in forma 1.21, exact catact.proc_tvala randul de nota. Cota 0/goala = lista completa.tlTipExramane gol (toate explicatiile cuid_jtva_coloana > 0), ca in ramuraElsea randului de nota; daca vrei restrangerea la TVA exigibil din JV, e un parametru in plus.- Corelarea codului SAF-T: alegerea scrie
id_jtva_coloanasiproc_tvav((cota_tva + 100) / 100), apoi cheamaUpdateExplicatieSAFTArt- metoda noua infrm_modific2024, copie a luiUpdateExplicatieSAFTRulcutvdin loc detrul(acelasiGetTaxCodeIdPart, aceeasi gardagl406). La finalcalculeaza_valori_articol, ca valoarea liniei si bara de totaluri sa urmeze noua cota.
6. Defect gasit pe drum: salvarea pierde tacut alegerile de pe liniile existente
ScrieArticoleFacturaEditate (ofacturare_editare.prg:471) actualiza liniile deja salvate
doar cu sters, cantitate, pret, pret_cu_tva. Restul campurilor apareau doar in
INSERT-ul liniilor noi. Consecinta: pe o linie existenta, codul de TVA ales din nomenclator,
gestiunea, valuta, articolul, pretul de achizitie si discountul se pierdeau la salvare fara
niciun mesaj - defect care exista inainte de explicatia TVA, nu introdus de ea.
UPDATE-ul acopera acum toate campurile pe care grila si nomenclatoarele le pot schimba:
pret_achizitie, proc_tvav, discount_unitar, id_articol, id_gestiune, id_valuta,
id_jtva_coloana, taxcode, cont.
De probat
- Total note: modifica suma pe un rand de nota -> "Total note" se schimba pe loc, iar verdictul trece pe "divergent" daca nu mai bate cu articolele.
- Cod TVA: pe pagina Articole, coloana Taxcode + butonul de modificare -> lista trebuie sa arate denumirile, nu "Memo"; cautarea "incepe cu" pe denumire trebuie sa filtreze.
- Explicatie TVA: pe o linie cu cota 21%, lista trebuie sa contina doar explicatiile de 21%; dupa alegere, coloana Taxcode se schimba singura.
- Persistenta: alege cod TVA / explicatie TVA pe o linie deja salvata, salveaza, redeschide - valorile trebuie sa fie acolo.
- Dialogul de sincronizare (document cu rulaje): capetele se schimba cand comuti directia, iar legenda rosie de jos nu mai exista.