# Fluxuri de calcul și facturare pe tipuri de prestații

Acest document descrie **lanțul complet de facturare end-to-end** pentru fiecare tip de
prestație: **Import → Calcul → Salvare → Listare**. Scopul este să nu mai fie nevoie de fiecare
dată să se caute prin cod *cum* se ajunge de la datele sursă la valoarea facturată.

Documente complementare (a NU se duplica):
- `docs/facturare.md` — fluxul general de salvare a facturii (form `frm_factura` →
  `factura_salvare_db` → `PACK_FACTURARE.pck`), structura `crsFactura`, formulele de TVA.
- `docs/cautare_vcx_vct.md` — cum se caută cod în binarele `.vcx`/`.scx`.

Constante tipuri prestații: `Include/roaacnpro.h` (string `TIP_*`, numeric `NTIP_*`).
Codul de calcul al claselor de formular stă în binarul `Clase/oacnpro.vcx`; referințele de mai jos
folosesc cache-ul TEXT `_textcache/clase/oacnpro.vc2` (vezi `docs/cautare_vcx_vct.md`).

> Notație: `fișier:linie`. Pentru clase, `oacnpro.vc2:NNNN` = `_textcache/clase/oacnpro.vc2`.

---

## 0. Convenții de rotunjire

Rotunjirile folosesc constante globale de precizie, promovate din `RoaApp` (framework COMUN):

| Constantă | Rol | Valoare uzuală |
|-----------|-----|----------------|
| `gnPC`    | precizie valori în monedă națională (lei) | 2 |
| `gnPVal`  | precizie valori în valută | 2 |
| `gnZ`     | precizie penalități (testat în cod: 2 — `proceduri_acnpro.prg:1542`) | 2 |
| `gnPCant` | precizie cantitate | (config) |
| `gnPPret` / `gnPPretV` | precizie preț unitar (lei / valută) | (config) |
| `gnPcurs` | precizie curs valutar | (config) |

Aceste constante sunt setate la inițializarea aplicației din configurația firmei (COMUN); nu sunt
hard-codate în acest repo. Acolo unde formula folosește un număr fix de zecimale (ex. `Round(..., 2)`,
`Round(..., 3)`, `Round(..., 4)`) acela este intenționat și independent de configurație.

---

## 1. IMPORT DATE (sursă RORIS)

### 1.1. Sinonime Oracle către schema `roris`
Datele sursă sunt tabele din sistemul extern **RORIS**, expuse aplicației prin **sinonime** create
în `database.txt`. Toate `ips_*` sunt sinonime spre `roris.ips_*`:

- `ips_voyages`, `ips_voyage_members`, `ips_voyage_locks` — voiaje, membrii convoiului, ecluzări
  (`database.txt:2-3,11`).
- `ips_berthings` / `ips_vberthings` — staționări la dană (cheiaj) (`database.txt:15,17`).
- `ips_cargoes`, `ips_goods`, `ips_goods_groups` — mărfuri și grupe de marfă (`database.txt:7-9`).
- `ips_routes` / `ips_vroutes`, `ips_route_points` — rute și puncte de rută (distanțe)
  (`database.txt:5,16,24`).
- `ips_vessels`, `ips_vessel_types`, `ips_vas_echivalent`, `ips_grup_tip_nave` — nave, tipuri,
  echivalențe UM, grupe de tip navă (`database.txt:4,10,13,14`).
- `ips_vas_um` — unități de măsură ale tarifelor (`database.txt:12`).
- Vederile `ips_v*` (ex. `ips_vberthings`, `ips_vvoyages`, `ips_vroute_points`) sunt versiuni
  pre-join ale acelorași date.

Tabelele proprii ale aplicației (NU sinonime): `ips_voyages_vanzari`, `ips_voyage_members_vanzari`,
`ips_regdoc`, `vanzari`, `factura`, `penalitati`, `contracte`, `ips_vtarife_tranzit`,
tarifele de cheiaj/contract.

