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
218 lines
13 KiB
Markdown
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`.
|