From f315aad14c6d615967f0c65add5915bdce78ab45 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Wed, 25 Mar 2026 17:15:08 +0000 Subject: [PATCH] fix: round acquisition price to 2 decimals in inventory note script 4 decimal places in STOC.PRET caused FACT-008 errors during invoicing because pack_facturare.descarca_gestiune does exact price matching. Also add pack_facturare flow analysis documentation. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/pack_facturare_analysis.md | 85 +++++++++++++++++++++++++++++++ scripts/create_inventory_notes.py | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 docs/pack_facturare_analysis.md diff --git a/docs/pack_facturare_analysis.md b/docs/pack_facturare_analysis.md new file mode 100644 index 0000000..fd36320 --- /dev/null +++ b/docs/pack_facturare_analysis.md @@ -0,0 +1,85 @@ +# pack_facturare — Invoicing Flow Analysis + +## Call chain + +1. `initializeaza_date_factura(...)` — sets `ntip`, `nluna`, `nan`, `nid_sucursala`, etc. +2. `adauga_articol_factura(...)` — inserts into `VANZARI_DETALII_TEMP` +3. `scrie_factura2(...)` — reads `VANZARI_DETALII_TEMP`, loops articles, calls `contabilizeaza_articol` +4. `contabilizeaza_articol(detalii_articol)` — for ntip<=20 (facturi), calls `descarca_gestiune` +5. `descarca_gestiune(...)` — looks up STOC and decrements + +## Key parameter mapping (adauga_articol_factura -> descarca_gestiune) + +`adauga_articol_factura` stores into `VANZARI_DETALII_TEMP`, then `contabilizeaza_articol` passes to `descarca_gestiune`: + +| descarca_gestiune param | Source in VANZARI_DETALII_TEMP | adauga_articol_factura param | +|---|---|---| +| V_ID_ARTICOL | id_articol | V_ID_ARTICOL (param 2) | +| V_SERIE | serie | V_SERIE (param 3) | +| V_PRET_ACHIZITIE | pret_achizitie | V_PRET_ACHIZITIE_TEMP (param 7) | +| V_PRETD | pretd | V_PRETD (param 8) | +| V_ID_VALUTAD | id_valutad | V_ID_VALUTAD (param 9) | +| **V_PRETV_ALES** | **pretv_orig** | **V_PRETV_ORIG (param 22)** | +| V_PRET_UNITAR | pret | V_PRET_TEMP (param 10) | +| V_PROC_TVAV | proc_tvav | calculated from JTVA_COLOANE | +| V_CANTE | cantitate | V_CANTITATE (param 14) | +| V_DISCOUNT | discount_unitar | V_DISCOUNT_UNITAR (param 15) | +| V_ID_GESTIUNE | id_gestiune | V_ID_GESTIUNE (param 6) | +| V_CONT | cont | V_CONT (param 16) | + +## descarca_gestiune STOC lookup (ELSE branch, normal invoice ntip=1) + +File: `api/database-scripts/08_PACK_FACTURARE.pck`, body around line 8326-8457. + +The ELSE branch (default for ntip=1 factura simpla) queries STOC with **exact match** on ALL these: + +```sql +WHERE A.ID_ARTICOL = V_ID_ARTICOL + AND A.ID_GESTIUNE = V_ID_GESTIUNE + AND NVL(A.CONT, 'XXXX') = V_CONT -- e.g. '371' + AND A.PRET = V_PRET_ACHIZITIE -- EXACT match on acquisition price + AND A.PRETD = V_PRETD + AND NVL(A.ID_VALUTA, 0) = DECODE(V_ID_VALUTAD, -99, 0, NVL(V_ID_VALUTAD, 0)) + AND A.PRETV = V_PRETV_ALES -- sale price (0 for PA gestiuni) + AND NVL(A.SERIE, '+_') = NVL(V_SERIE, '+_') + AND A.LUNA = pack_facturare.nluna + AND A.AN = pack_facturare.nan + AND A.CANTS + A.CANT + nvl(b.cant, 0) > a.cante + nvl(b.cante, 0) + AND NVL(A.ID_PART_REZ, 0) = NVL(V_ID_PART_REZ, 0) + AND NVL(A.ID_LUCRARE_REZ, 0) = NVL(V_ID_LUCRARE_REZ, 0) +``` + +If no rows found -> FACT-008 error ("Articolul X nu mai e in stoc!"). + +## Common FACT-008 causes + +1. **Price precision mismatch** — STOC.PRET has different decimal places than what facturare sends. Oracle compares with `=`, so `29.915 != 29.92`. **Always use 2 decimals for PRET in STOC/RUL.** +2. **PRETV mismatch** — For gestiuni la pret de achizitie (PA), STOC.PRETV should be 0. If non-zero, won't match. +3. **Wrong LUNA/AN** — Stock exists but for a different month/year than the invoice session. +4. **Wrong CONT** — e.g. stock has CONT='345' but invoice expects '371'. +5. **Wrong ID_GESTIUNE** — stock in gestiune 2 but invoicing from gestiune 1. +6. **No available quantity** — `CANTS + CANT <= CANTE` (already fully sold). + +## CASE branches in descarca_gestiune + +| Condition | Source table | Use case | +|---|---|---| +| ntip IN (8,9) | RUL (returns) | Factura de retur | +| ntip = 24 | RUL (returns) | Aviz de retur | +| ntip = nTipFacturaHotel | STOC (no cont/pret filter) | Hotel invoice | +| ntip IN (nTipFacturaRestaurant, nTipNotaPlata) | STOC + RUL_TEMP | Restaurant | +| V_CANTE < 0 with clistaid containing ':' | RUL + STOC | Mixed return+sale | +| **ELSE** (default, ntip=1) | **STOC** | **Normal invoice** | + +## lnFacturareFaraStoc option + +If `RF_FACTURARE_FARA_STOC = 1` in firma options, the ELSE branch includes a `UNION ALL` with `TIP=3` from `NOM_ARTICOLE` — allowing invoicing without stock. Otherwise, FACT-008 is raised. + +## Important: scripts inserting into STOC/RUL + +When creating inventory notes or any stock entries programmatically, ensure: +- **PRET** (acquisition price): **2 decimals** — must match exactly what facturare will send +- **PRETV** (sale price): 0 for gestiuni la pret de achizitie (PA) +- **PRETD**: match expected value (usually 0 for RON) +- **CONT/ACONT**: must match the gestiune configuration +- **LUNA/AN**: must match the invoicing period diff --git a/scripts/create_inventory_notes.py b/scripts/create_inventory_notes.py index 053aee5..b3724b1 100644 --- a/scripts/create_inventory_notes.py +++ b/scripts/create_inventory_notes.py @@ -423,7 +423,7 @@ def main(): price_info = prices.get(id_articol, {}) pret_vanzare = price_info.get("pret_vanzare", 1.30) proc_tvav = price_info.get("proc_tvav", 1.19) - pret_achizitie = round(pret_vanzare / (1 + ADAOS_PERCENT), 4) + pret_achizitie = round(pret_vanzare / (1 + ADAOS_PERCENT), 2) articles_to_insert.append({ "codmat": codmat,