### 1.2. Importul propriu-zis
Importul rulează ca **executabil separat** `importroris.exe` (proiect `importroris.pjx`), NU din
aplicația principală:
- Punct de intrare: `Programe/importroris_main.prg` — rulează silentios (`importroris s nnn`,
  unde `nnn` = nr. zile) sau cu formular (`Do Form importroris`) (`importroris_main.prg:32-37`).
- Importul efectiv este delegat unui **pachet Oracle**:
  `pack_acn_import.import_roris_job(?ptLastGenerationTime)` (`importroris_proceduri.prg:33`).
  Toată extragerea/normalizarea din `roris.*` în tabelele locale `ips_*` se face în pachetul PL/SQL,
  nu în VFP.

### 1.3. Câmpuri sursă relevante pentru calcul
La calcul, datele importate sunt citite din vederi de calcul:
- **Tranzit**: vederea `ips_vvoyage_members_calcul` (citită în `calcul_tranzit`,
  `proceduri_acnpro.prg:835`). Câmpuri-cheie: `distanta`, `distanta_cdmn` (km pe canal),
  `tcap` (capacitate/tone), `trn` (NRT), `lbd`, `hp`, `cuplat`, `periculos`, `procdiv`,
  `gds_id`/`gdsg_id` (marfă/grupă marfă), `vtp_id`/`vgrp_id` (tip/grupă navă), `rte_id` (rută),
  `cargo` (cantitate marfă). Schema cursorului `crsVoyages` în `proceduri_acnpro.prg:838-844`.
- **Cheiaj**: vederea `ips_vberthings` (citită în `calcul_cheiaj`, `proceduri_acnpro.prg:1023`).
  Câmpuri: `datai`/`datap` (intrare/plecare → durată), `cap`, `trn`, `lbd`, `hp`, `lung`,
  `tipn_id`, `dana_id`/`rpt_id` (dana). Schema `crsBerthings` în `proceduri_acnpro.prg:1028`.
- **Ecluzări** (tranzit): `ips_vvoyage_locks` (defalcate pe membru și cameră de ecluzare), citite
  la distribuția pe ecluze în `completeaza_regdoc_tranzit` (`proceduri_acnpro.prg:2325`).

---

## 2. CALCUL TARIFE ȘI VALORI

Calculul se face în clasele de formular din `Clase/oacnpro.vcx`. Lanțul pentru tranzit/cheiaj este:
`frm_tranzit.do_executa` → `calcul_tranzit`/`calcul_cheiaj` (umplu cursoarele din RORIS) →
formularul de calcul (`frm_calcul_tranzit` / `frm_calcul_cheiaj`) → metoda de calcul tarife.

### 2.1. TRANZIT

- **Pregătire date**: `calcul_tranzit(tcVyeIds)` — `proceduri_acnpro.prg:740`. Creează `crsVoyage`
  (convoaie) și `crsVoyages` (membrii, cu indicatorii din `ips_vvoyage_members_calcul`).
- **Calcul valoare**: clasa `frm_calcul_tranzit`, metoda **`do_executa`** —
  `oacnpro.vc2:3651-3918`.

**De unde vin tariful și cantitatea:**
- Tarifele: `IPS_VTARIFE_TRANZIT` (join cu `IPS_VVAS_UM`), selectate de DOUĂ ori:
  - tarife pe **contract** (`ctr_id = lnClientCtrId`) — `oacnpro.vc2:3688-3694` (cursor `tTarife`);
  - tarife **generale/fără contract** (`ctr_id = get_ctr_id_fara_contract()`) —
    `oacnpro.vc2:3698-3703` (cursor `tTarife2`).
- Selecția tarifului se face pe tip UM (`TC`/`TRN`/`LBD`/`HP`), încadrarea pe capacitate
  (`TCAP1/TCAP2` la capacitatea totală a convoiului, `TCCAP1/TCCAP2` la capacitatea cumulată a
  clientului), rută (`RTE_ID`) și grupă/tip marfă (`GDSG_ID`/`GDS_ID`) — `oacnpro.vc2:3750-3812`.
  Ordinea de căutare: contract+marfă → general+marfă → contract+grupă → general+grupă → "orice
  marfă" (`GDSG_ID=0`).
