#13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2. Cod: clasa noua ofacturare_util (geometrie si utilitare de formular), inrolata in roafacturare.prg; meniul "Facturare (nou)" plat, cu reparatia literalului peste limita VFP de 255 de caractere care impiedica compilarea metodei. Livrare: changelog 2.11.19, marcajul de versiune DB pentru scripturile finale din SCRIPTURI_CLAR\2026\09, inventarul livrarii in docs/livrare_13.md si registrul de erori deschise. Documentatia de lucru a etapei (cercetare, rapoarte, handoff-uri, snapshot-uri de scripturi si backup-uri de rollback) a fost scoasa din arbore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
@@ -1,337 +0,0 @@
|
||||
Cercetare S9: reemiterea unui document cu acelasi ID_FACT (SET_IDFACT + DOCUMENTE)
|
||||
====================================================================================
|
||||
|
||||
Verdict (rezumat)
|
||||
------------------
|
||||
**DA, dar cu conditii — nu e o schimbare izolata.** `SET_IDFACT` activ (`PACK_CONTAFIN.pck:3037-3040`)
|
||||
ia neconditionat un `ID_FACT` nou din `SEQ_IdFact`; niciun apelant din toata suita (~25-30 copii
|
||||
identice ale `oscrie_in_fisiere.prg`, cate una per produs) ii impune un `ID_FACT`. Varianta comentata
|
||||
(`:3016-3035`, cauta pe `NRACT+SERIE_ACT+DATAACT+ID_CTR` cu `STERS=0`) **nu rezolva S9** ca atare:
|
||||
dupa stergerea soft a documentului vechi, `STERS` e deja 1, cautarea nu-l gaseste, si cade tot pe
|
||||
secventa — plus riscul de coliziune cu un document viitor neinrudit care are aceleasi 4 campuri.
|
||||
Blocajul real nu e in `SET_IDFACT`, ci in scrierea din `DOCUMENTE`: acolo e un `INSERT` simplu
|
||||
(`:796-817`) pe `ID_DOC`, care e **PRIMARY KEY** (`PK_DOCUMENTE`, unic, `fn_script.sql:5192-5198`).
|
||||
Stergerea (`STERGE_DIN_ACT:1835-1855`) e soft-delete pur — `ACT.STERS=1`, apoi `DOCUMENTE.STERS=1`
|
||||
pentru id_fact-urile gasite pe acel `COD` — randul vechi **nu se sterge fizic**. Deci reemiterea cu
|
||||
acelasi `ID_FACT`, cu codul de azi neschimbat, ar arunca `ORA-00001` la insertul in `DOCUMENTE`,
|
||||
pentru ca randul cu acel `ID_DOC` inca exista (doar marcat `STERS=1`). Varianta `MERGE` deja
|
||||
comentata (`:818-847`) nu ajuta din prima: are doar `WHEN NOT MATCHED`, fara `WHEN MATCHED`, deci
|
||||
daca randul exista deja l-ar ignora tacit — documentul reemis ar ramane cu `DOCUMENTE.STERS=1`.
|
||||
Concluzie operationala: reutilizarea e posibila, dar cere trei schimbari simultane (detaliate la C.7),
|
||||
nu doar reactivarea codului comentat din `SET_IDFACT`.
|
||||
|
||||
A. SET_IDFACT
|
||||
--------------
|
||||
|
||||
### A.1 — Ramura activa vs. ramura comentata
|
||||
|
||||
Cod integral, `PACK_CONTAFIN.pck:3014-3040`:
|
||||
|
||||
```
|
||||
------------------------------------------------------------------------------------
|
||||
/* -- 25.02.2013 : am comentat pentru ca se face unirea id_fact pe listarea din JC/JV
|
||||
PROCEDURE SET_IDFACT(tdDataAct ACT_TEMP.DATAACT%TYPE,
|
||||
tcSerie_Act ACT_TEMP.SERIE_ACT%TYPE,
|
||||
tnNrAct ACT_TEMP.NRACT%TYPE,
|
||||
tnId_Ctr ACT_TEMP.ID_CTR%TYPE) IS
|
||||
V_ID_FACT DOCUMENTE.ID_DOC%TYPE;
|
||||
BEGIN
|
||||
BEGIN
|
||||
SELECT ID_DOC
|
||||
into pack_contafin.nIdFact
|
||||
FROM DOCUMENTE
|
||||
WHERE NRACT = tnNrAct
|
||||
AND NVL(SERIE_ACT, '+-') = NVL(tcSerie_Act, '+-')
|
||||
AND DATAACT = tdDataAct
|
||||
AND NVL(ID_CTR, 0) = NVL(tnId_Ctr, 0)
|
||||
AND STERS = 0;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
SELECT SEQ_IdFact.NEXTVAL into pack_contafin.nIdFact FROM DUAL;
|
||||
END;
|
||||
END SET_IDFACT;*/
|
||||
------------------------------------------------------------------------------------
|
||||
PROCEDURE SET_IDFACT(V_GCS IN VARCHAR2) IS
|
||||
BEGIN
|
||||
SELECT SEQ_IdFact.NEXTVAL into pack_contafin.nIdFact FROM DUAL;
|
||||
END SET_IDFACT;
|
||||
```
|
||||
|
||||
Diferenta de comportament daca s-ar reactiva varianta comentata: in loc sa genereze mereu un
|
||||
`ID_FACT` nou, ar cauta intai in `DOCUMENTE` un document **nesters** (`STERS=0`) cu aceeasi
|
||||
combinatie `NRACT + SERIE_ACT + DATAACT + ID_CTR`, si doar daca nu gaseste nimic ar cere secventa.
|
||||
Doua probleme pentru S9:
|
||||
- **nu se aplica la reemitere**: documentul vechi e deja marcat `STERS=1` inainte de rescriere
|
||||
(vezi B.6), asa ca filtrul `STERS=0` nu-l gaseste — cade tot pe `SEQ_IdFact.NEXTVAL`, exact ca azi;
|
||||
- **risc de coliziune**: daca NRACT/SERIE_ACT/DATAACT/ID_CTR ar coincide intamplator cu alt document
|
||||
nesters (nu neaparat cel pe care il reemitem), i-ar imprumuta ID_FACT-ul aceluia.
|
||||
Semnatura veche are 4 parametri de identitate diferiti de semnatura activa (1 parametru `V_GCS`,
|
||||
folosit doar ca "user"/context, nefolosit in corp) — deci reactivarea ar cere fie o supraincarcare,
|
||||
fie schimbarea semnaturii peste tot unde e chemata (vezi A.2).
|
||||
|
||||
### A.2 — Apelanti
|
||||
|
||||
**Un singur punct de apel in PL/SQL**: `PACK_CONTAFIN.pck:721`, in bucla din `SCRIE_IN_ACT`:
|
||||
|
||||
```
|
||||
pack_contafin.set_idfact(V_GCS);
|
||||
/* 25.02.2013 : se face cumularea id_fact pe listarea din RC/RJ
|
||||
PACK_CONTAFIN.SET_IDFACT(itemfact.dataact, itemfact.serie_act, itemfact.nract, itemfact.id_ctr);*/
|
||||
lnIdFact := get_idFact();
|
||||
```
|
||||
|
||||
buclat pe grupuri distincte `(NRACT, DATAACT, DATAIREG, SERIE_ACT, ID_CTR, ID_SET)` extrase din
|
||||
`ACT_TEMP WHERE ID_FACT = -1` (`:713`) — deci `-1` e sentinela "acest rand cere un `ID_FACT` nou".
|
||||
|
||||
`SCRIE_IN_ACT` insusi e apelat **doar pe drumul de scriere**, niciodata pe cel de stergere —
|
||||
in `finalizeaza_scriere_act_rul` (`:8449-8459`):
|
||||
|
||||
```
|
||||
if tnScrieSterge <> 2 then
|
||||
pack_contafin.SCRIE_IN_ACT(user);
|
||||
...
|
||||
else
|
||||
pack_contafin.STERGE_DIN_ACT(user, lnAn, lnLuna, tnCod, tnIdUtil, tnModificareNota);
|
||||
...
|
||||
```
|
||||
|
||||
Deci `SET_IDFACT` nu se atinge deloc la stergere — confirma ca azi cele doua operatii (stergere +
|
||||
reemitere) sunt independente unele de altele in privinta ID_FACT.
|
||||
|
||||
**Cine cheama `final_scriere_act_rul_local` / `SCRIE_IN_ACT` din VFP**: acelasi fisier
|
||||
`COMUN\programe\oscrie_in_fisiere.prg`, replicat identic in ~25-30 produse ROA (verificat prin grep
|
||||
pe `*.prg` in tot `D:\ROA`): `ROAFACTURARE`, `ROACONT` (output), `ROAGEST`, `ROAIMOB`, `ROAEFACTURA`,
|
||||
`ROADEVIZE`, `ROAVIN`, `ROACASA`, `ROASAL`, `ROAPRETURI`, `ROAOBINV`, `ROARESTAURANT`,
|
||||
`ROACOMENZI`, `ROAAPROV`, `ROASITOP`, `ROASITFIN`, `ROADECL`, `ROASALSPEC`, `ROABAVERT`,
|
||||
`ROACONIMPORT`, `ROAPRINT`, s.a. — plus doua variante care apeleaza `SCRIE_IN_ACT` direct, fara
|
||||
wrapper-ul local: `CONTAFIN2ORA\VFP2ORA\Programe\oscrie_in_fisiere.prg:367`,
|
||||
`ROADEFSALARII\COMUN\programe\oscrie_in_fisiere.prg:141`,
|
||||
`ROARESTAURANTCONFIG\COMUN_ROA\programe\oscrie_in_fisiere.prg:135`.
|
||||
Un al doilea import vechi (`COMUN\datemenu\xold\import_xdbf\oscrie_in_fisiere.prg`) apare in multe
|
||||
produse dar e **comentat integral** (`*!*`) — inactiv.
|
||||
|
||||
**Niciun apelant nu impune un `ID_FACT`.** Toti trimit `ID_FACT = -1` in `ACT_TEMP` (via
|
||||
`sql_temp_insert` in `oscrie_in_fisiere.prg:126-137`, care copiaza direct campurile din cursorul VFP,
|
||||
inclusiv `id_fact`) si lasa `SCRIE_IN_ACT` sa-l completeze din secventa. Confirmare suplimentara in
|
||||
`COMUN\clase\omodificari.vc2:4131-4132`: `"daca se schimba partenerul, se pune id_fact = -1 in loc
|
||||
de 0 pentru a se putea genera un nou id_fact"` — exact sentinela pe care se bazeaza bucla din
|
||||
`SCRIE_IN_ACT`.
|
||||
|
||||
### A.3 — Variabila/parametru existent pentru un ID_FACT dorit
|
||||
|
||||
**Nu exista azi.** `PACK_CONTAFIN` are o variabila de pachet `nIdFact` (setata de `SET_IDFACT`,
|
||||
citita de `GET_IDFACT`), dar e scrisa neconditionat de fiecare apel al lui `SET_IDFACT` — nu poate
|
||||
fi folosita ca "intrare" fara sa se schimbe corpul procedurii. Nu exista niciun `nid_...` global, nici
|
||||
alt parametru de sesiune care sa transmita un `ID_FACT` dorit lui `SET_IDFACT` sau lui `SCRIE_IN_ACT`.
|
||||
Ar trebui adaugata o variabila noua de pachet (ex. un "ID_FACT fortat", implicit `NULL`), citita
|
||||
**doar** in corpul activ al lui `SET_IDFACT`, consumata si resetata la prima folosire — vezi C.8.
|
||||
Acelasi diagnostic e deja notat in planul de proiect, `plan_13_unificare_formular_facturare.md:1717-1719`:
|
||||
`"ID_FACT. Se citeste inainte de stergere ... si se impune documentului nou, printr-un comutator
|
||||
folosit numai de regenerare. SET_IDFACT nu se schimba neconditionat — e cod comun intregii suite."`
|
||||
|
||||
B. DOCUMENTE la reemitere cu acelasi ID_FACT
|
||||
----------------------------------------------
|
||||
|
||||
### B.4 — INSERT sau UPDATE/MERGE azi
|
||||
|
||||
`PACK_CONTAFIN.pck:788-817`, in interiorul buclei din `SCRIE_IN_ACT`, cod activ (INSERT simplu):
|
||||
|
||||
```
|
||||
-- SCRIE IN DOCUMENTE
|
||||
lnTvaIncasare := case when itemfact.tva_incasare > 0 then 1 else 0 end;
|
||||
-- 25.02.2013 : am repus insertul pentru ca se face cumularea id_fact pe listarea din RC/RJ
|
||||
INSERT INTO DOCUMENTE
|
||||
(ID_DOC, ID_UTIL, DATAORA, TVA_INCASARE, SERIE_ACT, NRACT, DATAACT, DATAIREG, ID_CTR, ID_SET)
|
||||
VALUES
|
||||
(lnIdFact, lnID_Util, LD_DATAORA, lnTvaIncasare, itemfact.serie_act, itemfact.nract,
|
||||
itemfact.dataact, itemfact.dataireg, decode(itemfact.id_ctr, 0, NULL, itemfact.id_ctr),
|
||||
itemfact.id_set);
|
||||
/*
|
||||
-- modificare ROACONT v 2.4.0 (27.12.2012): am adaugat serie_act, nract, dataact
|
||||
-- modificare 21.02.2013: am adaugat id_ctr
|
||||
MERGE INTO DOCUMENTE A
|
||||
USING (SELECT lnIdFact as ID_DOC, itemfact.serie_act as SERIE_ACT, itemfact.nract as NRACT,
|
||||
itemfact.dataact as DATAACT,
|
||||
decode(itemfact.id_ctr, 0, NULL, itemfact.id_ctr) AS ID_CTR
|
||||
FROM DUAL) B
|
||||
ON (A.ID_DOC = B.ID_DOC)
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (ID_DOC, ID_UTIL, DATAORA, TVA_INCASARE, SERIE_ACT, NRACT, DATAACT, ID_CTR)
|
||||
VALUES (B.ID_DOC, lnID_Util, LD_DATAORA, lnTvaIncasare, B.SERIE_ACT, B.NRACT, B.DATAACT, B.ID_CTR);*/
|
||||
```
|
||||
|
||||
Deci **azi e mereu un INSERT nou** — pe drumul normal (ID_FACT vine din secventa, mereu inexistent
|
||||
in `DOCUMENTE`) asta e corect, dar pentru cazul S9 (ID_FACT reutilizat, deja existent — chiar si
|
||||
soft-sters) INSERT-ul ar da eroare de unicitate (vezi B.5). Varianta `MERGE` comentata are doar
|
||||
`WHEN NOT MATCHED` — daca s-ar reactiva neschimbata, un `ID_DOC` deja existent ar fi pur si simplu
|
||||
ignorat (fara `WHEN MATCHED`), documentul reemis ramanand cu randul vechi din `DOCUMENTE`
|
||||
(cu `TVA_INCASARE`/`ID_SET` nemodificate si, mai grav, cu `STERS` neresetat — vezi B.6).
|
||||
|
||||
### B.5 — Constrangere de unicitate pe DOCUMENTE
|
||||
|
||||
DDL gasit in `D:\ROA\DATABASE\ALTELE\Creare_server_scripturi\FirmaNoua\fn_script.sql:5162-5198`:
|
||||
|
||||
```
|
||||
CREATE TABLE "DOCUMENTE" ("ID_DOC" NUMBER(20, 0) NOT NULL ENABLE, "DATAORA" DATE NOT NULL ENABLE,
|
||||
"ID_UTIL" NUMBER(5, 0) NOT NULL ENABLE, "STERS" NUMBER(1, 0) NOT NULL ENABLE,
|
||||
"DATAORAS" DATE, "ID_UTILS" NUMBER(5, 0) NOT NULL ENABLE) ...
|
||||
...
|
||||
CREATE UNIQUE INDEX "PK_DOCUMENTE" ON "DOCUMENTE" ("ID_DOC") ...
|
||||
ALTER TABLE "DOCUMENTE" ADD CONSTRAINT "PK_DOCUMENTE" PRIMARY KEY ("ID_DOC") USING INDEX ... ENABLE
|
||||
```
|
||||
|
||||
**Da: `ID_DOC` e PRIMARY KEY, unic.** (Coloanele `SERIE_ACT/NRACT/DATAACT/DATAIREG/ID_CTR/ID_SET/
|
||||
TVA_INCASARE` din INSERT-ul de la B.4 nu apar in acest script — script vechi de firma noua,
|
||||
probabil tabela a fost alterata ulterior cu `ALTER TABLE ADD COLUMN`; constrangerea de PK insa e
|
||||
stabila si nu are motiv sa fi fost scoasa.) Un `INSERT INTO DOCUMENTE (ID_DOC=...)` cu o valoare de
|
||||
`ID_DOC` care exista deja (chiar si `STERS=1`) arunca `ORA-00001: unique constraint (PK_DOCUMENTE)
|
||||
violated`. Nu am gasit alta constrangere de unicitate pe `DOCUMENTE`; nici FK de la `ACT.ID_FACT`
|
||||
catre `DOCUMENTE.ID_DOC` (`ACT.ID_FACT` e doar indexat, `IDX_ID_FACT`, `fn_script.sql:1637`, fara
|
||||
constrangere de integritate referentiala gasita) — deci reinserarea de randuri in `ACT` cu
|
||||
`ID_FACT` reutilizat **nu** e blocata de vreo constrangere pe `ACT` insusi; blocajul e exclusiv pe
|
||||
`DOCUMENTE`.
|
||||
|
||||
### B.6 — Randurile vechi la stergere: fizic sterse, STERS=1, sau raman
|
||||
|
||||
**Soft-delete pur, pe toate cele patru tabele relevante — nimic nu se sterge fizic.**
|
||||
|
||||
`STERGE_DIN_ACT` (`PACK_CONTAFIN.pck:1815-1859`), apelata din `finalizeaza_scriere_act_rul` cand
|
||||
`tnScrieSterge = 2`:
|
||||
|
||||
```
|
||||
PROCEDURE STERGE_DIN_ACT(V_GCS VARCHAR2, tnAn in number, tnLuna in number, tnCod in number,
|
||||
tnId_utils in number, tnTip IN NUMBER) is
|
||||
-- tnTip : 0 = modificare ; 1 = stergere
|
||||
...
|
||||
BEGIN
|
||||
...
|
||||
UPDATE /*+ index(ACT IDX_COD) */ ACT
|
||||
SET STERS = 1, DATAORAS = LD_DATAORA, ID_UTILS = lnId_util
|
||||
WHERE COD = tnCod and an = tnAn and luna = tnLuna;
|
||||
|
||||
IF lnTip = 1 THEN
|
||||
UPDATE DOCUMENTE
|
||||
SET STERS = 1, ID_UTILS = LNID_UTIL, DATAORAS = LD_DATAORA
|
||||
WHERE ID_DOC IN
|
||||
(SELECT /*+ index(ACT IDX_COD) */ DISTINCT ID_FACT
|
||||
FROM ACT
|
||||
WHERE COD = tnCod and an = tnAn and luna = tnLuna
|
||||
AND ID_FACT <> 0
|
||||
and ID_SET not in (90501, 90021)
|
||||
AND NOT (SCD = '4426' AND SCC = '4428')
|
||||
AND NOT (SCD = '4428' AND SCC = '4427'));
|
||||
END IF;
|
||||
|
||||
update act_temp set suma = -suma, suma_val = -suma_val;
|
||||
END STERGE_DIN_ACT;
|
||||
```
|
||||
|
||||
`ACT` -> `STERS=1` (randurile raman fizic, pe acelasi `COD`). Cand `tnTip=1` (stergere, nu simpla
|
||||
modificare), **`DOCUMENTE` primeste si el `STERS=1`**, pentru toate `ID_FACT` distincte gasite pe
|
||||
acel `COD` in `ACT` (cu exceptiile de mai sus pentru seturi/conturi speciale). Nicaieri nu am gasit
|
||||
un `UPDATE DOCUMENTE ... SET STERS = 0` — cautare exhaustiva in `PACK_CONTAFIN.pck` (`grep -i
|
||||
"UPDATE DOCUMENTE"`) a dat un singur rezultat, cel de mai sus. Deci nu exista azi niciun mecanism
|
||||
care sa "reinvie" un rand din `DOCUMENTE`.
|
||||
|
||||
La fel, `STERGE_DIN_RUL` / `STERGE_DIN_RUL_OBINV` (`:1861-1893`) fac `UPDATE ... SET STERS = 1` pe
|
||||
`RUL`/`RUL_OBINV`, fara stergere fizica.
|
||||
|
||||
Pentru `IREG_PARTENERI` si `JV2007` situatia e diferita in mod util pentru S9: acestea nu sunt copii
|
||||
1:1 ale documentului, ci **agregate recalculate prin `MERGE`** pe chei de business (an, luna, cont /
|
||||
`ID_FDOC`, `ID_FACT`, `NRACT`, `SERIE_ACT`, `DATAACT`, `DATAIREG`, `ID_PART`, ...) — vezi
|
||||
`SCRIE_JV_2007` (`:3328-3373+`) si `SCRIE_IN_IREG_PARTENERI`/`EXECUTA_SCRIE_IN_IREG` (`:7030+`,
|
||||
`:7607+`). Ambele sunt apelate **si pe drumul de scriere, si pe cel de stergere**
|
||||
(`finalizeaza_scriere_act_rul:8495-8578`, fara conditie pe `tnScrieSterge` in afara sursei: `act_temp`
|
||||
la scriere/stergere, `act` la refacere). La stergere, `sterge_document` (`:7699-8118`) reinsereaza in
|
||||
`ACT_TEMP` copii ale randurilor vechi din `ACT`/`RUL`/`RUL_OBINV`, **cu acelasi `ID_FACT` ca inainte**
|
||||
(coloana `id_fact` e copiata direct din sursa, nu resetata la `-1`), asa ca `MERGE`-ul din
|
||||
`SCRIE_JV_2007`/`SCRIE_IN_IREG_PARTENERI` recalculeaza (compenseaza) exact randul cu acel `ID_FACT`
|
||||
— nu creeaza duplicate. Deci reutilizarea `ID_FACT`-ului **nu produce dubluri in `JV2007`/
|
||||
`IREG_PARTENERI`**; problema e strict izolata la `DOCUMENTE`.
|
||||
|
||||
Nota din plan, care confirma independent aceasta zona de risc:
|
||||
`plan_13_unificare_formular_facturare.md:1737`: `"De verificat si daca DOCUMENTE primeste un al
|
||||
doilea rand pe acelasi ID_DOC sau il refoloseste."` — raspunsul, dupa aceasta cercetare: **niciuna
|
||||
din cele doua, in starea actuala a codului — ar arunca eroare de unicitate**, nu ar produce liniste
|
||||
tacuta cu duplicat sau refolosire.
|
||||
|
||||
C. Verdictul care conteaza
|
||||
----------------------------
|
||||
|
||||
### C.7 — Se poate reemite cu acelasi ID_FACT fara sa se strice nimic?
|
||||
|
||||
**DA, dar cu conditii** — niciuna dintre ele nu e implementata azi:
|
||||
|
||||
1. **Nu folosi varianta comentata a lui `SET_IDFACT` ca atare.** Cautarea `STERS=0` nu gaseste
|
||||
documentul (deja sters soft inainte de rescriere) si e vulnerabila la coliziuni pe chei de
|
||||
business partajate cu alt document. In loc de cautare, ID_FACT-ul trebuie **citit explicit
|
||||
inainte de stergere** (VFP il are deja in cursorul documentului editat) si **transmis** pe drumul
|
||||
de scriere — exact ce zice planul S9.
|
||||
2. **`SET_IDFACT` are nevoie de o cale de intrare noua, inerta implicit.** O variabila de pachet
|
||||
noua (ex. "ID_FACT fortat", `NULL` default) + o procedura noua de setat-o explicit inainte de
|
||||
scriere; corpul activ al `SET_IDFACT` verifica intai variabila, o consuma si o reseteaza; daca e
|
||||
`NULL` (cazul general — toate celelalte ~25-30 apeluri din suita), comportamentul e identic cu
|
||||
azi (secventa). Nu se toarna in semnatura existenta `SET_IDFACT(V_GCS)`, ca sa nu se schimbe
|
||||
apelul de la niciun alt caller.
|
||||
3. **Scrierea in `DOCUMENTE` trebuie sa devina un upsert real, cu `WHEN MATCHED`.** Nici INSERT-ul
|
||||
activ, nici MERGE-ul comentat (fara `WHEN MATCHED`) nu revigoreaza un rand soft-sters. E nevoie de
|
||||
un `MERGE ... WHEN MATCHED THEN UPDATE SET STERS = 0, DATAORA = ..., ID_UTIL = ..., TVA_INCASARE
|
||||
= ..., SERIE_ACT = ..., NRACT = ..., DATAACT = ..., DATAIREG = ..., ID_CTR = ..., ID_SET = ...`
|
||||
pe langa `WHEN NOT MATCHED THEN INSERT` (cazul normal, ID_FACT nou din secventa).
|
||||
4. **Succesiunea corecta**, in aceeasi tranzactie (deja planificata in S9 la nivel de VFP — vezi
|
||||
`plan_13...md:1713-1719`, mutarea stergerii in tranzactia deschisa de scriere): sterge documentul
|
||||
vechi (soft-delete, ca azi) -> seteaza variabila de la punctul 2 cu `ID_FACT`-ul citit inainte de
|
||||
stergere -> scrie documentul nou prin drumul obisnuit (`ACT_TEMP` cu `ID_FACT = -1` ca de obicei,
|
||||
dar acum grupul respectiv va primi ID_FACT-ul fortat in loc de unul nou) -> commit doar dupa ce
|
||||
ambele operatii au avut succes; orice eroare -> rollback total, documentul vechi ramane intact.
|
||||
|
||||
- **NU** (fara aceste conditii): `INSERT INTO DOCUMENTE` cu `ID_DOC` reutilizat, cat timp randul vechi
|
||||
e inca prezent cu `STERS=1`, arunca `ORA-00001` pe `PK_DOCUMENTE` — asta e dovada, nu presupunere
|
||||
(B.5 + B.4).
|
||||
|
||||
### C.8 — Suprafata de risc pentru restul suitei
|
||||
|
||||
- **~25-30 cai de apel** trebuie sa ramana neafectate: toate copiile `COMUN\programe\
|
||||
oscrie_in_fisiere.prg` din fiecare produs ROA (listate in A.2), plus cele 3 variante care apeleaza
|
||||
`SCRIE_IN_ACT` direct. Toate trec prin acelasi punct final: `SET_IDFACT(V_GCS)` in
|
||||
`PACK_CONTAFIN.pck:3037`.
|
||||
- **Garantia structurala propusa**: variabila de pachet noua, default `NULL`/inert, citita **doar**
|
||||
in interiorul corpului activ al lui `SET_IDFACT` (nu in semnatura, nu in vreun parametru propagat
|
||||
de apelanti); se seteaza explicit **doar** de codul de regenerare din ROAFACTURARE, chiar inainte
|
||||
de a incepe scrierea documentului reemis, si se consuma/reseteaza la prima citire (fie in
|
||||
`SET_IDFACT`, fie la finalul tranzactiei, ca sa nu "scurgi" valoarea catre urmatoarea scriere
|
||||
neinrudita din aceeasi sesiune Oracle — relevant daca `goExecutor`/conexiunea e reutilizata intre
|
||||
operatii ale aceluiasi utilizator in acelasi produs). Cu default inert si citire localizata strict
|
||||
in corpul lui `SET_IDFACT`, toate celelalte ~25-30 cai raman byte-for-byte identice cu azi — nu e
|
||||
nevoie sa se verifice fiecare apelant individual, garantia e la sursa (variabila neinitializata =
|
||||
comportament vechi).
|
||||
- **Riscul real nu e in `SET_IDFACT`, ci in `DOCUMENTE`.** Schimbarea INSERT->MERGE cu `WHEN MATCHED`
|
||||
la `PACK_CONTAFIN.pck:796-817` e riscanta pentru toata suita in alt sens: `WHEN MATCHED` s-ar
|
||||
declansa doar cand `ID_DOC` (generat din secventa) coincide cu unul existent — ceea ce, pe drumul
|
||||
normal, nu se intampla niciodata (secventa e monoton crescatoare, nu se repeta), deci practic
|
||||
ramura noua e inerta pentru toti apelantii actuali si activa doar cand variabila de la C.8 a fost
|
||||
setata explicit. Totusi orice modificare la acest INSERT/MERGE e in cod comun apelat de toata
|
||||
suita si trebuie testata pe cel putin un ciclu normal de scriere (fara variabila fortata) in
|
||||
fiecare produs care scrie facturi/note, nu doar in ROAFACTURARE.
|
||||
|
||||
Ramas de verificat pe baza vie
|
||||
--------------------------------
|
||||
- Structura curenta reala a tabelei `DOCUMENTE` (DDL-ul citat e dintr-un script vechi de "firma
|
||||
noua"; coloanele `SERIE_ACT/NRACT/DATAACT/DATAIREG/ID_CTR/ID_SET/TVA_INCASARE` folosite de
|
||||
INSERT-ul activ nu apar in acel DDL — probabil adaugate ulterior prin `ALTER TABLE`). De rulat pe
|
||||
baza vie: `SELECT column_name, nullable FROM user_tab_columns WHERE table_name = 'DOCUMENTE'
|
||||
ORDER BY column_id;` si `SELECT constraint_name, constraint_type FROM user_constraints WHERE
|
||||
table_name = 'DOCUMENTE';` — sa se confirme ca `PK_DOCUMENTE` e inca activa si ca nu exista alta
|
||||
constrangere aparuta intre timp.
|
||||
- Daca exista deja documente reale in productie unde `DOCUMENTE.ID_DOC` a fost, intr-un fel sau
|
||||
altul, reutilizat (ex. printr-o interventie manuala) — de verificat cu
|
||||
`SELECT id_doc, count(*) FROM documente GROUP BY id_doc HAVING count(*) > 1;` (ar trebui sa fie
|
||||
gol, dat fiind PK-ul, dar merita confirmat inaintea oricarei schimbari).
|
||||
- Comportamentul exact al `finalizeaza_stergere_nota`/`finalizeaza_modificare_nota` (`:8601+`,
|
||||
nu au fost citate integral aici) fata de `ID_FACT`/`ID_FACTD` — relevante daca reemiterea schimba
|
||||
seria/numarul, nu doar continutul (cazul S9 "de baza" e cel mai simplu: acelasi NRACT/SERIE_ACT).
|
||||
- Comportamentul lui `EXECUTA_SCRIE_TVA`/`SCRIE_JC_2007` (mentionate la `:8504-8540`, cazul an <
|
||||
2007 sau JC) fata de reutilizarea ID_FACT — nu au fost verificate in detaliu, doar `SCRIE_JV_2007`.
|
||||
- Nu am putut testa efectiv (fara acces la baza vie) daca `ORA-00001` e chiar eroarea ridicata de
|
||||
Oracle in acest scenariu exact — e o deductie directa din DDL (PK unic + INSERT simplu pe coloana
|
||||
respectiva), dar merita o rulare de proba pe o baza de test inainte de a proiecta solutia finala.
|
||||
Reference in New Issue
Block a user