# FACT-008 la vending: pretul de achizitie se trimite cu 3 zecimale, stocul il tine cu 4 Investigatie pe productia VENDING (tunel SSH, strict citiri). Articol reclamat: `ZAHAR STICK BRUN 4G 200BUC/SET`, `id_articol = 5155`. ## Simptom La salvarea facturii: `Articolul ZAHAR STICK BRUN 4G 200BUC/SET nu mai e in stoc! (FACT-008)`, desi articolul are 500 buc pe stoc si e in lista de preturi. ## Cauza `pack_facturare.descarca_gestiune` cauta randul din `STOC` prin egalitate exacta pe pretul de achizitie (productie, `PACK_FACTURARE` body linia **7186**, ramura `ELSE`): ```sql AND A.PRET = V_PRET_ACHIZITIE ``` Daca `BULK COLLECT` nu aduce niciun rand, se ridica FACT-008 (linia 7247). Datele din productie: | sursa | valoare | |---|---| | `STOC.PRET` (id_articol 5155, gest. 1001, cont 371, luna 8 / 2026) | **8.5586** | | `RUL` receptia din 06.08.2026 (id_rul 568464) | cant 500, valoare 4279.28 -> 4279.28/500 = 8.55856 -> **8.5586** | | `OPTIUNI.PPRET` (precizia pretului de achizitie) | **3** | Clientul VFP tine pretul corect (cursorul e definit `pret_achizitie N(20, max(gnPPret,4))`, deci 4 zecimale), dar **il serializeaza in SQL cu `gnPPret` zecimale**: - `COMUN\clase\ofacturare.vc2:14073` — `frm_facturare_articole.do_scrie_articole` - `COMUN\clase\ofacturare.vc2:18108` — `frm_facturare_articole2.do_scrie_articole` - `COMUN\programe\ofacturare_stoc.prg:360` — `adauga_articol_factura_stoc` ```foxpro Alltrim(Str(poArt.pret_achizitie,18,gnPPret)) ``` `Str(8.5586, 18, 3)` = `8.559`. In `VANZARI_DETALII_TEMP.PRET_ACHIZITIE` (NUMBER(22,6)) ajunge 8.559, iar predicatul `A.PRET = V_PRET_ACHIZITIE` compara 8.5586 cu 8.559 -> 0 randuri -> FACT-008. Verificat pe productie: ``` pret = 8.559 -> 0 randuri pret = 8.5586 -> 1 rand ``` Ramura `tip = 3` (articole fara stoc) nu salveaza situatia: `OPTIUNI.RF_FACTURARE_FARA_STOC = 0`. ## Intinderea problemei Nu e un caz izolat. In `STOC` exista **15 randuri** cu pret pe mai mult de 3 zecimale, toate in luna 8 / 2026, si **toate vor da FACT-008** la facturare: ``` 1070 CAFEA COVIM OROCREMA 1KG 42.3203 360 buc 1367 PULBERE ALBA -ADAOS BAUTURI CALDE 25.3857 120 buc 1433 ZAHAR STICK 5G 200BUC/SET 7.2072 1000 buc 1537 CONTOR VOLUMETRIC NECTA 19.8347 30 buc 1677 GARNITURA BUCSA MIXER NECTA NEW .4958 60 buc 1965 MOTOREDUCTOR GRUP CAFEA NECTA 152.0667 3 buc 2020 LAVAZZA BBE EXPERT GUSTO FORTE 55.8815 1188 buc (cants) 2057 LAVAZZA BBE EXPERT GUSTO PIENO 61.5397 396 buc 2261 FURTUN SILICONIC 6X9 6.6116 50 buc 2934 BUCSA TEFLON MIXER NECTA 4.7107 60 buc 3680 ZAHAR MARGARITAR 1 KG 3.3243 100 buc 4282 GARNITURA NECTA OR2037 WITT 9100 1.6528 60 buc 5133 ZAHAR STICK MXA 5G 100BUC/SET 3.6036 1000 buc 5155 ZAHAR STICK BRUN 4G 200BUC/SET 8.5586 500 buc ``` In `RUL`, preturile cu peste 3 zecimale apar **doar din 09.07.2026** incoace (20 randuri, ultimul 14.08.2026). Inainte de aceasta data nu exista niciunul — deci comportamentul a aparut recent, pe calea de receptie (pret unitar = valoare / cantitate, rotunjit la scale-ul coloanei `STOC.PRET`, care e 4). ## Solutii **Rapid, fara cod (productie):** `OPTIUNI.PPRET` de la 3 la 4. `Str()` incepe sa emita 4 zecimale si predicatul se potriveste. Aliniaza precizia de transport cu scale-ul real al `STOC.PRET`. **Durabil, in cod:** in cele 3 puncte de mai sus, serializarea sa foloseasca aceeasi precizie ca definitia cursorului: ```foxpro Alltrim(Str(poArt.pret_achizitie,18,Max(gnPPret,4))) ``` Nu se recomanda relaxarea predicatului in `descarca_gestiune` (`round(A.PRET, ...)`): pe gestiuni cu mai multe loturi ale aceluiasi articol ar putea potrivi randul gresit. ## Risc similar, neatins inca `pretv_orig` se trimite cu `gnPPretV` (= 2 la vending), iar `STOC.PRETV` are scale 4, cu acelasi predicat de egalitate exacta (`A.PRETV = V_PRETV_ALES`). La vending toate randurile din stoc au `pretv = 0`, deci nu se manifesta; pe o gestiune tinuta la pret de vanzare cu pret pe 3-4 zecimale ar da acelasi FACT-008. ## De unde vin zecimalele: importul eFactura din ROACONT (confirmat) Ipoteza s-a confirmat pe date. Receptia care a creat stocul articolului 5155 vine din eFactura: ``` ANAF_EFACTURA_DETALII / ANAF_EFACTURA furnizor NAVIS PROD CONCEPT SRL, NVS 1427, 06.08.2026 id_articol 5155, cantitate 500, PRET = 8.5586, VALOAREFARATVA = 4279.28 ``` Sunt **doua** surse de zecimale, ambele ocolind `gnPPret`: **1. Pretul din XML-ul furnizorului are el insusi 4 zecimale.** Cazul 5155 (8.5586) si 1433 (7.2072, NVS 1406). Se preia ca atare in `ANAF_EFACTURA_DETALII.PRET` si de acolo in NIR. **2. Importul recalculeaza pretul unitar dupa distribuirea discounturilor, cu numarul de zecimale scris in cod (4, respectiv 6), nu cu `gnPPret`** — `frm_import_efactura.importmodifica`, `D:\ROA\ROACONT\COMUN\clase\anaf_efactura.vc2`: | linie | cod | efect | |---|---|---| | 12727 | `Set pret = ROUND(ROUND(pret / lnTotalFaraTVAx, 6) * lnTotalCuTVAx, 6)` | 6 zecimale | | 12744 | `lnPret = pret - ROUND(lnDiscount / cantitate, 4)` | 4 zecimale — discount pe linie | | 12786 | `Set Pret = Round(Pret * lnProcent, 4)` | 4 zecimale — discount/transport global | Verificare pe date, cazuri unde XML-ul avea 2 zecimale si stocul a ajuns cu 4 (deci recalculul de la 12744 e cel care a produs zecimalele): | articol | XML: cant / pret / valoare | valoare/cant | `STOC.PRET` | |---|---|---|---| | 1677 GARNITURA BUCSA MIXER | 60 / 0.50 / 29.75 | 0.4958333 | **0.4958** | | 1965 MOTOREDUCTOR GRUP CAFEA | 3 / 152.07 / 456.20 | 152.066666 | **152.0667** | | 1537 CONTOR VOLUMETRIC | 30 / 19.83 / 595.04 | 19.834666 | **19.8347** | | 2934 BUCSA TEFLON MIXER | 30 / 4.71 / 141.32 | 4.7106666 | **4.7107** | Mai departe, `frm_import_efactura.importmodifica` (`anaf_efactura.vc2:12810`) duce `d.Pret` in cursorul NIR-ului **fara nicio rotunjire**, desi toate valorile vecine din acelasi `SELECT` trec prin `Round(..., gnPC)`. ### De ce rotunjirea la import nu e solutia buna Daca la import s-ar rotunji pretul la `gnPPret = 3`, pentru 5155 ar rezulta 8.559 x 500 = 4279.50, fata de valoarea reala a facturii, 4279.28 — o diferenta de 0.22 lei intre valoarea receptionata si cea care se descarca ulterior din stoc. Exact de aceea `STOC.PRET` are scale 4 si cursoarele din facturare sunt declarate `N(20, max(gnPPret,4))`. Concluzia ramane: reparatia corecta e la **transportul din facturare** (`Str(..., 18, gnPPret)` -> `Max(gnPPret,4)`), sau, ca masura imediata, `OPTIUNI.PPRET = 4`. Importul eFactura e sursa zecimalelor, dar zecimalele in sine sunt legitime. ## Al patrulea punct de emisie, in afara COMUN (ROAGEST) `D:\ROA\ROAGEST\Programe\ofactureaza.prg`, liniile **267, 268, 280**, construieste acelasi apel `pack_facturare.adauga_articol_factura(...)` cu aceeasi trunchiere (`gnPPret`, `gnPPretVal`, `gnPPretV`). E cod propriu ROAGEST, nu in `COMUN`, deci reparatia din `COMUN` nu-l acopera. Acelasi tipar, aceeasi solutie. In plus, copiile `COMUN` din ROAGEST / ROACONT / ROAACNPRO sunt in urma celei din ROAFACTURARE (`ofacturare.vc2` are acolo liniile la 13857 / 17889) — primesc reparatia la urmatorul `svn update` plus recompilare. ## Ce mai atinge PPRET, in afara transportului Nu e doar precizie de transport. Aceeasi optiune conduce: - **rotunjirea pretului unitar la NIR-ul introdus manual**: `COMUN\clase\ointroduceri.vc2`, liniile 1459, 1495, 15533, 19159 — `Round(valoare / cantitate, gnPPret)`. Deci calea manuala de receptie respecta deja `gnPPret`; doar importul eFactura o ocoleste. Cu `PPRET = 4`, si NIR-urile introduse manual vor stoca preturi cu 4 zecimale, nu 3. - **mastile de editare/afisare** ale pretului de achizitie: `ofacturare.vc2:3490`, `ofacturare_comun.vc2:1643`, `ointroduceri.vc2:10071, 16390, 19638` (`get_mask(..., gnPPret)`). De aici si concluzia despre scriptul global: dupa ce intra versiunile cu `Max(gnPPret,4)`, ridicarea lui PPRET la 4 nu mai repara nimic, dar schimba rotunjirea receptiilor manuale si afisarea la toti clientii.