- Cantitatea (`cant`) depinde de UM: `TC`→`tcap`, `TRN`→`trn`, `LBD`→`lbd`, `HP`→`hp`
  (`oacnpro.vc2:3768-3795`).

**Coeficienți** (`oacnpro.vc2:3717-3727, 3861-3865`):
- `corect` (coeficient corector): pornește de la 100, +`gnACNPFmarfa` (fără marfă), +`gnIpsPCuplat`
  (necuplat), +`gnIpsPPericulos` (marfă periculoasă); apoi normalizat:
  `corect = Round(lnCoeficient/100, 3)` (`oacnpro.vc2:3861`).
- `procdiv` — coeficient suplimentar adus din sursă (`Nvl(procdiv,0)`).
- `procdist` (coeficient distanță): **km din 64.4** (lungimea canalului), plafonat la 1:
  ```
  Replace procdist With MIN(Round(Abs(distanta) / 64.4, 2), 1.00)   && oacnpro.vc2:3864
  ```

**Formula valorii pe navă** (`oacnpro.vc2:3867`):
```
valval = Round(tarif * cant * procdist * (corect + procdiv), 2)
```

**Valoare minimă / valoare finală manuală** (`oacnpro.vc2:3877-3910`):
- Suma pe convoi: `lnValoareConvoi = SUM(valval) FOR ales=1`.
- Dacă `lnValoareConvoi <= valoare_minima_convoi` (`gnIpsValoareMinConvoi`) și > 0 și nu s-a scris
  manual, valoarea finală devine valoarea minimă (`oacnpro.vc2:3883-3885`).
- Dacă utilizatorul a scris o **valoare finală** diferită, valorile se distribuie proporțional:
  ```
  Replace All VALVAL With Round(lnValoareFinala * VALVAL / lnValoareConvoi, gnPC) For ales = 1   && oacnpro.vc2:3891
  ```
  Diferența de rotunjire dintre suma recalculată și valoarea finală se pune pe primul rând
  (`oacnpro.vc2:3903-3907`). La stornare (val. finală < 0) se recalculează cantitatea
  (`oacnpro.vc2:3895`); tariful NU se recalculează (apare tariful de încadrare pe recapitulație).

**Rotunjiri tranzit:** `procdist`→2 zecimale, `corect`→3 zecimale, `valval`→2 zecimale fix;
distribuția valorii finale→`gnPC`.

### 2.2. CHEIAJ

- **Pregătire date**: `calcul_cheiaj(tcVyeIds)` — `proceduri_acnpro.prg:963`. Creează `crsVoyage`,
  `crsBerthings` (staționări din `ips_vberthings`) și `crsBerthingDetails` (prestații de facturat).
- **Calcul valoare**: clasa `frm_calcul_cheiaj`, metoda **`do_calcul_tarife`** —
  `oacnpro.vc2:1191-1375`.

**Durata** (oră → UM tarif): `lnDurata1 = Round((datap - datai)/3600, 3)` ore
(`oacnpro.vc2:1228`), apoi împărțită la `corect` pentru transformare în UM tarifului (ore sau zile)
și, dacă tariful are flag `plus`, rotunjită în sus cu `Ceiling()` (`oacnpro.vc2:1289-1292`).

**Tariful**: `crsTarifeDiverseContract` construit de `make_tarife_cheiaj_contract` cu tarifele de
contract și cele generale (`oacnpro.vc2:1215`). Încadrarea pe interval de durată:
`lim1*corect < durata AND lim2*corect >= durata`, după `ctr_id`, `id_articol`, `intern`
(`oacnpro.vc2:1247-1248`).

