Files
solduri2roa/docs/raport_form_init_balanta.md
Marius Mutu 92dc8c7b32 solduri2roa: balante SAGA PDF -> xlsx initializare ROACONT
Extragere pe coordonate (pdfplumber), generarea celor doua xlsx pentru
FUNDATIA si MASTER 12/2025, regulile de mapare si rapoartele de verificare.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BdA5a3ECKFD6Citf1ptPZu
2026-09-21 00:02:30 +03:00

218 lines
13 KiB
Markdown

# Semantica importului `init_facturi_balanta_note.xlsx`
Analiza read-only. Sursa de cod: `D:\ROA\ROACONT\COMUN\ferestre\frm_initializare_facturi_balanta.sc2`
(liniile citate sunt cele din fisierul text FoxBin2Prg). Fara analize speculative.
## Fluxul
Butonul **Import** (`cmdNoteFacturiBalanta`, optiunea 1) executa in ordine:
1. `VerificaImport()` - `frm...sc2:2354`, metoda la `2292-2310`.
2. `ExportDate()` - `frm...sc2:2360`, metoda la `738-993`.
3. `Creeazanote()` - `frm...sc2:2364`, metoda la `241-733`.
4. `ModificaNote()` sau `Scrienote()` - `frm...sc2:2368-2371`.
`ExportDate` citeste xlsx-ul in cursorul `cFacturiTemp` (`frm...sc2:760-774`) si lasa in urma
cursorul `cFacturi` (`frm...sc2:825-847`). `Creeazanote` transforma `cFacturi` in `actactan`
(note in Registrul Jurnal, `id_set = 90024`, `frm...sc2:258`).
**Maparea coloanelor este positionala**, nu dupa numele din capul de tabel: `appendfromxlsx`
ia campurile cursorului cu `AFIELDS` in ordine (`appendfromxlsx.prg:111-135`) si scrie pe rand.
De aceea numele xlsx difera de numele campului:
| xlsx | cursor `cFacturiTemp` | citat |
|---|---|---|
| nume | denumire | `frm...sc2:761` (ord. camp 10) |
| numar | nract | `frm...sc2:760` (ord. 7) |
| data | dataact | `frm...sc2:760` |
| explicatia | explicatie | `frm...sc2:762` |
| **sold** | **valoare** | `frm...sc2:765` |
| **soldval** | **totval** | `frm...sc2:765` |
| **soldtvaneex** | **tva** | `frm...sc2:765` |
| **acont4428neex** | **acont4428** | `frm...sc2:765` |
Maparea sold/soldval/soldtvaneex -> valoare/totval/tva e confirmata si de codul comentat
`frm...sc2:781-799` (`sold -> valoare`, `soldtvaneex -> tva`, `soldval -> totval`).
---
## 1. Randurile TIP=BALANTA: totdeb/totcred
**Sunt SUME TOTALE cumulate** (sold initial + rulaje), nu solduri nete. In sablon:
"Total sume debitoare BALANTA" / "Total sume creditoare BALANTA" (Sheet1, rand 1). Comentariul
din fluxul inrudit o spune explicit: `TOTDEB/TOTCRED = sume totale (sold la 1 ianuarie + rulaj
precedent anual + rulaj lunar)` (`frm...sc2:1034`).
Ce face codul cu ele:
- Le transforma in cate o linie separata, nu intr-o diferenta: `totdeb as valoare` pe latura D,
`totcred as valoare` pe latura C, unite cu UNION ALL (`frm...sc2:350-356`).
- Latura (D/C) pentru BALANTA vine din union-ul de mai sus, NU din lista de la `383` (lista 401,
404, 462, 419, 408, 4551 -> C se aplica doar peste `cFacturiTemp`, care la acel moment contine
doar randuri FACTURA; `frm...sc2:381-383`).
- Nota generata: `id_fdoc = 69` (SOLD) pentru BALANTA, fata de 42 (FACTURA) (`frm...sc2:508`).
- Semnul: daca `tipDC = 'C'` -> contul intra pe credit (`pcScc = pcCont`, `pcAscc = pcAcont`);
daca `tipDC = 'D'` -> pe debit (`pcScd = pcCont`, `pcAscd = pcAcont`) (`frm...sc2:551-579`).
- **Contrapartida: goala.** Partea opusa rămâne `''` (`pcScd/pcAscd` gol pe latura C,
`pcScc/pcAscc` gol pe latura D - `frm...sc2:553-556, 567-570`). Nu exista cont de sold
initial (891/892) in cod. Nota de BALANTA este **unilaterala**, cate o linie per cont/latura.
- Suma postata = soldul BALANTA minus TVA-ul neexigibil de pe aceeasi linie (pentru BALANTA
`tva = 0`, deci suma ramane `valoare`) (`frm...sc2:493, 504-506, 531-546`).
- Daca un cont are si totdeb si totcred nenule, se genereaza doua linii distincte.
## 2. Randurile TIP=FACTURA
**Coloane obligatorii** - sablonul le declara (Sheet1, rand 1 / instructiuni): `an, luna, cont,
nr, data, nume, cod_fiscal, sold factura` (optional `facturat/achitat`), `sold TVA Neexigibil`
daca exista; "Pentru FACTURA, OBLIGATORIU completati NUME si COD FISCAL". Codul insa **nu le
valideaza explicit**; singurul filtru dur este `an` numeric nenul (`frm...sc2:846`,
`WHERE !Empty(Val(Transform(an)))`). Un rand fara `an` este ignorat tacit.
**Partenerul** se creeaza/gaseste astfel:
- `ExportDate` grupeaza randurile FACTURA dupa `denumire, cod_fiscal, reg_com` (`frm...sc2:865-869`)
si adauga mereu un partener `NEREPARTIZAT` (`frm...sc2:871-877`).
- `CompleteazaParteneriROA` (`oproceduri_import.prg:5571-5910`): normalizeaza codul
(`Upper`, fara spatii, `oproceduri_import.prg:5624`); daca lungimea <= 3, codul devine `''` si
cautarea se face **dupa denumire** (`oproceduri_import.prg:5626-5628, 5639-5650`).
- Cauta intai dupa cod exact (`5638-5641`), apoi dupa `NormalizeazaCUI` (`5643-5646`). Daca nu
gaseste, **creeaza partener nou** cu `pack_def.adauga_partener` (`5667-5717`), folosind codul
fiscal ca atare (`5677`), `tip_persoana = 1` daca lungimea < 13, altfel 2 (`5686`).
- **Nu exista validare de CUI (checksum/format).** `NormalizeazaCUI` doar face UPPER, scoate
spatiile si taie prefixul `RO` cand restul e numeric (`validare.prg:1679-1699`). Deci
`"401.00027"` rămâne `"401.00027"`; are 9 caractere (>3), este folosit ca `cod_fiscal`, iar
daca nu exista deja, creeaza un partener nou cu acest cod. **Randul nu este respins.**
- `id_part` se intoarce pe randurile FACTURA prin `Update cFacturi Set id_part ... Where
cod_fiscal = ... AND denumire = ... AND reg_com = ...` (`frm...sc2:902`).
**Documentul/nota generata**: `id_fdoc = 42` (FACTURA) (`frm...sc2:508`), o linie de valoare
(`facturat` sau `valoare`, minus TVA neexigibil) si, daca exista, o linie `ACHITAT`
(`frm...sc2:529-633`), plus notele de TVA neexigibil (`frm...sc2:650-725`). `id_fact` se ia din
`vireg_parteneri` sau din `SEQ_IdFact` (`frm...sc2:262-320`).
## 3. Legatura FACTURA <-> BALANTA
Nu se aduna si nu se verifica egalitatea; **BALANTA se reduce cu totalul facturilor**:
- Se insumeaza `facturat - achitat` pe `cont, acont, tipDC` din randurile FACTURA
(`frm...sc2:389-392`); se adauga si soldul de 4428 TVA neexigibil (`frm...sc2:395-402`).
- Pentru fiecare grupa se cauta linia BALANTA pe `cont/acont/tipDC` (`frm...sc2:411-412`) si
`REPLACE valoare WITH valoare - lnSoldFactura` (`frm...sc2:428`).
- Daca linia BALANTA nu exista, se creeaza automat una cu explicatia `DIFERENTA FACTURI` si
partener `NEREPARTIZAT` (`frm...sc2:413-426`).
- `lnSoldFactura = IIF(sold <> 0, sold, valoare)` - daca `facturat-achitat` e 0, foloseste
`SUM(valoare)` (soldul facturii) (`frm...sc2:408`).
- **Nu exista verificare de egalitate si nici eroare la diferenta**; restul rămâne sold
`NEREPARTIZAT`.
## 4. Lungimi `cont` / `acont` si combinare
- Cursorul le declara `C(20)` (`frm...sc2:760`); la iesire se aplica `PADR(ALLTRIM(...), 4, ' ')`
(`frm...sc2:826-827`), deci minim 4, fara trunchiere la 4. In baza, `CONFIG_CONT_IREG.CONT`
este `VARCHAR2(4)` (docs/config_cont_ireg.md:24). Practic, sablonul cere `cont` <= 4 si
`acont` <= 4.
- Daca celula `cont` contine un punct (`401.01`), `ExportDate` o separa: `cont = LEFT(pana la
punct)`, `acont = SUBSTR(dupa punct)`, iar `acont`-ul din coloana proprie se pastreaza daca
nu e gol (`frm...sc2:806-816`).
- In nota finala contul sintetic si analiticul sunt **campuri separate**, nu concatenate:
`scd/ascd` si `scc/ascc` (`frm...sc2:639-645`); `pcCont = ALLTRIM(cont)`,
`pcAcont = ALLTRIM(acont)` (`frm...sc2:477-478`).
## 5. Rolul `CONFIG_CONT_IREG` / `CU_INREGISTRARI`
- Se citeste `select cont, decode(fel_cont,'0','D','C') as tipdc, cu_inregistrari from
CONFIG_CONT_IREG` (`frm...sc2:435`). Pentru fiecare cont din config, pe liniile BALANTA se
forteaza partenerul `NEREPARTIZAT` (`frm...sc2:438-443`), ca sa se poata genera balanta de
parteneri.
- `cu_inregistrari = 1` marcheaza conturile cu inregistrari de partener. In `Creeazanote`, daca
linia BALANTA are cont in config, `tipdc` de config este opus laturii curente si
`cu_inregistrari = 1`, atunci pe linia opusa se pune `id_factc/id_factd = id_fact` si
`perechec/pereded = nract` (`frm...sc2:582-595`).
- Lista efectiva a conturilor cu `CU_INREGISTRARI = 1` (dump Oracle local) este in
`docs/config_cont_ireg.md:89-91` (401, 403, 404, 408, 409, 4091-4094, 4111, 4118, 413, 418,
419, 426, 4511, 4551, 456, 457, 461, 462, 471, 472, 4754, 542, 8051, plus 1621, 167, 232,
234, 261, 2678, 2691). Fluxul de initializare directa are liste echivalente hardcodate:
parteneri-balanta `401,404,408,409,4091,4092,4093,4111,418,419,461,462,4551,5311,5121,5124`
(`frm...sc2:1104`) si inregistrari-parteneri fara 5311/5121/5124 (`frm...sc2:1107`).
- Randurile FACTURA cu partener sunt deci necesare pentru conturile din `CONFIG_CONT_IREG` cu
`cu_inregistrari = 1`; BALANTA pe acele conturi primeste partener de diferenta.
## 6. Unde se completeaza `id_partd` / `id_partc`
In `Creeazanote`, dupa regula debit/credit:
- Linia de valoare: `tipDC = 'C'` -> partenerul pe credit (`pnIdPartC = id_part`,
`pnIdPartD = 0`); `tipDC = 'D'` -> pe debit (`pnIdPartD = id_part`, `pnIdPartC = 0`)
(`frm...sc2:551-579`). Motivul e in comentariu: 401 pe credit, 4111 pe debit.
- Linia `ACHITAT`: invers - `tipDC = 'C'` (furnizor) -> partener pe debit; `tipDC = 'D'`
(client) -> pe credit (`frm...sc2:597-630`).
- Liniile de TVA neexigibil: 4428 vs 401/4111, partener pe latura contului de partener
(`frm...sc2:654-678`).
- Suplimentar pentru BALANTA, pe linia opusa, `id_factc/id_factd` din config
(`frm...sc2:582-595`). Insertul in `actactan` le scrie in `id_partd/partd/id_partc/partc`
(`frm...sc2:639-645, 716-721`).
## 7. Validari care blocheaza / opresc importul (lista scurta)
- Documente deja importate: doar avertisment de confirmare, nu blocheaza
(`frm...sc2:2292-2310`, mesaj la `2355`).
- `'Nu s-a generat id_fact!'` (`frm...sc2:313`).
- `'Nu s-a gasit/generat id-ul de factura. Se opreste generarea de id-uri!'` (`frm...sc2:323`).
- `'Eroare la adaugarea in clienti ROA ...'` - opreste `CompleteazaParteneriROA`
(`oproceduri_import.prg:5711`).
- Fisier neales: `Getfile` gol -> return (`frm...sc2:751-755`).
- Rand fara `an` numeric: ignorat tacit (`frm...sc2:846`).
- Erori de citire xlsx: `'Nimic de importat'`, `'Foaie inexistenta'` (`appendfromxlsx.prg:24-45,
139-145`).
- `'Nu recunosc structura de balanta!'` - doar fluxul direct `InitBalanta` (`frm...sc2:1095`).
- Erori Oracle propagate prin `goExecutor.cEroare` (ex. `frm...sc2:292-294, 981`).
Nu exista validare de completitudine pe coloanele FACTURA (nume/cod_fiscal/numar/data).
## 8. `soldtvaneex` / `acont4428neex` / `baza..tva..`
- `soldtvaneex` -> campul cursor `tva`: soldul TVA neexigibil al facturii
(`frm...sc2:765`; mapare in codul comentat `790`).
- `acont4428neex` -> campul cursor `acont4428`: contul analitic 4428
(`frm...sc2:765`); folosit ca `ascd/ascc` pe liniile de 4428
(`frm...sc2:656-657, 670-671`).
- `baza21/tva21 ... baza20/tva20` -> `baza..tva..`: baza si TVA neexigibil pe cote
(`frm...sc2:766-772`). Cota se determina in ordinea 21, 11, 19, 9, 5, 24, 20
(`frm...sc2:679-711`), iar suma TVA-ului pe cote este `pnTottvatax` (`frm...sc2:510`).
- **Cand sunt obligatorii**: numai cand factura are TVA neexigibil (`lnTVA <> 0`,
`frm...sc2:650`). Sablonul cere explicit: "REGISTRE TVA TVA LA INCASARE. Trebuie completat
SOLD TVA NEEXIGIBIL + BAZA SI TVA NEEXIGIBIL pentru ca randul FACTURA sa aiba explicatie TVA
si sa apara in Registrele de TVA". `acont4428neex` se completeaza doar daca e nevoie.
Daca `tva = 0`, nu se genereaza nicio nota de exigibilitate.
## 9. Contul sintetic din analitice - il creeaza singur (confirmat)
- Instructiunea din sablon (Sheet1): "La tip BALANTA se completeaza DOAR CONTURILE ANALITICE,
DACA EXISTA, altfel contul sintetic (ex: 419.1 si 419.2 nu si 419). **Importul creeaza automat
contul sintetic din suma analiticelor**".
- Formularul separa `cont.acont` (`frm...sc2:806-816`) si creeaza intrarea de plan conturi
pentru analitic prin `merge into plcont` (`frm...sc2:943-986`).
- Sinteticul propriu-zis se construieste in engine, la scrierea notelor:
`PACK_CONTAFIN.SCRIE_IN_BALANTA` face `BAL` (sintetic) = `SUM(DEBIT)/SUM(CREDIT)` grupat pe
`scd/scc`, si `BALANA` (analitic) grupat pe `scd + ascd` (`ff_2026_09_09_06_COMUN_PACK_CONTAFIN.sql:6894-6957`),
apelat din `final_scriere_act_rul_local` (`...sql:8552-8553`).
- Fluxul direct `InitBalanta` o face explicit in VFP: "Balanta sintetica" = `SUM` grupat pe
`cont2` fara `acont2` (`frm...sc2:1151-1160`), insert in `bal` (`frm...sc2:1188-1200`) si
analitica in `balana` (`frm...sc2:1245-1258`).
## 10. Randul de start si numele foii
- `appendfromxlsx(m.lcFile, "cFacturiTemp", "", 2, "Sheet1", .T.)` (`frm...sc2:774`):
`lnStartRows = 2`, deci **randul 1 (capul de tabel) este sarit; citirea incepe de la randul 2**.
Sablonul o confirma: "IMPORTUL INCEPE DE LA RANDUL 2. LASATI RANDUL 1 (CAPUL DE TABEL)".
- Foaia asteptata: **`Sheet1`**, potrivita case-insensitive dupa nume in `get_sheet`
(`appendfromxlsx.prg:605-634`); in fisier `xl/workbook.xml` foaia se numeste `Sheet1`.
- Randurile de instructiuni (2-19 in sablon) sunt citite ca date dar eliminate de filtrul
`an` nenul (`frm...sc2:846`); datele reale incepand cu randul 20 in sablon.
---
## Observatii
- Ambele directii folosesc acelasi sablon `init_facturi_balanta_note.xlsx` (`frm...sc2:2258`);
optiunea 2 (initializare directa) foloseste insa `InitBalanta`/`InitFacturi`, cu alte fisiere
si alte structuri (`balanta.xlsx`, `facturi.xlsx`).
- Toate citatele de mai sus sunt din fisierul `.sc2` (text), nu din binar.
- Nu s-a modificat nimic in `D:\ROA\ROACONT`.