#13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2. Cod: clasa noua ofacturare_util (geometrie si utilitare de formular), inrolata in roafacturare.prg; meniul "Facturare (nou)" plat, cu reparatia literalului peste limita VFP de 255 de caractere care impiedica compilarea metodei. Livrare: changelog 2.11.19, marcajul de versiune DB pentru scripturile finale din SCRIPTURI_CLAR\2026\09, inventarul livrarii in docs/livrare_13.md si registrul de erori deschise. Documentatia de lucru a etapei (cercetare, rapoarte, handoff-uri, snapshot-uri de scripturi si backup-uri de rollback) a fost scoasa din arbore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
@@ -1,720 +0,0 @@
|
||||
# S8 — Proiectare: incarcarea documentului existent in formularul unificat
|
||||
|
||||
Livrabilul povestii **S8** din `docs\plan_13_unificare_formular_facturare.md:2944-2962` (etapa II,
|
||||
deciziile 5, 8, 9, 19, 35, 50). Cercetare **READ-ONLY** — zero editari de cod, zero write-back, zero
|
||||
`git_sync.ps1` / `txt2vcx.ps1`, zero commit. Pe Oracle **numai `SELECT`** pe dictionar
|
||||
(`all_tab_columns` pentru `VANZARI`, `VANZARI_DETALII`, `FACT_VFACTURI`, `FACT_VFACTURI_DETALII`).
|
||||
`COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg` (perimetrul #6) doar
|
||||
citite, neatinse.
|
||||
|
||||
**Conventie de marcare**, folosita peste tot in raport:
|
||||
- **[V]** = verificat direct pe cod / pe dictionarul Oracle, cu `fisier:linie` sau nume de coloana;
|
||||
- **[D]** = dedus din cod verificat, dar concluzia insasi n-a fost executata / observata;
|
||||
- **[N]** = nestabilit, cu motivul scris.
|
||||
|
||||
---
|
||||
|
||||
## 0. Verdict (rezumat)
|
||||
|
||||
Schita din plan — *„`completeaza_setari_document` pentru antet + `cursor_retur_document(V_COPIERE = 1)`
|
||||
pentru linii, fara degradarea de tip din `do_copiaza`"* — e corecta ca directie, dar **niciuna dintre
|
||||
cele doua piese nu incarca documentul**, si asta nu e o nuanta de implementare:
|
||||
|
||||
1. **`completeaza_setari_document(toFactura, .T.)` copiaza 16 proprietati din ~120 [V]**
|
||||
(`COMUN\programe\ofacturare_comun.prg:361-411`). Nu copiaza **niciunul** dintre cei 14 parametri de
|
||||
identitate/antet ai lui `modifica_date_factura`, in afara de `id_delegat` / `id_masina` / `id_agent`.
|
||||
Serie, numar, data, scadenta, `text_aditional`, `id_facturare`, `id_ruta`, `tip_saft`, `efactura`,
|
||||
`listare_detaliata`, `dataora_exp`, discountul de document, `discount_evidentiat`, `eproforma`,
|
||||
valuta, cursul — **toate lipsesc**. Sectiunea 1.2 le da pe toate, cu sursa.
|
||||
2. **`cursor_retur_document(V_COPIERE = 1)` nu umple gridul documentului, ci gridul-sursa.** Pe calea de
|
||||
copiere, rezultatul lui intra in `crsarticole` (selectorul din stanga), iar `crsfactura` (documentul)
|
||||
se creeaza **gol** si ramane gol — comentariul e explicit: *„Nu adaug automat articolele din factura
|
||||
originala, ca sa dau posibilitate de modificare"* (`COMUN\programe\ofacturare.prg:455-457`,
|
||||
`:338` `creeaza_facturacrs([crsfactura])`) **[V]**. Transferul in document se face **numai** prin
|
||||
`do_adauga_tot` → `do_adauga_articol`, care pentru articolele gestionabile trece prin
|
||||
**dialogul de alegere din stoc** (`do_alege_stoc`). Sectiunea 4.3.
|
||||
3. **`cursor_retur_document` nu intoarce `ID_VANZARE_DET` si nu intoarce `TAXCODE` [V]**
|
||||
(lista completa de coloane: `PACK_FACTURARE:3949-4054`). Fara `ID_VANZARE_DET`:
|
||||
- **cheia de linie presupusa de S8b (§1.2 al raportului S8b) nu exista** pe calea propusa;
|
||||
- **ruta ieftina `modifica_explicatie_articol` devine neapelabila** — primul ei parametru **este**
|
||||
`V_ID_VANZARE_DET` (`PACK_FACTURARE:14511-14519`) **[V]**.
|
||||
Fara `TAXCODE`, cerinta explicita a planului („explicatia si `taxcode` pe fiecare linie") nu e
|
||||
acoperita.
|
||||
|
||||
**Recomandarea centrala a acestei proiectari:** S8 **nu** se construieste pe perechea din schita, ci pe
|
||||
**precedentul care exista deja si face exact acest lucru** — `relisteaza_ofacturare_stoc`
|
||||
(`COMUN\programe\ofacturare_stoc.prg:456-742`) **[V]**, care reconstituie `poDate` + cursorul de linii
|
||||
dintr-un document salvat, prin `FACT_VFACTURI` (antet) + `FACT_VFACTURI_DETALII` (linii), pentru
|
||||
relistare. `FACT_VFACTURI_DETALII` **are** `ID_VANZARE_DET` si `TAXCODE` **[V]**. Detaliile,
|
||||
compromisurile si ce ramane totusi de completat — sectiunea 1.3 si 4.
|
||||
|
||||
---
|
||||
|
||||
## 1. Inventarul complet a ce se incarca, camp cu camp
|
||||
|
||||
### 1.1 Cele doua canale de citire, comparate pe coloane [V]
|
||||
|
||||
Sursa: `PACK_FACTURARE:3949-4054` (`cursor_retur_document`) si `all_tab_columns` pentru
|
||||
`FACT_VFACTURI_DETALII` / `VANZARI_DETALII`.
|
||||
|
||||
| Ce trebuie pe linie | `cursor_retur_document(V_COPIERE=1)` | `FACT_VFACTURI_DETALII` | Exista pe `VANZARI_DETALII`? |
|
||||
|---|---|---|---|
|
||||
| `ID_VANZARE_DET` (cheia liniei) | **NU** | **DA** | DA |
|
||||
| `TAXCODE` | **NU** | **DA** | DA |
|
||||
| `EXPLICATIE` | DA | DA | DA |
|
||||
| `ID_POL` (politica de pret pe linie) | DA | **NU** (doar `NUME_LISTA_PRETURI`) | DA |
|
||||
| `PRETD` / `ID_VALUTAD` | DA (`PRETD`) | **NU** | DA |
|
||||
| `GESTIONABIL` (flag calculat) | DA (calculat, vezi 1.4) | **NU** | — (derivat din `ID_GESTIUNE`) |
|
||||
| `DIFERENTA` | pliata in `PRET` (vezi 1.4) | **NU** | DA |
|
||||
| `ID_GESTIUNE`, `LOT`, `SERIE`, `CANTITATE`, `PRET`, `PRET_CU_TVA`, `PROC_TVAV`, `ID_JTVA_COLOANA`, `ID_JTVA_COLOANA_EX`, `PRET_ACHIZITIE`, `DISCOUNT_UNITAR`, `ID_VALUTA`, `CURS`, `MULTIPLICATOR` | DA | DA | DA |
|
||||
| `ID_CTR` / `NUMAR_CONTRACT` | **NU** | **DA** | DA (`ID_CTR`) |
|
||||
|
||||
**Concluzia operationala: niciunul dintre cele doua canale nu e suficient singur [V].** Cele doua
|
||||
coloane care lipsesc din `cursor_retur_document` (`ID_VANZARE_DET`, `TAXCODE`) exista **amandoua pe
|
||||
`VANZARI_DETALII`**, deci sunt disponibile fara nicio schimbare de structura — lipseste doar din lista
|
||||
`SELECT`.
|
||||
|
||||
**Trei variante, cu recomandare:**
|
||||
|
||||
| Varianta | Ce cere | Risc |
|
||||
|---|---|---|
|
||||
| **(A)** adaugarea celor doua coloane in `SELECT`-ul lui `cursor_retur_document` | doua randuri in PL/SQL, plus `A1.ID_VANZARE_DET, A1.TAXCODE` in subselectul intern | Procedura e folosita si de **copiere** si (prin `cursor_retur`) de **retur**. Coloanele in plus ajung in `crsarticole` → `Scatter Name poArticol` → si `taxcode` **s-ar gathera** in `crsfactura` (campul exista deja acolo, `creeaza_facturacrs`, `ofacturare_comun.prg:1785`) **[V]**. Adica **copierea ar incepe sa transporte `taxcode`** — probabil o corectie, dar e o **schimbare de comportament pe o cale existenta**, nu una inerta. |
|
||||
| **(B) procedura noua**, `cursor_editare_document`, clona cu cele doua coloane in plus — **RECOMANDAT** | o procedura noua in `pack_facturare`, zero atingere pe cele existente | Duplicare de SQL (~100 randuri). Costul e intretinerea, nu regresia. Garantie de regresie zero **prin constructie**, in acelasi spirit ca solutia `SET_IDFACT` din S9. |
|
||||
| **(C)** citire din `FACT_VFACTURI_DETALII` (calea `relisteaza_ofacturare_stoc`) | zero cod Oracle nou | Pierde `ID_POL`, `PRETD`/`ID_VALUTAD`, `GESTIONABIL` si tratamentul `DIFERENTA`/valuta din `cursor_retur_document` — adica exact partea grea. Ar cere refacerea ei in VFP. |
|
||||
|
||||
*Recomandare:* **(B)**, cu `SELECT`-ul copiat identic din `cursor_retur_document` plus
|
||||
`A1.ID_VANZARE_DET` si `A1.TAXCODE`, si cu ramura `GESTIONABIL` decisa explicit (1.4).
|
||||
|
||||
### 1.2 Antetul — ce se incarca, si de unde [V]
|
||||
|
||||
`poDate` e `oDateFactura` (`COMUN\programe\ofacturare_comun.prg:99-320`). Coloana „sursa" e coloana din
|
||||
`FACT_VFACTURI` (view-ul din spatele `crsFacturi`, folosit deja de `do_modifica`
|
||||
`ofacturare_comun.vc2:4560-4568` si de `relisteaza_ofacturare_stoc` `ofacturare_stoc.prg:504-509`),
|
||||
sau `VANZARI` direct.
|
||||
|
||||
Legenda coloanei „azi": **CSD** = acoperit de `completeaza_setari_document(…, .T.)`; **GOL** = nimeni
|
||||
nu-l incarca azi pe calea de copiere, deci e **gol de umplut in S8**.
|
||||
|
||||
#### (a) Identitatea documentului — antetul vizibil
|
||||
|
||||
| `poDate.` | Sursa | Azi | Nota |
|
||||
|---|---|---|---|
|
||||
| `nIdTipDoc` (FACTURA/PROFORMA/BON) | derivat din `tip` + `eproforma` | **GOL** — linia e **comentata explicit** in CSD (`ofacturare_comun.prg:366`) | vezi 3.2 |
|
||||
| `tip` | `FACT_VFACTURI.TIP` | **GOL** (si azi **degradat** de `do_copiaza`) | S8 il pastreaza, per plan |
|
||||
| `eProforma` | `FACT_VFACTURI.EPROFORMA` | **GOL** — `eproforma` nu apare deloc in `ofacturare_comun.prg` (rezultatul 1 al rundei 13) | |
|
||||
| `serie_act` | `FACT_VFACTURI.SERIE_ACT` | **GOL** (CSD il pune doar in `.descriere`, ca text) | vezi 4.2 — conflict cu `poGeneratorNumere` |
|
||||
| `nract` | `FACT_VFACTURI.NUMAR_ACT` | **GOL** (idem) | idem |
|
||||
| `dataact` | `FACT_VFACTURI.DATA_ACT` | **GOL** (`Init` pune **azi**) | |
|
||||
| `datascad` | `FACT_VFACTURI.DATA_SCAD` | **GOL** (`Init` calculeaza din `gnZileScadentaFact`) | |
|
||||
| `zi_curs` | **NU EXISTA COLOANA** — vezi 1.5 | **GOL, si nerecuperabil** | raspuns la intrebarea deschisa din S8b §5.2 |
|
||||
| `in_valuta` / `id_valuta` / `nume_valuta` | `FACT_VFACTURI.IN_VALUTA` / `ID_VALUTA` / `NUME_VAL` | **GOL** (`Init` deriva `in_valuta` din `tip`) | |
|
||||
| `Curs` / `multiplicator` | `FACT_VFACTURI.CURS` / `MULTIPLICATOR` | **GOL** | pe linii, din `VANZARI_CURSURI` |
|
||||
|
||||
#### (b) Partener si sursa
|
||||
|
||||
| `poDate.` | Sursa | Azi |
|
||||
|---|---|---|
|
||||
| `id_client` / `nume_client` | `ID_PART` / `CLIENT` | **CSD** |
|
||||
| `cod_fiscal` | `FACT_VFACTURI.COD_FISCAL` | **GOL** |
|
||||
| `sold_lei` / `sold_valuta` | recalculate la deschidere (derivate, read-only) | **GOL** — se recalculeaza, nu se restaureaza |
|
||||
| `listaid` (id comanda / contract / lista avize) | vezi 1.6 | **CSD, dar cu valoare GRESITA pentru editare** — CSD scrie `.listaid = toDateAnterior.id_vanzare` (`ofacturare_comun.prg:383`) **[V]** |
|
||||
| `descriere` (nr. comanda/contract/avize) | `FACT_VFACTURI.ALTELE` / `COMANDA` / `CONTRACT` / `AVIZE` | **CSD, dar cu serie+numarul documentului insusi**, nu al sursei (`:384`) |
|
||||
| `id_gestiune_init` | `FACT_VFACTURI.ID_GESTIUNE` | **GOL** |
|
||||
| `id_pol` / `nume_politica` | **NU EXISTA pe `VANZARI`** — doar `VANZARI_DETALII.ID_POL` | **GOL** — vezi 1.5 |
|
||||
| `id_ctr` / `contract` | `VANZARI.ID_CTR` / `VANZARI.CONTRACT` | **GOL** |
|
||||
|
||||
#### (c) Pliat — analitice (grupul A, read-only in #13, decizia 26)
|
||||
|
||||
| `poDate.` | Sursa | Azi |
|
||||
|---|---|---|
|
||||
| `id_sectie` / `sectie` | `FACT_VFACTURI.ID_SECTIE` / `SECTIE` | **CSD** |
|
||||
| `id_lucrare` / `nrord` | `ID_LUCRARE` / `LUCRARE` | **CSD** |
|
||||
| `id_responsabil` / `responsabil` | **NU EXISTA pe `VANZARI`** | **GOL, si nerecuperabil din `VANZARI`** — liniile sunt **comentate** in CSD (`:369-370`) **[V]** |
|
||||
| `id_venchelt` / `venchelt` | **NU EXISTA pe `VANZARI`** | **GOL** — idem, comentate (`:373-374`) **[V]** |
|
||||
|
||||
> Faptul ca `ID_RESPONSABIL` si `ID_VENCHELT` **nu sunt coloane pe `VANZARI`** (verificat pe
|
||||
> `all_tab_columns`) e **dovada structurala** ca grupul A traieste la nivel de **linie de nota**, nu de
|
||||
> antet — exact ce spunea `rute_scriere_antet.md`, dar acum cu argument de schema, nu de cautare. **[V]**
|
||||
|
||||
#### (d) Pliat — alte date (`frm_alte_date`) si cei 14 parametri
|
||||
|
||||
| `poDate.` | Sursa | Azi |
|
||||
|---|---|---|
|
||||
| `id_delegat` / `nume_delegat` / `BIdelegat` / `CNPdelegat` | `ID_DELEGAT` / `DELEGAT` / `BIDELEGAT` / `CNPDELEGAT` | **CSD** |
|
||||
| `id_masina` / `nrinmat` | `ID_MASINA` / `NRINMAT` | **CSD** |
|
||||
| `id_agent` / `nume_agent` | `ID_AGENT` / `NUME_AGENT` | **CSD** |
|
||||
| `id_facturare` / `adresa_facturare` | `ID_FACTURARE` / `ADRESA_FACTURARE` | **GOL** |
|
||||
| `dataora_exp` | `DATAORA_EXP` | **GOL** |
|
||||
| `text_aditional` | `TEXT_ADITIONAL` | **GOL** — plus capcana de la 1.7 |
|
||||
| `nListareDetaliata` | `LISTARE_DETALIATA` | **GOL** |
|
||||
| `tip_saft` | `TIP_SAFT` | **GOL** (`Init` pune `380`) |
|
||||
| `eFactura` | `EFACTURA` | **GOL** (`Init` pune `0`) |
|
||||
| *`id_ruta`* | `ID_RUTA` | **GOL, si nu exista proprietate pe `oDateFactura`** — vezi 1.5 |
|
||||
| `afisare_scadenta` | `AFISARE_SCADENTA` | **GOL** (`Init` pune `1`; ROACONTRACTE il recalculeaza) |
|
||||
| `tva_incasare` | `TVA_INCASARE` | **GOL** (`Init` ia `goCalendar.tva_incasare`) |
|
||||
| `institutie_publica` | `FACT_VFACTURI.INSTITUTIE_PUBLICA` | **GOL** |
|
||||
| `nTipFactura` | `TIP_FACTURA` | **GOL** |
|
||||
| `nIdBeneficiar` | `ID_BENEFICIAR` | **GOL** |
|
||||
| `id_ordl` | `ID_ORDL` | **GOL** |
|
||||
| `coeficient_k` | `VANZARI.COEFICIENT_K` | **GOL** |
|
||||
| grupul C (`ntip_incasare`, `serie_chit`, `nr_incasare`, `incasat`, `id_casa`) | `TIP_INCASAT`, `SERIE_INCASAT`, `NR_INCASAT`, `SUMA_INCASAT` | **GOL** — blocat in etapa I, dar vezi 2.3 |
|
||||
|
||||
#### (e) Discountul de document — nu e in `poDate`
|
||||
|
||||
**[V]** Discountul de document **nu are proprietate pe `oDateFactura`**: traieste in proprietatile
|
||||
formularului `frm_facturare_articole.ndiscfactron` / `.ndiscfactval`
|
||||
(`ofacturare.vc2:5286-5287` declaratie `*p:`, `:5317-5318` initializare la `0`,
|
||||
`:11325`/`:11337` `ControlSource` pe cele doua textbox-uri, `:14272-14274` citirea la scriere).
|
||||
|
||||
| Ce | Sursa | Cum se incarca |
|
||||
|---|---|---|
|
||||
| discount de document, lei | `VANZARI.DISCOUNT` (in lei cand `IN_VALUTA=0`) | `Thisform.ndiscfactron` |
|
||||
| discount de document, valuta | `VANZARI.DISCOUNT` (in valuta cand `IN_VALUTA=1`) | `Thisform.ndiscfactval`, plus `ndiscfactron = Round(ndiscfactval * Curs / multiplicator, …)` |
|
||||
| `discount_evidentiat` | `VANZARI.DISCOUNT_EVIDENTIAT` | `poDate.discount_evidentiat` (`ControlSource` la `ofacturare.vc2:11305` si `:15968`) |
|
||||
|
||||
**Precedentul exact exista** si trateaza deja bifurcatia lei/valuta:
|
||||
`ofacturare_stoc.prg:553-561` **[V]** — `lnDiscountVal = discount` cand `in_valuta = 1`, altfel
|
||||
`lnDiscount = discount`. S8 copiaza acest tipar.
|
||||
|
||||
**Atentie [V]:** `oDateFactura.Init` pune `.discount_evidentiat = IIF(TYPE('gnDiscountEvidentiat')='N',
|
||||
gnDiscountEvidentiat, 1)` (`ofacturare_comun.prg:238`) — **optiunea de firma, nu valoarea documentului**.
|
||||
Daca S8 nu suprascrie, un document emis pe alta setare apare cu discountul evidentiat altfel decat a
|
||||
fost emis, si — pentru ca `discount_evidentiat` **atinge sumele** (e parametru al lui `scrie_factura2`,
|
||||
`ofacturare.vc2:14358`) — ar declansa **regenerare la simpla deschidere**. Fals pozitiv de acelasi tip
|
||||
cu lookup-ul delegatului, dar cu efect mai scump.
|
||||
|
||||
### 1.3 Liniile — inventar
|
||||
|
||||
Coloanele intoarse de `cursor_retur_document(V_COPIERE=1)`, in ordinea din `SELECT`
|
||||
(`PACK_FACTURARE:3963-4022`) **[V]**: `ID_C` (=`ROWNUM`), `ID_ARTICOL`, `LOT`, `SERIE`, `ID_POL`,
|
||||
`ID_VALUTA`, `DISCOUNT_UNITAR`, `DISCOUNT_UNITAR_VAL`, `CODMAT`, `CODBARE`, `DENUMIRE`, `UM`,
|
||||
`GESTIONABIL`, `CANTITATE`, `PROC_TVAV`, `ID_JTVA_COLOANA`, `PRETURI_CU_TVA`, `CURS`, `MULTIPLICATOR`,
|
||||
`PRET`, `PRET_VAL`, `TIP_VALUTA`, `NUME_VAL`, `EXPLICATIE`, `ID_GESTIUNE`, `PRET_ACHIZITIE`, `PRETD`,
|
||||
`ID_JTVA_COLOANA_EX`.
|
||||
|
||||
**Lipsesc, si sunt necesare pentru S8/S8b:** `ID_VANZARE_DET`, `TAXCODE`, `ID_CTR`, `CODMATC`,
|
||||
`COD_UM_ISO`, `CONT`. Ultimele trei sunt in `crsfactura` si vin azi pe alte cai
|
||||
(`do_adauga_articol` cere `codmatf` cu un `SELECT` separat, `ofacturare.vc2:12932-12934` **[V]**).
|
||||
|
||||
### 1.4 Doua capcane in `cursor_retur_document`, ambele verificate direct
|
||||
|
||||
**(i) `GESTIONABIL` cu `V_COPIERE = 1` vine din nomenclatorul CURENT, nu din document [V]**
|
||||
(`PACK_FACTURARE:3990-3997`):
|
||||
|
||||
```
|
||||
(case when V_PROFORMA = 1 then 0
|
||||
when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE, starea de AZI
|
||||
else A.GESTIONABIL -- NVL2(A1.ID_GESTIUNE,1,0), starea DOCUMENTULUI
|
||||
end) AS GESTIONABIL
|
||||
```
|
||||
|
||||
Pentru **copiere** e corect (documentul nou se emite cu regulile de azi). Pentru **editare** e o
|
||||
divergenta tacuta: un articol care a fost facturat gestionabil si intre timp a fost trecut pe
|
||||
`IN_STOC = 0` (sau invers) se incarca cu **alt regim** decat cel cu care e scris in `VANZARI_DETALII`.
|
||||
Efectul practic: articolul trece pe alta ramura in `do_adauga_articol` (dialog de stoc vs. fara),
|
||||
deci se schimba si ce se descarca la reemitere. **Recomandare: pe calea de editare se foloseste
|
||||
`A.GESTIONABIL` (ramura `else`), adica adevarul documentului** — argument suplimentar pentru varianta
|
||||
(B) din 1.1. **Aceasta e a cincea valoare din rezultatul 6 al handoff-ului (`IN_STOC` din nomenclator),
|
||||
regasita pe calea de CITIRE, nu doar pe cea de scriere.**
|
||||
|
||||
**(ii) `PRET` vine rotunjit si cu `DIFERENTA` pliata inauntru [V]** (`PACK_FACTURARE:4008-4014`):
|
||||
`ROUND(...) + A.DIFERENTA`. Confirma rezultatul 6 din handoff. Consecinta directa pentru **S8b**:
|
||||
comparatia de pret la confirmare trebuie facuta pe **aceasta forma** (rotunjita + `DIFERENTA`), nu pe
|
||||
`VANZARI_DETALII.PRET` brut — altfel orice document cu `DIFERENTA <> 0` apare modificat la deschidere.
|
||||
|
||||
### 1.5 Trei campuri de antet care nu au unde sa fie salvate — deci nu se pot restaura [V]
|
||||
|
||||
Verificat pe `all_tab_columns` pentru `VANZARI`:
|
||||
|
||||
| Camp | Constatare | Ce inseamna pentru S8 |
|
||||
|---|---|---|
|
||||
| **`zi_curs`** | **Nu exista coloana `ZI_CURS` pe `VANZARI`.** Se stocheaza rezultatul (`CURS`, `MULTIPLICATOR`, si `VANZARI_CURSURI` pe linie), nu ziua de la care s-a luat cursul. | **Inchide intrebarea deschisa din S8b §5.2.** Nu e „S8 trebuie sa suprascrie implicitul cu valoarea salvata" — **nu exista valoare salvata**. Se incarca `Curs`/`multiplicator` din document, iar `zi_curs` **se exclude din comparatie** si (recomandat) **se ascunde pe calea de editare**, ca sa nu sugereze o valoare pe care documentul n-o are. Ascunderea are precedent in acelasi `Do Case` (`ofacturare.vc2:9720-9725`, tipurile 8 si 9). |
|
||||
| **`id_pol`** (politica de preturi, antet) | Nu exista pe `VANZARI`; exista **pe linie** (`VANZARI_DETALII.ID_POL`). | Antetul nu are ce sa afiseze ca „politica documentului". Recomandat: pe editare se afiseaza politica **doar daca e unica pe toate liniile**, altfel gol — si e oricum **blocat** (grupul B, 3.1). |
|
||||
| **`id_ruta`** | Exista pe `VANZARI` (`ID_RUTA`) si e **unul din cei 14**, dar **`oDateFactura` nu are proprietate `id_ruta`** (verificat pe lista completa de proprietati, `ofacturare_comun.prg:99-218`). Azi valoarea circula prin `poRec` (`Scatter` din `crsfacturi`), nu prin `poDate` (`ofacturare_comun.vc2:4601`). | **Proprietate noua pe `oDateFactura`**, altfel `but_modifica` (S8c) n-are de unde sa citeasca ruta. Gol de umplut, semnalat aici pentru ca S8c il presupune existent. |
|
||||
|
||||
### 1.6 Legatura cu sursa — `id_comanda`, `id_ctr`, lista de avize
|
||||
|
||||
Ce exista, verificat:
|
||||
|
||||
| Sursa | Unde e salvata | Citibila? |
|
||||
|---|---|---|
|
||||
| comanda | `VANZARI.ID_COMANDA` (+ `VANZARI.COMANDA`, text) **[V]** | **DA**, direct din `FACT_VFACTURI.ID_COMANDA` |
|
||||
| contract | `VANZARI.ID_CTR` (+ `VANZARI.CONTRACT`, text) **[V]** | **DA**, direct din `FACT_VFACTURI.ID_CTR` |
|
||||
| avize | `VANZARI_CORESP(ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP)` + `VANZARI.AVIZE` (text redundant) **[V]** (`PACK_FACTURARE:15494-15516`) | **DA ca date, NU ca procedura** — vezi mai jos |
|
||||
|
||||
**[V] Nu exista in `pack_facturare` nicio procedura care sa CITEASCA lista sursa a unui document.**
|
||||
Cele 9 aparitii ale lui `VANZARI_CORESP` in export sunt: 6 in garzile lui `sterge_factura`
|
||||
(`:5454-5530`), 1 `UPDATE ... STERS = 1` tot acolo (`:5582`), 1 subselect in
|
||||
`scrie_cantitati_vanzari_avize` (`:6319`), 1 `INSERT` in `scrie_corespondente_vanzari` (`:15494`).
|
||||
**Citirea e cod nou** — un `SELECT` simplu, dar de scris:
|
||||
|
||||
```sql
|
||||
SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP
|
||||
WHERE ID_VANZARE_FACT = :id AND STERS = 0 AND TIP = 1
|
||||
```
|
||||
|
||||
**Semantica lui `TIP` nu e stabilita in acest raport [N]** — `scrie_corespondente_vanzari(V_TIP)`
|
||||
comuta doar sursa listei (`clistaid_avize` pentru `TIP = 1`, `clistaid` altfel, `:15485-15493`), iar
|
||||
valorile efective (`1/2/3`) vin din `CASE`-ul lui `finalizeaza_factura`, necitit aici. Handoff-ul
|
||||
rundei 13 le da ca `1/2/3` folosite, `4` liber. **De confirmat ramura cu ramura la implementare**, nu
|
||||
de preluat din raport — e exact tiparul care a produs cifra gresita a rundei 13.
|
||||
|
||||
**Nota de proiectare:** `poDate.listaid` e **suprasolicitat**. Pe calea de copiere/editare el trebuie sa
|
||||
fie `id_vanzare`-ul documentului (ca `cursor_retur_document` sa-i citeasca liniile), dar pentru
|
||||
reemitere `pack_facturare.clistaid` / `clistaid_avize` trebuie sa contina **lista sursei originale**.
|
||||
Sunt **doua valori diferite in acelasi camp**, la momente diferite. Precedentul din
|
||||
`relisteaza_ofacturare_stoc` arata ca problema e veche si **nerezolvata**: acolo
|
||||
`poDate.listaid = Iif(poDate.tip = 3, Alltrim(Str(id_comanda)), [0])` **[V]**
|
||||
(`ofacturare_stoc.prg:531`) — cu ramura de **contract comentata** la `:529`, deci nici acel precedent
|
||||
nu restaureaza sursa pentru contracte sau avize. **S8 are nevoie de un camp separat**
|
||||
(propunere: `poDate.cListaSursa` + `poDate.cListaSursaAvize`), nu de o a doua semnificatie a lui
|
||||
`listaid`. Vezi si sectiunea 6.
|
||||
|
||||
### 1.7 `text_aditional` — trei transformari intre ce se vede si ce se salveaza [V]
|
||||
|
||||
1. **Truncat la 100 de caractere** la scriere: `LEFT(Nvl(poDate.text_aditional,[]),100)`
|
||||
(`ofacturare.vc2:14356`, identic pe toate ramurile `scrie_*`).
|
||||
2. **`CR+LF` inlocuit cu `Chr(170)`** imediat inainte:
|
||||
`poDate.text_aditional = Strtran(poDate.text_aditional, Chr(13)+Chr(10), Chr(170), 1, 100, 1)`
|
||||
(`:14281`) — **si atribuirea e pe `poDate` insusi**, deci obiectul ramane modificat dupa scriere.
|
||||
3. Pe calea `modifica_date_factura` **nu exista** nici truncare, nici substitutie
|
||||
(`ofacturare_comun.vc2:4608` trimite `?poRec.text_aditional` ca parametru legat) **[V]** —
|
||||
deci **cele doua rute salveaza forme diferite ale aceluiasi camp**.
|
||||
|
||||
**Consecinte pentru S8:** la incarcare, `Chr(170)` trebuie convertit inapoi in `CR+LF` (altfel textul
|
||||
apare pe un rand cu caractere ciudate), iar comparatia din S8b trebuie facuta pe forma **normalizata**
|
||||
(vezi 5.2). Fara asta, orice document emis cu text pe mai multe randuri apare „modificat" la
|
||||
deschidere. **Nesemnalat pana acum in niciun raport.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Initializarile „pentru document nou" care trebuie sarite la editare
|
||||
|
||||
Cerinta obligatorie din S8b, rezultatul 5, plus inventarul cerut de briefing.
|
||||
|
||||
### 2.1 Lookup-ul „ultimul delegat / ultima masina" — **garda exista deja** [V]
|
||||
|
||||
`frm_alte_date.Init`, `COMUN\clase\ferestre_cere_date.vc2:3105-3208`. Codul real
|
||||
(`:3110-3136`) — si aici raportul S8b si planul descriu situatia **incomplet**:
|
||||
|
||||
```
|
||||
If poDate.eProforma = 0
|
||||
If Empty(Nvl(poDate.id_delegat,0)) And Empty(Nvl(poDate.id_masina,0)) && :3111
|
||||
poDate.id_delegat = 0
|
||||
poDate.id_masina = 0
|
||||
... cauta_date_ultima_factura[_tip](...) && :3118-3124
|
||||
```
|
||||
|
||||
**Lookup-ul e deja conditionat de „ambele goale".** Deci:
|
||||
|
||||
- pentru un document care **are** delegat sau masina salvate, e suficient ca **S8 sa populeze
|
||||
`poDate.id_delegat` / `id_masina` INAINTE de construirea lui `frm_alte_date`** — lookup-ul nu mai
|
||||
ruleaza, fara niciun cod nou. `completeaza_setari_document` le pune deja (1.2.d), deci pe calea de
|
||||
editare conditia e indeplinita **din ordinea de apel**, nu dintr-un semnal;
|
||||
- **riscul real ramane, dar e mai ingust decat il descrie S8b:** el se manifesta **exact pe documentele
|
||||
care n-au nici delegat, nici masina salvate** — un caz frecvent (multe facturi se emit fara delegat).
|
||||
Pentru acelea, lookup-ul umple `poDate` cu ultimul delegat al clientului, si atunci: ori documentul
|
||||
apare modificat, ori `modifica_date_factura` scrie **un delegat pe care documentul nu l-a avut
|
||||
niciodata**. Sub `modifica_date_factura` campul se scrie **neconditionat** (`ID_DELEGAT = V_ID_DELEGAT`,
|
||||
`PACK_FACTURARE:14462`) **[V]**, deci scrierea gresita e certa, nu probabila.
|
||||
|
||||
**Mecanismul propus (minim, si in acord cu tiparul existent):** parametru nou pe `frm_alte_date.Init`
|
||||
sau — mai ieftin si mai greu de ratat — **o proprietate pe `poDate`**, `poDate.lEditare`, citita in
|
||||
conditia de la `:3111`:
|
||||
|
||||
```
|
||||
If !poDate.lEditare And Empty(Nvl(poDate.id_delegat,0)) And Empty(Nvl(poDate.id_masina,0))
|
||||
```
|
||||
|
||||
Argumentul pentru proprietate pe `poDate` si nu parametru: `frm_alte_date` **nu e singurul** formular
|
||||
care are initializari de acest tip (2.2), `poDate` e deja obiectul citit de toate, si e acelasi tipar
|
||||
cu `lCopiere`, care exista deja pe `oDateFactura` (`ofacturare_comun.prg:212`) **[V]**.
|
||||
|
||||
**„Ce se intampla cand documentul chiar n-are delegat salvat":** cu garda de mai sus, `poDate.id_delegat`
|
||||
ramane `.NULL.` (valoarea implicita din declaratia de clasa), campul se afiseaza gol, iar la salvare
|
||||
`modifica_date_factura` primeste `NULL` si scrie `NULL` — **identic cu starea din baza**. Adica exact
|
||||
comportamentul dorit: documentul ramane cum a fost. Fara garda, valoarea devine `0` (atribuirea de la
|
||||
`:3112-3113`) **si apoi** rezultatul lookup-ului.
|
||||
|
||||
> **Diferenta fata de S8b, spusa explicit:** S8b cerea „sarirea explicita a lookup-ului"; codul real
|
||||
> arata ca sarirea e **deja implicita** pentru documentele cu delegat, si e **necesara explicit** doar
|
||||
> pentru cele fara. Concluzia lui S8b (S8 trebuie sa faca ceva) ramane valida; **motivul si perimetrul
|
||||
> se schimba**, iar asta reduce riscul de la „primul document editat al unui client cu activitate
|
||||
> recenta" la „primul document **fara delegat** al unui client cu activitate recenta".
|
||||
|
||||
### 2.2 Alte initializari de acelasi tip — inventar cu `fisier:linie` [V]
|
||||
|
||||
Cautate in `oDateFactura.Init`, `frm_alte_date.Init`, `frm_date_factura.Init`, `frm_date_aviz.Init`.
|
||||
|
||||
| # | Loc | Ce face | Efect pe calea de editare | Gravitate |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `ofacturare_comun.prg:232-236` | `.Data`, `.dataireg`, `.dataact` = azi (sau ultima zi a lunii de lucru); `.datascad` din `gnZileScadentaFact`; `.zi_curs` = azi | Documentul apare cu **data de azi** si scadenta recalculata | **Mare** — atinge 2 din cei 4 campuri de identitate |
|
||||
| 2 | `ofacturare_comun.prg:238` | `.discount_evidentiat` = `gnDiscountEvidentiat` (optiune de firma) | Vezi 1.2.e — poate declansa **regenerare** la simpla deschidere | **Mare** |
|
||||
| 3 | `ofacturare_comun.prg:233` | `.tva_incasare` = `goCalendar.tva_incasare` (starea de azi a firmei) | Un document emis in alt regim se incarca cu regimul curent | Medie |
|
||||
| 4 | `ofacturare_comun.prg:237` | `.in_valuta = 1` pentru `tnIdSet` / `tnTip` din lista | Derivat din tip, nu din document — coincide de obicei, dar nu prin constructie | Mica |
|
||||
| 5 | `ofacturare_comun.prg:241-243` | `.initializeaza_politica_pret()` pentru tipurile 23, 30, 41 — apel `actualizeaza_politica_pret` | Politica **curenta**, nu cea a documentului | Medie (tipuri de transfer) |
|
||||
| 6 | `ofacturare_comun.prg:240` | `.initializeaza_setari_document()` → `actualizeaza_document(tip)` → `id_fdoc` / `fdoc` | Reconfigureaza tipul de document din setarile curente | Medie |
|
||||
| 7 | `ofacturare_comun.prg:245-283` | ramura **ROACONTRACTE** (`goContract`): suprascrie `id_client`, `nume_client`, `cod_fiscal`, `listaid`, `descriere`, `id_sectie`, `id_responsabil`, `id_valuta`, **si `.datascad = .dataact + lnScadentaIncasare`**, **si `.afisare_scadenta`** | Daca `goContract` exista in sesiune, **suprascrie antetul documentului editat cu datele contractului** | **Mare**, conditionata de context |
|
||||
| 8 | `ofacturare_comun.prg:288-316` | ramura **ROACOMENZI** (`goComanda`, `tnTip = 3`): idem, `id_client`, `listaid`, `descriere`, `id_sectie`, `sectie` | Idem | **Mare**, conditionata |
|
||||
| 9 | `ferestre_cere_date.vc2:3177-3179` | `If This.opt_incasat.Value = 2 → poDate.incasat = poDate.totalctva` | Suprascrie suma incasata cu totalul documentului | Medie (grup C, blocat in etapa I) |
|
||||
| 10 | `ferestre_cere_date.vc2:3166-3171` | `poDate.id_casa = gnid_part_casa` (casa implicita a firmei) | Suprascrie casa documentului | Medie (grup C) |
|
||||
| 11 | **`ferestre_cere_date.vc2:3183-3185`** | `IF poDate.tip = 2 AND poDate.afisare_scadenta = 0 AND AT([Scadenta la ], poDate.text_aditional) = 0` → **prefixeaza** `text_aditional` cu `„Scadenta la N zile."` | **A doua instanta a exact aceluiasi defect ca lookup-ul delegatului**, si pe un camp din cei 14: modifica `text_aditional` la `Init`, fara actiune a utilizatorului | **Mare** |
|
||||
| 12 | `ferestre_cere_date.vc2:3150` | `If poDate.incasat <> 0 → Thisform.opt_incasat.Value = 2` — atribuire programatica pe `opt_incasat` | Declanseaza `ProgrammaticChange` → `actualizeaza_tipincasare()` → alocare/dezalocare de numere de chitanta (riscul deja documentat in `s3b_alte_date_analitice.md` §4.3) | Medie |
|
||||
| 13 | `ofacturare.prg:207-209` | `poGeneratorNumere.ResetNumere()` + `creeaza_cursor_serii(nIdTipDoc)`, la fiecare trecere prin `factureaza` | **Aloca un numar nou** pe calea de emitere | **Mare** — vezi 4.2 |
|
||||
| 14 | `ofacturare.prg:184-193` | `Do Case` pe `tnTip` care forteaza `poDate.nIdTipDoc` (5 = FACTURA / 6 = AVIZ) **inainte** de `completeaza_setari_document` | Pe editare, `nIdTipDoc` trebuie sa vina din document (proforma = 23, bon = 3), nu din tip | Medie |
|
||||
|
||||
**Nr. 11 merita subliniat**: garda lui (`AT([Scadenta la ], text_aditional) = 0`) il face inert pe un
|
||||
document de contract emis **cu acelasi numar de zile de scadenta**. Devine activ exact cand
|
||||
scadenta s-a schimbat de la emitere — adica precis cazul in care textul e cel vechi si trebuie
|
||||
pastrat. **Metoda `Destroy`/`Unload` face si operatia inversa** (`:3037-3038`: `Strtran(...,[])`),
|
||||
ceea ce inseamna ca pe calea normala prefixul e adaugat si scos in aceeasi sesiune; pe o cale de
|
||||
editare care **nu** trece prin acelasi `Unload`, prefixul ar ramane. **[D]** — n-am urmarit toate
|
||||
caile de iesire ale formularului.
|
||||
|
||||
### 2.3 Regula generala propusa
|
||||
|
||||
> **Orice camp al lui `poDate` populat prin apel Oracle sau dintr-o variabila globala/`go*` in
|
||||
> `Init`/`Load` e o sugestie pentru document nou, nu o valoare de document.** Pe calea de editare,
|
||||
> ordinea trebuie sa garanteze ca aceste sugestii **nu ajung sa se execute** (garda), nu doar ca sunt
|
||||
> **suprascrise dupa** (ceea ce ar merge pentru valori, dar **nu** pentru efectele secundare — nr. 12
|
||||
> si nr. 13 aloca numere, nu doar seteaza campuri).
|
||||
|
||||
---
|
||||
|
||||
## 3. Ce se blocheaza la editare, si de ce
|
||||
|
||||
### 3.1 Blocate — schimbarea lor ar insemna alt document
|
||||
|
||||
| Camp / control | De ce | Ruta care ar lipsi oricum |
|
||||
|---|---|---|
|
||||
| **Tipul documentului** (`Ct_clb_fdoc`, `poDate.tip` / `nIdTipDoc`) | Tipul decide ce sursa se consuma, ce nota se scrie si ce garzi se aplica. `do_copiaza` il **degradeaza** tocmai pentru ca un document copiat nu mai poate reconsuma sursa (`ofacturare_comun.vc2:3694-3711`) **[V]**; la editare degradarea e interzisa prin plan, deci tipul e fix. | grupul B — nicio ruta de scriere pe loc |
|
||||
| **Sursa** (`Ct_clb_altele`) | Vezi 3.2 | grupul B |
|
||||
| **Clientul** (`Ct_clb_nume_client`) | Schimbarea partenerului rescrie `IREG_PARTENERI`, `ACT`, soldurile — alt document | grupul B |
|
||||
| **Valuta, `zi_curs`, gestiunea sursa, politica de preturi** | grupul B, decizia 25; in plus `zi_curs` si `id_pol` **n-au valoare salvata** (1.5) | grupul B |
|
||||
| **Grupul C** (incasare) | decizia 25; in plus `opt_incasat` are efect secundar de alocare (2.2 nr. 12) | grupul C |
|
||||
| **Grupul A** (venit/cheltuiala, sectie, responsabil, lucrare) | decizia 26 — read-only permanent in #13; in plus doua din patru **nu exista pe `VANZARI`** (1.2.c) | editarea e a lui #6 |
|
||||
|
||||
### 3.2 `Ct_clb_altele` — verificarea ceruta explicit, cu doua corectii la plan [V]
|
||||
|
||||
Planul (`:2952-2955`) spune: *„eticheta schimbata pe tip de `do_schimba_explicatia` („Nr. contract" /
|
||||
„Nr. comanda" / „Nr. factura" / „Nr. facturi" / „Locatie", `ofacturare.vc2:9633-9643`), eliminat azi
|
||||
din formular cand `gnScadereStoc = 0` si tipul e 1/5/10 fara copiere."*
|
||||
|
||||
Citit ramura cu ramura din `frm_date_factura.Init` (`ofacturare.vc2:9563-9796`), `Do Case`-ul de la
|
||||
`:9615-9722`:
|
||||
|
||||
**Corectia 1 — lista de etichete e incompleta.** Intervalul `9633-9643` din plan e corect ca interval,
|
||||
dar contine **sase** apeluri, nu cinci: `Nr. contract` (`:9633`, tip 2/6/52), `Nr. comanda` (`:9635`,
|
||||
tip 3), **`Nr. aviz / avize` (`:9637`, tip 4)**, `Nr. factura` (`:9639`, tip 7), `Nr. facturi`
|
||||
(`:9641`, tip 8/9), `Locatie` (`:9643`, tip 45). **Planul omite exact tipul 4** — cel pentru care
|
||||
`Ct_clb_altele` tine **lista de avize**, adica singura sursa care trebuie refurnizata lui S9
|
||||
(sectiunea 6). Omisiunea nu e cosmetica.
|
||||
|
||||
**Corectia 2 — conditia de eliminare e mai larga decat cea din plan.** `ct_clb_altele` e scos
|
||||
(`RemoveObject`) in **trei** situatii, nu una:
|
||||
|
||||
| Ramura | Conditie | Ce face |
|
||||
|---|---|---|
|
||||
| `:9616-9628` | `gnScadereStoc = 0 And Inlist(poDate.tip, 1, 5, 10, **48, 49**)` | daca `llCopiere` → eticheta `Nr. factura` (`:9623`); altfel **`RemoveObject('ct_clb_altele')`** (`:9627`) |
|
||||
| `:9651-9660` | **`gnScadereStoc = 1`** `And Inlist(poDate.tip, 1, 5, 10)` | idem (`:9653` / `:9658`) |
|
||||
| `:9705-9712` (in `Otherwise`) | `Inlist(poDate.tip, 48, 49)` | **`RemoveObject('ct_clb_altele')`** neconditionat |
|
||||
|
||||
Deci: tipurile sunt **1, 5, 10, 48, 49** (nu doar 1/5/10), si eliminarea are loc si cand
|
||||
**`gnScadereStoc = 1`**, nu doar cand e `0`. Formularea din plan („`gnScadereStoc = 0` si tipul e
|
||||
1/5/10") descrie **una** din trei ramuri.
|
||||
|
||||
**Consecinta pentru S8, si e in favoarea noastra:** pe ramurile 1 si 2, `llCopiere = .T.` **pastreaza**
|
||||
controlul si ii pune eticheta `Nr. factura`. Calea de editare, care va avea acelasi semnal ridicat
|
||||
(`lCopiere` sau `lEditare`), **mosteneste automat pastrarea controlului** — nu e nimic de adaugat, doar
|
||||
de **blocat**. Pe ramura 3 (tipurile 48/49) controlul e scos neconditionat; **[N]** n-am stabilit daca
|
||||
tipurile 48/49 intra in perimetrul etapei II.
|
||||
|
||||
### 3.3 Ce ramane editabil
|
||||
|
||||
Cei 14 parametri, prin `but_modifica` (S8c), **plus** liniile (cantitati, preturi, discounturi,
|
||||
explicatii, adaugari/stergeri) si discountul de document — care declanseaza regenerarea. Nimic din
|
||||
sectiunea 3.1.
|
||||
|
||||
---
|
||||
|
||||
## 4. Ordinea reala de incarcare, si de ce conteaza
|
||||
|
||||
### 4.1 Secventa propusa
|
||||
|
||||
```
|
||||
0. S7 a validat deja documentul (garzi) si a stabilit id_vanzare.
|
||||
1. Citeste ANTETUL: SELECT ... FROM FACT_VFACTURI WHERE id_vanzare = :id
|
||||
2. Citeste LISTA SURSA (avize) inainte de orice altceva: SELECT ... FROM VANZARI_CORESP (§6)
|
||||
3. poDate = CreateObject("oDateFactura", 0, 0) <-- tnIdSet = 0 => Init NU ruleaza (§4.2)
|
||||
4. poDate.lEditare = .T. <-- semnalul, inainte de orice formular
|
||||
5. Populeaza poDate din antet: cei 14 + tip + eproforma + valuta/curs +
|
||||
discount_evidentiat + client + gestiune + sursa (cListaSursa / cListaSursaAvize)
|
||||
6. Populeaza thisform.ndiscfactron / ndiscfactval din VANZARI.DISCOUNT
|
||||
7. Citeste LINIILE (canalul din §1.1(B)) -> crsarticole
|
||||
8. GARDA DE RECALCUL: thisform.lIncarcare = .T.
|
||||
9. Umple crsfactura din crsarticole, fara dialoguri (§4.3)
|
||||
10. Adauga lista de preturi peste crsarticole (pentru S4g: adaugarea de articole noi)
|
||||
11. thisform.lIncarcare = .F.
|
||||
12. Un singur do_calculeaza_totaluri()
|
||||
13. SNAPSHOT pentru S8b (§5)
|
||||
14. Blocheaza antetul (S8c) si campurile din §3.1; arata formularul
|
||||
```
|
||||
|
||||
### 4.2 De ce pasul 3 arata asa — `tnIdSet = 0` [V]
|
||||
|
||||
Tot corpul lui `oDateFactura.Init` e inchis in `If !Empty(m.tnIdSet)` (`ofacturare_comun.prg:225`).
|
||||
Cu `tnIdSet = 0`, **niciuna dintre cele opt initializari de la 2.2 (nr. 1-8) nu se executa**, iar
|
||||
constructorul devine inert. **Precedentul exista si e chiar cel de reincarcare a unui document:**
|
||||
`relisteaza_ofacturare_stoc` face `poDate = Createobject("oDateFactura", 0, 0)`
|
||||
(`ofacturare_stoc.prg:497`) **[V]** exact din acest motiv.
|
||||
|
||||
Asta rezolva **printr-o singura decizie de constructie** opt din cele paisprezece initializari
|
||||
periculoase, fara nicio modificare in `oDateFactura` — si e mult mai robust decat „suprascriem dupa",
|
||||
pentru ca nu depinde de completitudinea listei de suprascrieri.
|
||||
|
||||
**Ce ramane de tratat separat, pentru ca nu trece prin `Init`:**
|
||||
- nr. 9-12 (`frm_alte_date.Init`) → garda `poDate.lEditare` de la 2.1;
|
||||
- **nr. 13, `poGeneratorNumere`** — e apelat din `factureaza` (`ofacturare.prg:207-209`), nu din
|
||||
`Init`. Pe calea de editare **nu trebuie sa se aloce numar**: seria si numarul vin din document
|
||||
(decizia F / plan §F). `oGeneratorNumere` are deja `dezaloca_numar` si `verifica_numar`
|
||||
(`ofacturare.prg:227`, `:250`), dar calea corecta e **sa nu se aloce deloc**. **[N]** —
|
||||
`COMUN\programe\oserii_numere.prg` n-a fost citit in aceasta sesiune; planul citeaza `:227-233`
|
||||
pentru afirmatia „la modificare nu se aloca numar nou". **De verificat la implementare** ca ocolirea
|
||||
alocarii nu lasa `poDate.rezultat_serii` intr-o stare pe care `frm_date_factura.Init` o citeste
|
||||
(`ofacturare.vc2:9736`: `If Inlist(poDate.rezultat_serii, 1, 2, 3) → clb_serie_act.do_initializeaza(...)`).
|
||||
|
||||
### 4.3 Pasul 9 e piesa care lipseste azi — si e cea mai mare
|
||||
|
||||
**[V]** Pe calea de copiere, `crsfactura` ramane gol; documentul se compune manual sau prin
|
||||
`do_adauga_tot`. `do_adauga_tot` (`ofacturare.vc2:13169-13198`) face `SCAN` peste `crsarticole` si
|
||||
cheama `do_adauga_articol(.T.)`, care (`:12871-12894`):
|
||||
|
||||
- pe ramura `poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45` — creeaza
|
||||
`frm_articol_factura` **fara sa-l arate** (cu `tlImplicit = .T.`) si calculeaza totalurile. Acceptabil.
|
||||
- pe ramura `Otherwise` — cheama **`do_alege_stoc(...)`**, adica **dialogul de alegere din stocul de
|
||||
azi**. Pe calea de editare asta e gresit de doua ori: (a) ar putea cere interventia utilizatorului
|
||||
pentru fiecare linie gestionabila la simpla deschidere a documentului; (b) ar alege **loturi/serii
|
||||
din stocul curent**, desi documentul are deja `LOT`, `SERIE` si `ID_GESTIUNE` proprii, intoarse de
|
||||
cursor.
|
||||
|
||||
In plus, `do_adauga_tot` are un `Do While` cu `aMessageBox("Nu ati selectat toata cantitatea …")`
|
||||
(`:13188`) — **un modal per linie neacoperita**. Inacceptabil la incarcare.
|
||||
|
||||
Si `do_adauga_articol` scrie `Replace id_temp With Recno()` (`:12951` si `:13000`) **[V]** — deci chiar
|
||||
daca sursa ar avea `ID_VANZARE_DET`, **nu ar ajunge in `crsfactura` pe aceasta cale**.
|
||||
|
||||
**Concluzie:** S8 nu poate refolosi `do_adauga_tot`. Ii trebuie o **populare directa**
|
||||
`crsarticole → crsfactura` (un `INSERT INTO crsfactura ... SELECT ...` plus recalculul valorilor pe
|
||||
linie prin `calculeaza_totaluri`), care:
|
||||
1. **nu deschide niciun dialog**;
|
||||
2. pastreaza `lot`, `serie`, `id_gestiune`, `id_pol`, `pretd` **din document**;
|
||||
3. duce `id_vanzare_det` intr-o coloana proprie noua pe `crsfactura` (**nu** in `id_temp`, care e
|
||||
suprasolicitat: `Recno()` pe o cale, `id_vanzare_det` pe alta — `prelucreaza_facturacrs` face
|
||||
`id_vanzare_det As id_temp`, `ofacturare_comun.prg:1811` **[V]**);
|
||||
4. duce `taxcode`.
|
||||
Precedentul de structura exista: blocul `tnTip = 30` din `factureaza`
|
||||
(`ofacturare.prg:340-378`) face exact o populare directa `crsarticole → crsfactura` prin
|
||||
`INSERT INTO crsfactura (...) Values (...)`, fara niciun dialog **[V]**. Se cloneaza forma lui.
|
||||
|
||||
### 4.4 Garda de „nu recalcula acum" — unde, si de ce
|
||||
|
||||
`crsfactura` e `RecordSource`-ul gridului, iar coloanele au `Valid`/`InteractiveChange` care
|
||||
recalculeaza. La populare programatica, `Valid` **nu** se declanseaza in VFP (se declanseaza doar la
|
||||
iesirea din control, pe interactiune) — deci riscul principal **nu** e in grid, ci in:
|
||||
|
||||
- **`ControlSource` legate direct de `poDate`** (ex. `poDate.discount_evidentiat`,
|
||||
`ofacturare.vc2:11305`) — atribuirea programatica declanseaza `ProgrammaticChange`, nu `Valid`
|
||||
**[D]** (comportament VFP standard; nu l-am observat rulat aici);
|
||||
- **`opt_incasat.Value =`** — 2.2 nr. 12, efectul secundar documentat;
|
||||
- **`clb_discount.procent.Value =`** (`ofacturare.vc2:13475`) — daca S8 populeaza procentul de discount
|
||||
in loc de suma, `InteractiveChange` ar recalcula discountul pe baza curenta, care in timpul popularii
|
||||
e incompleta.
|
||||
|
||||
**Recomandare concreta:** un singur flag pe formular, `Thisform.lIncarcare`, testat la intrarea in
|
||||
`do_calculeaza_totaluri` si in `actualizeaza_discount` (`ofacturare.vc2:13408-13415`), plus **regula ca
|
||||
discountul de document se incarca ca SUMA** (`ndiscfactron`/`ndiscfactval`, valorile pe care le citeste
|
||||
si scrierea, `:14272-14274`), **nu ca procent** — procentul se recalculeaza din suma la pasul 12
|
||||
(`:13475`: `procent.Value = Round(ndiscfactron * 100 / nbazafdiscount, 2)`), nu invers.
|
||||
|
||||
### 4.5 Asezarea — decizia 5
|
||||
|
||||
Nimic din cele de mai sus nu schimba aspectul: nu se adauga banda de avertizare, coloane cu valori
|
||||
initiale sau panou de diferente. Se schimba **titlul ferestrei** si **butonul principal** (decizia 9 /
|
||||
S8c). Diferentele vizibile fata de introducere sunt **doar** cele care rezulta din blocarea campurilor
|
||||
(3.1) si din ascunderea lui `zi_curs` (1.5) — ultima e o abatere minora de la „identic", propusa
|
||||
motivat, **de confirmat de Marius** (intrebarea 4, sectiunea 8).
|
||||
|
||||
---
|
||||
|
||||
## 5. Interfata cu S8b — ce se retine ca „stare initiala"
|
||||
|
||||
### 5.1 Momentul
|
||||
|
||||
Snapshot-ul se ia la **pasul 13**: dupa incarcarea completa si dupa singurul recalcul, dar **inainte de
|
||||
afisarea formularului**. Nu mai devreme (valorile derivate n-ar fi calculate) si nu mai tarziu (orice
|
||||
`Init` de subformular ar putea polua — 2.2).
|
||||
|
||||
### 5.2 Ce se retine, si in ce forma
|
||||
|
||||
| Grup | Forma | Normalizare obligatorie inainte de comparatie |
|
||||
|---|---|---|
|
||||
| **Cei 14 parametri** | copie a valorilor din `poDate` (+ `id_ruta`, 1.5) intr-un obiect `poDateInitial` | `.NULL.` vs `0` vs `''` — functie unica aplicata **simetric**; `text_aditional`: **`LEFT(...,100)` + `Chr(170)`→`CR+LF`** pe ambele parti (1.7) |
|
||||
| **Discountul de document** | `ndiscfactron` si `ndiscfactval`, **ca sume** | `Round(..., gnPc)` / `Round(..., gnPVal)` |
|
||||
| `discount_evidentiat` | scalar | — |
|
||||
| **Liniile** | copie a lui `crsfactura`, cheia = **`id_vanzare_det`** (coloana noua, 4.3) | `Round` la `gnPc` / `gnPPretV` / `gnPCant`; pretul comparat in forma **rotunjita + `DIFERENTA`** (1.4.ii) |
|
||||
| **Explicatie / taxcode pe linie** | in aceeasi copie | `Alltrim`, `Nvl(...,'')` |
|
||||
|
||||
**Trei precizari care corecteaza sau completeaza S8b:**
|
||||
|
||||
1. **Cheia `id_vanzare_det` nu vine gratuit** — S8b o presupunea incarcata („coloana deja incarcata la
|
||||
S8"). Nu e (1.1). Devine **livrabil al lui S8**, nu premisa.
|
||||
2. **Liniile fara `id_vanzare_det`** (adaugate in sesiune) se marcheaza cu `0`/`.NULL.` si inseamna
|
||||
direct „regenerare", ca in S8b §1.3.
|
||||
3. **`zi_curs` se scoate din comparatie** (1.5) — altfel orice document ar aparea modificat.
|
||||
|
||||
### 5.3 Cele 7 campuri comune `scrie_factura2` / `modifica_date_factura`
|
||||
|
||||
Nimic de adaugat la S8b §3.1 — lantul cu prioritate ramane. S8 doar garanteaza premisa lui: **`poDate`
|
||||
contine, la momentul confirmarii, valorile documentului plus editarile utilizatorului si nimic altceva**
|
||||
— ceea ce e exact ce asigura sectiunile 2 si 4.
|
||||
|
||||
---
|
||||
|
||||
## 6. Interfata cu S9 — ce trebuie sa incarce S8 ca S9 sa poata refurniza lista sursa
|
||||
|
||||
Pasul 1 nou al lui S9 (handoff, rezultatul 7) cere **citirea listei sursa inainte de stergere**. S8 e
|
||||
locul unde se citeste, pentru ca **dupa stergere `VANZARI_CORESP` are `STERS = 1`** (`:5582` **[V]**) si
|
||||
`VANZARI.ID_COMANDA` / `ID_CTR` raman pe randul soft-sters.
|
||||
|
||||
**Ce incarca S8, si de unde:**
|
||||
|
||||
| Ce | Camp propus pe `poDate` | Sursa | Consumator la reemitere |
|
||||
|---|---|---|---|
|
||||
| lista de avize | `cListaSursaAvize` | `SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP WHERE ID_VANZARE_FACT = :id AND STERS = 0 AND TIP = 1` | `pack_facturare.clistaid_avize` → `scrie_corespondente_vanzari(1)` si `marcheaza_facturat` |
|
||||
| comanda | `cListaSursa` | `FACT_VFACTURI.ID_COMANDA` | `pack_facturare.clistaid` |
|
||||
| contract | `cListaSursa` (+ `id_ctr`) | `FACT_VFACTURI.ID_CTR` | idem, plus `CTR_RATE_FACTURI` |
|
||||
| tipul original | `poDate.tip`, nedegradat | `FACT_VFACTURI.TIP` | `CASE`-ul pe `ntip` din `finalizeaza_factura` |
|
||||
|
||||
**Doua avertismente:**
|
||||
|
||||
1. **`poDate.listaid` NU poate purta aceasta informatie** — la incarcare el trebuie sa fie
|
||||
`id_vanzare`-ul documentului insusi, ca sa se citeasca liniile (1.6). Doua campuri distincte,
|
||||
nu unul reinterpretat.
|
||||
2. **Semantica valorilor lui `TIP`** din `VANZARI_CORESP` **nu e stabilita aici [N]** (1.6) — se
|
||||
citeste din `CASE`-ul real al lui `finalizeaza_factura` la implementare.
|
||||
|
||||
**Nu tine de S8**, dar se semnaleaza pentru ca S8 decide continutul lui `crsarticole`:
|
||||
`do_scrie_factura` face `Select crsarticole` + `Calculate Sum(cantitate) To lnCantitateRamasa` pe
|
||||
ramurile `poDate.Tip = 4` (`ofacturare.vc2:14305-14307`) si `Inlist(poDate.Tip,3,21,25,28,42,47)`
|
||||
(`:14336-14338`) **[V]**, si pe baza sumei intreaba *„Doriti sa se inregistreze si avizul de retur?"* /
|
||||
*„Doriti sa se inchida comanda?"* si seteaza `pnParametruAditional`. Pe calea de editare `crsarticole`
|
||||
contine liniile documentului **plus lista de preturi adaugata peste ele** (`ofacturare.prg:465-473`
|
||||
**[V]**), deci **suma e lipsita de sens** si intrebarea ar aparea gresit, cu efect real pe
|
||||
`pnParametruAditional`. **De rezolvat in S9** — fie prin cursor separat pentru lista de preturi, fie
|
||||
prin calcularea sumei doar peste randurile provenite din document.
|
||||
|
||||
---
|
||||
|
||||
## 7. Criteriul „gata cand", in forma testabila
|
||||
|
||||
**Comun tuturor tipurilor.** Pe un document existent, dupa deschidere si **inainte** de orice
|
||||
interactiune:
|
||||
|
||||
| # | Ce se verifica | Cum |
|
||||
|---|---|---|
|
||||
| C1 | serie, numar, data, scadenta afisate = cele din `VANZARI` | comparatie ecran ↔ `SELECT serie_act, numar_act, data_act, data_scad FROM vanzari WHERE id_vanzare = :id` |
|
||||
| C2 | **niciun numar nou alocat** | inainte/dupa: ultimul numar din generatorul de serii pentru `nIdTipDoc` e neschimbat |
|
||||
| C3 | numarul de linii din grid = `SELECT count(*) FROM vanzari_detalii WHERE id_vanzare = :id AND sters = 0` | |
|
||||
| C4 | pe fiecare linie: cantitate, pret, discount, gestiune, lot, serie, cota TVA, explicatie, `taxcode` = valorile din `VANZARI_DETALII` (pret in forma rotunjita + `DIFERENTA`, 1.4.ii) | |
|
||||
| C5 | totalurile afisate = `VANZARI.TOTAL_FARA_TVA` / `TOTAL_TVA` / `TOTAL_CU_TVA` | |
|
||||
| C6 | discountul de document si `discount_evidentiat` = `VANZARI.DISCOUNT` / `DISCOUNT_EVIDENTIAT` | |
|
||||
| C7 | delegat, masina, agent, adresa de facturare, `dataora_exp`, `text_aditional`, `listare_detaliata`, `tip_saft`, `efactura`, `id_ruta` = `VANZARI` | inclusiv **cazul „documentul n-are delegat"** → campul ramane gol (2.1) |
|
||||
| C8 | **nicio scriere in baza** — criteriul de baza al lui S8b | `SELECT dataoras, id_utils FROM vanzari WHERE id_vanzare = :id` neschimbat dupa deschidere+inchidere; idem pe `VANZARI_DETALII` |
|
||||
| C9 | **niciun dialog modal** la deschidere (nici alegere de stoc, nici „nu ati selectat toata cantitatea", nici „doriti sa inchideti comanda") | observatie |
|
||||
| C10 | aspectul e cel de introducere (decizia 5): fara banda, fara coloane de valori initiale, fara panou de diferente; difera doar titlul si butonul principal | observatie |
|
||||
|
||||
**Pe fiecare tip de sursa, in plus:**
|
||||
|
||||
| Tip | Ce se verifica specific |
|
||||
|---|---|
|
||||
| **comanda** (3, 21, 25, 28, 42, 47) | `Ct_clb_altele` afiseaza numarul comenzii, eticheta „Nr. comanda", **blocat**; `poDate.cListaSursa` = `VANZARI.ID_COMANDA` |
|
||||
| **contract** (2, 6, 26, 52) | eticheta „Nr. contract", blocat; `id_ctr` incarcat; **`goContract` din sesiune NU suprascrie antetul** (2.2 nr. 7); daca S10 se implementeaza, **niciun avertisment de re-derivare la simpla deschidere** (`cursor_retur_document` citeste pretul stocat, rezultatul 6 al handoff-ului) |
|
||||
| **aviz** (tip 4 = factura din avize) | eticheta **„Nr. aviz / avize"** (3.2), blocat; `poDate.cListaSursaAvize` = randurile `VANZARI_CORESP` ale documentului; **nicio intrebare „doriti sa se inregistreze si avizul de retur?"** la deschidere (§6) |
|
||||
| **factura simpla** (1, 5, 10) | `Ct_clb_altele` **pastrat si vizibil** cu eticheta „Nr. factura" (3.2, ramurile 1 si 2 cu `llCopiere`), spre deosebire de emiterea normala unde e scos |
|
||||
| **retur** (8, 9, 24) | `zi_curs` e oricum scos azi pentru 8/9 (`ofacturare.vc2:9720-9725`) — comportament neschimbat; liniile se incarca cu cantitatile documentului, nu cu cele disponibile la retur |
|
||||
| **ROAAUTO** | `poDate.id_ordl` incarcat din `VANZARI.ID_ORDL`; **[N]** nu s-a verificat in aceasta sesiune ce alte campuri specifice ROAAUTO exista pe antet — `roaauto_facturi.md` nu a fost citit |
|
||||
| **proforma** (`eproforma = 1`) | `poDate.eProforma` incarcat (1.2.a) → `frm_alte_date.Init` sare din start pe ramura de proforma (`:3110`), iar `gestionabil` vine `0` din cursor (1.4) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Riscuri, goluri ramase, si intrebarile pentru Marius
|
||||
|
||||
### 8.1 Ce n-am putut stabili, si de ce
|
||||
|
||||
| # | Ce | De ce |
|
||||
|---|---|---|
|
||||
| N1 | Semantica exacta a valorilor `VANZARI_CORESP.TIP` (`1/2/3`, `4` liber) | Cere citirea `CASE`-ului pe `ntip` din `finalizeaza_factura`, in afara perimetrului parcurs. **Nu se preia din raportul precedent** — e exact tiparul cifrei gresite din runda 13. |
|
||||
| N2 | Daca ocolirea alocarii de numar lasa `poDate.rezultat_serii` intr-o stare pe care `frm_date_factura.Init` o citeste gresit (`ofacturare.vc2:9736`) | `COMUN\programe\oserii_numere.prg` necitit in aceasta sesiune |
|
||||
| N3 | Daca prefixul „Scadenta la N zile." adaugat la `Init` (2.2 nr. 11) e scos pe **toate** caile de iesire | Am vazut operatia inversa la `ferestre_cere_date.vc2:3037-3038`, dar n-am urmarit toate caile de `Unload`/`Destroy` |
|
||||
| N4 | Campurile de antet specifice **ROAAUTO** | `roaauto_facturi.md` necitit |
|
||||
| N5 | Daca tipurile **48/49** (custodie) intra in perimetrul etapei II | Conteaza pentru 3.2, ramura 3 |
|
||||
| N6 | Daca `frm_facturare_articole2` (varianta paralela) trebuie tratata identic | Are `do_adauga_tot` / `do_adauga_articol` proprii (`ofacturare.vc2:17476`, `:17124`), cu logica usor diferita (fara testul `llGestionabil`) — **de decis daca S8 tinteste ambele forme sau doar `frm_facturare_articole`** |
|
||||
|
||||
### 8.2 Intrebari pentru Marius, cu recomandare
|
||||
|
||||
1. **Canalul de citire a liniilor: (A) extindem `cursor_retur_document`, (B) procedura noua
|
||||
`cursor_editare_document`, sau (C) `FACT_VFACTURI_DETALII`?** (1.1)
|
||||
*Recomandare:* **(B)**. Argumentul nu e estetica, ci ca (A) schimba **comportamentul copierii**
|
||||
(`taxcode` ar incepe sa se propage), iar (C) pierde `ID_POL`, `PRETD` si tratamentul valutar —
|
||||
partea grea. (B) da si libertatea de a alege corect `GESTIONABIL` (1.4.i).
|
||||
|
||||
2. **`GESTIONABIL` la editare: din nomenclatorul de azi (`IN_STOC`) sau din document (`ID_GESTIUNE`)?**
|
||||
(1.4.i)
|
||||
*Recomandare:* **din document**. Un document editat trebuie sa arate cum a fost emis; regimul de
|
||||
stoc al articolului s-a putut schimba intre timp fara nicio legatura cu documentul.
|
||||
|
||||
3. **`text_aditional`: se normalizeaza la incarcare (`Chr(170)` → `CR+LF`) sau se afiseaza ca atare?**
|
||||
(1.7)
|
||||
*Recomandare:* **se normalizeaza la incarcare si se re-normalizeaza la comparatie**, altfel orice
|
||||
document cu text pe mai multe randuri apare modificat la deschidere. Nota: cele doua rute de scriere
|
||||
salveaza **forme diferite** ale campului (truncat/substituit vs. brut) — merita semnalat separat,
|
||||
e un defect preexistent, nu al lui #13.
|
||||
|
||||
4. **`zi_curs` pe calea de editare: ascuns, sau afisat gol?** (1.5)
|
||||
*Recomandare:* **ascuns**, cu precedent in acelasi `Do Case` (tipurile 8/9). E o abatere mica de la
|
||||
decizia 5, si o semnalez ca atare — un camp afisat gol pe un document care are curs ar fi mai
|
||||
derutant decat absenta lui.
|
||||
|
||||
5. **`poDate.lEditare` ca proprietate pe `oDateFactura`, sau parametru pe `frm_alte_date.Init`?** (2.1)
|
||||
*Recomandare:* **proprietate**, pentru ca sunt **cel putin patru** locuri care au nevoie de semnal
|
||||
(2.2 nr. 9-13), nu unul, si pentru ca `lCopiere` e deja acolo, cu exact acelasi rol.
|
||||
|
||||
6. **`id_ruta` — proprietate noua pe `oDateFactura`?** (1.5)
|
||||
*Recomandare:* **da**. Fara ea S8c nu poate implementa unul din cei 14 parametri, iar azi valoarea
|
||||
circula doar prin `poRec`, care nu exista in formularul unificat.
|
||||
|
||||
7. **Tipurile 48/49 si `frm_facturare_articole2`** (N5, N6) — intra in perimetrul etapei II?
|
||||
*Recomandare:* **nu acum**; se declara explicit ca neacoperite, ca sa nu se descopere la testare.
|
||||
|
||||
8. **Defectul de la 2.2 nr. 11** (prefixarea `text_aditional` la `Init` pentru contracte) — se repara
|
||||
in #13, se semnaleaza separat, sau se lasa?
|
||||
*Recomandare:* **se ocoleste in #13** (prin `lEditare`) si **se semnaleaza separat** ca defect
|
||||
preexistent — repararea lui pe calea de emitere nu tine de aceasta poveste.
|
||||
|
||||
### 8.3 Ce a fost corectat fata de materialele existente
|
||||
|
||||
| Afirmatie anterioara | Stare |
|
||||
|---|---|
|
||||
| S8b: „lookup-ul delegatului trebuie sarit explicit, altfel pica primul criteriu" | **Nuantat** — garda `Empty(id_delegat) And Empty(id_masina)` exista deja (`ferestre_cere_date.vc2:3111`); riscul e real **doar** pe documentele fara delegat si fara masina |
|
||||
| S8b §1.2 / §7.4: „cheia de linie `id_vanzare_det`, coloana deja incarcata la S8" | **Infirmat** — `cursor_retur_document` nu o intoarce; devine livrabil al lui S8 |
|
||||
| S8b §5.2: „S8 trebuie sa suprascrie implicitul `zi_curs` cu data reala salvata" | **Infirmat structural** — nu exista coloana `ZI_CURS` pe `VANZARI` |
|
||||
| Plan S8: etichetele lui `Ct_clb_altele` (cinci) | **Incomplet** — sunt sase; lipseste „Nr. aviz / avize" (tip 4), exact cazul relevant pentru S9 |
|
||||
| Plan S8: „eliminat cand `gnScadereStoc = 0` si tipul e 1/5/10 fara copiere" | **Incomplet** — trei ramuri, tipurile `1,5,10,48,49`, si pentru `gnScadereStoc = 1`, nu doar `0` |
|
||||
| Plan S8: „`cursor_retur_document(V_COPIERE=1)` pentru linii" | **Insuficient** — umple selectorul, nu documentul; lipsesc `ID_VANZARE_DET` si `TAXCODE` |
|
||||
| Plan S8: „`completeaza_setari_document` pentru antet" | **Insuficient** — 16 proprietati din ~120, niciuna de identitate |
|
||||
|
||||
---
|
||||
|
||||
*Cercetare incheiata pe toate cele 8 puncte cerute in briefing. Afirmatiile portante au `fisier:linie`
|
||||
sau nume de coloana din dictionar. Nu s-a modificat niciun fisier de cod; pe Oracle numai `SELECT` pe
|
||||
`all_tab_columns`.*
|
||||
Reference in New Issue
Block a user