#13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2. Clase: ofacturare (nucleul formularului unificat), ofacturare_comun, ferestre_cere_date, ocomenzi, caut_ora (lista de preturi in combo-urile de cautare), omodificari. Programe: ofacturare impartit - ofacturare_antet, ofacturare_rutare_scriere si ogrid_latimi sunt fisiere noi; oproceduri_facturare primeste discountul pe linie si cota standard de TVA cand articolul nu are cota pe politica. Documentatie: capcana SQLExec no_data_found, conventia de encoding, depanarea testelor VFP si regulile de lucru - conflictele cu modificarile venite din alte proiecte sunt rezolvate pastrand ambele parti. Loguri de rulare a testelor scoase din versionare; testele raman. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
50
docs/capcana_sqlexec_no_data_found.md
Normal file
50
docs/capcana_sqlexec_no_data_found.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Capcana: linii pierdute tacut intre VFP si Oracle
|
||||
|
||||
## Simptomul
|
||||
|
||||
Un document se salveaza cu mai putine linii decat are pe ecran. Fara mesaj, fara eroare, fara
|
||||
nimic in log. Totalurile ies mai mici, dar consistente intre ele - deci nu arata a defect.
|
||||
|
||||
## Mecanismul, in doi pasi
|
||||
|
||||
1. Un `SELECT ... INTO` **fara handler** intr-o procedura PL/SQL arunca `ORA-01403`
|
||||
(`NO_DATA_FOUND`) cand predicatul nu potriveste niciun rand.
|
||||
2. ODBC il traduce ca `SQL_NO_DATA`, si **`SQLExec()` intoarce 1, adica succes**. Bucla din VFP
|
||||
testeaza `If lnSucces < 0` si nu vede nimic. Linia dispare fara urma.
|
||||
|
||||
Deci: eroare reala in Oracle -> succes raportat in VFP.
|
||||
|
||||
## De ce nu potriveste predicatul (cauza uzuala)
|
||||
|
||||
Santinela pusa doar pe coloana, nu si pe parametru:
|
||||
|
||||
AND NVL(A.CONT, 'XXXX') = V_CONT
|
||||
|
||||
VFP trimite sir gol pentru campul necompletat, iar in Oracle sirul gol **este NULL**; `'XXXX' = NULL`
|
||||
da UNKNOWN, deci zero randuri. Corect e pe amandoua:
|
||||
|
||||
AND NVL(A.CONT, 'XXXX') = NVL(V_CONT, 'XXXX')
|
||||
|
||||
Pe `ID_GESTIUNE` acelasi tipar merge, fiindca acolo VFP chiar trimite santinela `-1000`.
|
||||
|
||||
Cauza inrudita, acelasi simptom: un camp lipsa din lista de insert a cursorului, pe o coloana
|
||||
numerica **fara `NULL`** - ramane `0` tacit, nu NULL si nu eroare, si predicatul cade pe `0`.
|
||||
|
||||
## Ce se face, in ordinea asta
|
||||
|
||||
1. **Intai garda, apoi cauza.** Infasoara `SELECT ... INTO` in
|
||||
`BEGIN ... EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20000, '... (FACT-0xx : ' || <cheia> || ')')`.
|
||||
Fara ea, orice reparatie de cauza ramane neverificabila: mecanismul care ascunde defectul e inca
|
||||
acolo. Codul `FACT-0xx` **se cauta liber in `USER_SOURCE`**, nu se presupune ca e liber.
|
||||
2. Abia apoi simetrizeaza predicatul.
|
||||
3. **Asertiune pe NUMARUL DE LINII** in testul de flux. Exact piesa care lipsea: identitatea
|
||||
documentului si legaturile lui se pastrau corect, deci toate asertiunile existente treceau.
|
||||
|
||||
## Cum se cauta preventiv
|
||||
|
||||
In `USER_SOURCE`: fiecare `SELECT ... INTO` fara `EXCEPTION` in ramura lui, si fiecare predicat de
|
||||
forma `NVL(<coloana>, <santinela>) = <parametru>`.
|
||||
|
||||
Precedent: `PACK_FACTURARE.adauga_articol_factura`, ramura `ntip = 4` (facturare din avize) - un
|
||||
document reemis cu 2 linii din 4, nedetectat de doua sweep-uri la rand. Reparat 04.09.2026 cu
|
||||
`FACT-030`.
|
||||
Reference in New Issue
Block a user