**Cantitatea** după UM tarif (`oacnpro.vc2:1298-1313`): `ZI`→1 (ex. cheiaj iernat),
`TC`→`cap`, `TRN`→`trn`, `ML`→`lung`, `CP`/`HP`→`hp`, `LBP`/`LBD`→`lbd`. Dacă UM conține `ZI`,
valoarea se înmulțește și cu numărul de zile (`llZile`).

**Formula valorii** (`oacnpro.vc2:1320-1345`):
- Caz simplu (fără bază): `valval = tarif * cant * IIF(llZile, durata, 1)` (`oacnpro.vc2:1342`).
- Caz cu **tarif pe tranșe** (`arebaza=1`): se cumulează tarifele tranșelor inferioare
  (`baza=1`) plus tranșa curentă pentru durata rămasă (`oacnpro.vc2:1321-1343`).
- `valval = Round(valval, gnPVal)` (`oacnpro.vc2:1345`).

**Valoare finală manuală** (`oacnpro.vc2:1356-1367`): distribuție proporțională
`Round(lnValoareFinala * valval / lnValoareConvoi, gnPVal)`, recalcul cantitate
`Round(valval/tarif, 2)`, diferența pe primul rând.

### 2.3. CHIRII (și contracte similare)

- **Calcul valoare**: clasa `frm_calcul_contract` — `oacnpro.vc2:1615`. Lucrează cu
  `crsArticoleContract` (linii introduse pe baza articolelor de contract), NU pe date RORIS.
- Metode: `calculeazapreturi` (`oacnpro.vc2:2240`) → `calculeazapreturirand`
  (`oacnpro.vc2:2248`) → `calculeazatotaluri` (`oacnpro.vc2:2267`).

**Formula** (`calculeazapreturirand`, `oacnpro.vc2:2256-2262`):
- la modificarea cantității/prețului: `valval = Round(pret * cantitate, gnPC)`;
- la modificarea valorii (recalc preț unitar): `pret = Round(valval/cantitate, 4)`.

Tariful (`pret`) provine din articolul de contract (introdus de utilizator / tarif contract);
nu există coeficient de distanță sau corecție.

### 2.4. PENALITĂȚI

- **Calcul valoare**: clasa `frm_penalitati` — `oacnpro.vc2:8366`. Metoda `do_executa`
  (`oacnpro.vc2:9671`) apelează `calcul_penalitati2` (`proceduri_acnpro.prg:1286`); varianta
  cu vânzări reale este `calcul_penalitati` (`proceduri_acnpro.prg:1166`).
- Recalcul pe o linie editată: `calcul_penalitati_linie` (`proceduri_acnpro.prg:1455`).

**De unde vin datele**: facturi/încasări din `vanzari`, `vact`, `ireg_parteneri`; cotele de
penalitate din `contracte` (`coef_penalitati`→`ppenzi`, `coef_penalitati2`→`ppenzi2`,
`zile_penalitati`→`penzile`, `zile_gratie_penalitati`→`zilegratie`)
(`proceduri_acnpro.prg:1183,1225`). Cursorul de lucru: `crsCalculPenalitati`.

**Zile de întârziere** (`proceduri_acnpro.prg:1257-1265`):
- `databaza` = `Max(datascad, sfârșit lună precedentă)` sau `datascad` (după modul de calcul);
- `dataref` = `Min(dataref, pdDataReferinta)`;
- `nr_zile = IIF(dataref - databaza <= zilegratie, 0, dataref - databaza)` (zile de grație).

**Formula penalitate, o singură cotă** (`proceduri_acnpro.prg:1266`):
```
penalitati = Round(Round(ppenzi/100*suma, gnZ) * nr_zile, gnZ)
```

**Formula penalitate, două cote** (`CalculeazaPenalitati`, `proceduri_acnpro.prg:1510-1539`):
- se împart zilele restante între cota 1 (până la `penzile2-penzile`) și cota 2 (peste);
  vezi `lnZileProcent1`/`lnZileProcent2` (`proceduri_acnpro.prg:1531-1534`).
- ```
  penalitati = Round(Round(ppenzi /100*suma, gnZ)*lnZileProcent1, gnZ)
             + Round(Round(ppenzi2/100*suma, gnZ)*lnZileProcent2, gnZ)   && proceduri_acnpro.prg:1536
  ```
- Aplicată în `calcul_penalitati` doar pentru contracte cu `ppenzi2 <> 0`
  (`proceduri_acnpro.prg:1271-1277`).

**Rotunjiri**: toate la `gnZ` (dublă rotunjire: întâi penalitatea/zi, apoi totalul). Funcția de
test cu valori așteptate: `TestCalculeazaPenalitati` (`proceduri_acnpro.prg:1541`).

### 2.5. APA / PILOTAJ / ALTE / DIVERSE

Aceste tipuri **nu au un motor de calcul propriu** bazat pe RORIS. Sunt facturate prin lanțul
generic de contract/articol:
- Calculul valorii este `pret * cantitate` (vezi 2.3 CHIRII, `frm_calcul_contract` /
  `calculeazapreturirand`, `oacnpro.vc2:2256-2262`), respectiv introducere directă pe linia de
  factură în `frm_factura` (`crsFactura`, vezi `docs/facturare.md`).
- Tariful provine din articol/contract (`ips_vprestatii_locatii`, `contracte`), nu există
  coeficienți de distanță/corecție.
- Constantele de tip: `NTIP_APA 2`, `NTIP_PILOTAJ 4`, `NTIP_ALTE 5`, `NTIP_DIVERSE 9`
  (`Include/roaacnpro.h`).
- Salvarea acestor linii se face în `ips_regdoc` prin `salvare_contract`
  (`proceduri_acnpro.prg:1918`).

---

## 3. SALVARE FACTURĂ

Fluxul general (cap factură, articole, vânzări, contabilitate) este în `docs/facturare.md`;
sursa de adevăr pentru valori/TVA este **`PACK_FACTURARE.pck`**. Aici se documentează doar
specificul fiecărui tip.

### 3.1. Lanțul comun
- `factura_acn(tcTip, loDate)` — `proceduri_acnpro.prg:3064` — orchestrarea facturii.
- `factura_salvare_db(tcTip)` — `proceduri_acnpro.prg:3290` — persistarea:
  - `pack_facturare.initializeaza_date_factura(...)` (cap factură), `adauga_articol_factura_deviz`
    (articole), `scrie_in_vanzari` (`proceduri_acnpro.prg:3343,3382,3412`);
  - reg. doc.: `pack_acn.salveaza_regdoc(...)` pentru fiecare rând din `cRegDoc`
    (`proceduri_acnpro.prg:3430`);
  - pentru TRANZIT/CHEIAJ: actualizează `ips_voyages_vanzari.vz_id` cu id-ul vânzării
    (`proceduri_acnpro.prg:3448-3451`);
  - pentru PENALITĂȚI: inserează în tabela `penalitati` (`proceduri_acnpro.prg:3475-3488`).

### 3.2. TRANZIT — specific
- `salvare_tranzit` — `proceduri_acnpro.prg:1779`:
  - inserează capul de convoi facturat în **`IPS_VOYAGES_VANZARI`** (`...:1788-1791`);
  - inserează fiecare navă în **`IPS_VOYAGE_MEMBERS_VANZARI`** cu toate valorile calculate
    (`procdist`, `corect`, `tarif`, `cant`, `valval`, `distanta`, `distanta_cdmn`, etc.)
    (`...:1794-1849`). Tranzacție manuală cu COMMIT/ROLLBACK.
- `completeaza_regdoc_tranzit(tcVVIds)` — `proceduri_acnpro.prg:2259` — **distribuția pe canale și
  ecluze**:
  - procentul CDMN al fiecărei nave: `Round(DISTANTA_CDMN / DISTANTA, 4)` (`...:2332`);
  - valori CDMN = `valval * procentCDMN`, PAMN = restul (`...:2355-2364`);
  - valori pe **senale navigabile** = valoarea CDMN/PAMN × procentul de senal
    (`100 - procente_ecluze`)/100 (`...:2369-2385`);
  - procentele pe ecluze (`AGIGEA`/`CERNAVODA`/`OVIDIU`/`NAVODARI`) din `ips_vvoyage_locks` și
    constantele `gnIPSTranzitProcAG/CV/OV/NV` (`...:2289-2324`).

### 3.3. CHEIAJ — specific
Salvarea se face tot prin `IPS_VOYAGES_VANZARI` / `IPS_VOYAGE_MEMBERS_VANZARI` (același mecanism ca
tranzit, cu `poVoyage.tip = NTIP_CHEIAJ`) și prin lanțul comun din 3.1 (`vz_id` actualizat la
`factura_salvare_db`, `proceduri_acnpro.prg:3448`). `make_factura_cheiaj`
(`proceduri_acnpro.prg:3615`) construiește linia de articol în `crsFactura`.

### 3.4. CHIRII / APA / PILOTAJ / ALTE / DIVERSE — specific
- `salvare_contract` — `proceduri_acnpro.prg:1918` — inserează în **`ips_regdoc`** (tip, articol,
  locație, valută, client, contract, preț, cantitate, valval, TVA, perioadă) (`...:1924-1953`).

### 3.5. PENALITĂȚI — specific
- `salvare_penalitati` — `proceduri_acnpro.prg:2008` — marchează înregistrările alese/șterse;
  scrierea reală în tabela `penalitati` se face în `factura_salvare_db`
  (`proceduri_acnpro.prg:3475-3488`).
- `make_factura_penalitati` — `proceduri_acnpro.prg:3775` — construiește linia de factură.

---

## 4. LISTARE FACTURĂ + RECAPITULAȚIE

Rapoartele citesc, în general, **valorile deja calculate** din tabelele de vânzări; recapitulațiile
recalculează doar agregări/distribuiri pentru afișare, nu tarife.

### 4.1. Construirea liniilor de factură (`crsFactura`)
- `make_factura_tranzit` — `proceduri_acnpro.prg:3517`: citește valorile însumate din
  **`ips_voyage_members_vanzari`** (`SUM(valval)` pe valută, `proceduri_acnpro.prg:3561-3567`),
  numele convoiului din `ips_vvoyages` și completează `crsFactura` (un singur rând, cantitate 1,
  preț = valval în monedă națională). NU recalculează tarife.
- `make_factura_cheiaj` — `proceduri_acnpro.prg:3615`: analog, pentru cheiaj.
- `make_factura_penalitati` — `proceduri_acnpro.prg:3775`.

### 4.2. Recapitulații (rapoarte `Rapoarte/*.frx`)
Procedurile de generare a cursoarelor de raport: `Programe/proceduri_acnpro_rapoarte.prg` și
proceduri din `proceduri_acnpro.prg`:
- **Recapitulație tranzit**: `listeaza_recapitulatie_tranzit` — `proceduri_acnpro.prg:5504`.
  Citește **`ips_vvoyage_members_vanzari`** `WHERE vz_id = ?pnIdVanzare`
  (`...:5515-5584`) — toate valorile (`tarif`, `cant`, `procdist`, `corect`, `valval`, `valctva`...)
  sunt deja calculate și salvate; raportul le afișează. Capacitatea totală a convoiului se
  recalculează cu fereastră `LAST_VALUE(...) OVER(PARTITION BY vms_id)` (`...:5599-5613`).
  Modul de calcul afișat (textul formulei) se generează cu `mod_calcul_tranzit`
  (`proceduri_acnpro.prg:5728`): `TARIF * CANT * %DIST * (%COR + %SUPL) = TOTAL`
  (`...:5736,5746`).
- **Recapitulație cheiaj**: `listeaza_recapitulatie_cheiaj` — `proceduri_acnpro.prg:5368`.
- **Recapitulație penalități**: `listeaza_recapitulatie_penalitati` —
  `proceduri_acnpro.prg:5777`. Din factură citește din vederea `vpenalitati`
  `WHERE id_fact_pen = ?pnIdFact` (`...:5809-5836`); din formularul de calcul (evaluare) folosește
  cursorul `crsRecapitulatie` deja calculat. Valorile penalităților NU se recalculează la listare.
- Rapoarte `.frx` asociate: `Rapoarte/factura*.frx`, `recapitulatie_tranzit`,
  `recapitulatie_cheiaj`, `recapitulatie_penalitati`, `registru tranzit`.

**Regula generală**: la listare se citesc valori **deja calculate** (din
`ips_voyage_members_vanzari`, `vpenalitati`, `ips_regdoc`/`vanzari`). Singurele recalculări la
listare sunt: textul „mod de calcul" (`mod_calcul_tranzit`) și agregările/încadrările de capacitate
pe recapitulația de tranzit.

---

## 5. Capcane cunoscute

1. **Coeficientul de distanță rotunjit la 2 zecimale poate deveni 0.**
   `procdist = MIN(Round(Abs(distanta)/64.4, 2), 1.00)` (`oacnpro.vc2:3864`). Pentru distanțe sub
   ~0.32 km (0.005 × 64.4) `Round(.../64.4, 2)` dă 0 → `valval = tarif*cant*0*(...) = 0`. Câmpul
   `PROCDIST` este `N(6,3)` în schema cursorului (`proceduri_acnpro.prg:843`) și în
   `ips_voyage_members_vanzari`, deci ar putea stoca 3 zecimale, dar **calculul rotunjește la 2**,
   nu la 3 — distanțele foarte mici se facturează cu valoare 0.

2. **Împărțire la 0 la valoarea finală.**
   La distribuirea valorii finale introduse manual:
   `Round(lnValoareFinala * VALVAL / lnValoareConvoi, gnPC)` (`oacnpro.vc2:3891`, tranzit; analog
   `oacnpro.vc2:1360`, cheiaj). Dacă valoarea convoiului calculat (`lnValoareConvoi`) este 0 (de
   ex. toate `valval=0` din cauza capcanei 1, sau tarife 0), împărțirea dă eroare/`NaN`. Codul
   protejează parțial (condiția `lnValoareConvoi > 0` la valoarea minimă, `oacnpro.vc2:3883`), dar
   ramura cu valoare finală scrisă manual (`oacnpro.vc2:3887`) nu verifică `lnValoareConvoi <> 0`
   înainte de împărțire.

3. **Tariful NU se recalculează la valoarea finală (tranzit).** Intenționat: pe recapitulație apare
   tariful de încadrare, nu cel rezultat din valoarea finală (`oacnpro.vc2:3896-3899`). Diferența
   de rotunjire ajunge pe primul rând (`oacnpro.vc2:3906`), deci `valval` al primului rând poate
   diferi de `tarif*cant*procdist*(corect+procdiv)`.

4. **Penalități — dublă rotunjire.** Formula rotunjește întâi penalitatea/zi și apoi totalul
   (`Round(Round(ppenzi/100*suma, gnZ)*nr_zile, gnZ)`, `proceduri_acnpro.prg:1266`). Pentru cele
   două cote, fiecare termen este rotunjit separat și apoi însumat (`proceduri_acnpro.prg:1536`),
   deci totalul poate să nu fie egal cu `Round(total_brut, gnZ)`.

5. **`calcul_penalitati2` folosește `ireg_parteneri` în loc de `vanzari`** (temporar, până la
   importul vânzărilor) — comentariu în cod (`proceduri_acnpro.prg:1284-1286`,
   `oacnpro.vc2:9678`). Rezultatele pot diferi de `calcul_penalitati` până la stabilizare.

6. **Distribuția CDMN depinde de `DISTANTA <> 0`.** `Round(DISTANTA_CDMN/DISTANTA, 4)`
   (`proceduri_acnpro.prg:2332`) — dacă `DISTANTA` este 0, distribuția pe canale/ecluze eșuează.
