#13: formular de facturare unificat - etapa curenta

Squash al branch-ului de lucru plan13-s2.

Clase: ofacturare (nucleul formularului unificat), ofacturare_comun,
ferestre_cere_date, ocomenzi, caut_ora (lista de preturi in combo-urile de
cautare), omodificari.

Programe: ofacturare impartit - ofacturare_antet, ofacturare_rutare_scriere si
ogrid_latimi sunt fisiere noi; oproceduri_facturare primeste discountul pe linie
si cota standard de TVA cand articolul nu are cota pe politica.

Documentatie: capcana SQLExec no_data_found, conventia de encoding, depanarea
testelor VFP si regulile de lucru - conflictele cu modificarile venite din alte
proiecte sunt rezolvate pastrand ambele parti.

Loguri de rulare a testelor scoase din versionare; testele raman.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
2026-09-09 21:38:25 +03:00
parent d1d0d7c37f
commit 8e022d332e
259 changed files with 57305 additions and 1576 deletions

View File

@@ -1 +1 @@
2026-08-02
2026-09-09

View File

@@ -0,0 +1,50 @@
# Capcana: linii pierdute tacut intre VFP si Oracle
## Simptomul
Un document se salveaza cu mai putine linii decat are pe ecran. Fara mesaj, fara eroare, fara
nimic in log. Totalurile ies mai mici, dar consistente intre ele - deci nu arata a defect.
## Mecanismul, in doi pasi
1. Un `SELECT ... INTO` **fara handler** intr-o procedura PL/SQL arunca `ORA-01403`
(`NO_DATA_FOUND`) cand predicatul nu potriveste niciun rand.
2. ODBC il traduce ca `SQL_NO_DATA`, si **`SQLExec()` intoarce 1, adica succes**. Bucla din VFP
testeaza `If lnSucces < 0` si nu vede nimic. Linia dispare fara urma.
Deci: eroare reala in Oracle -> succes raportat in VFP.
## De ce nu potriveste predicatul (cauza uzuala)
Santinela pusa doar pe coloana, nu si pe parametru:
AND NVL(A.CONT, 'XXXX') = V_CONT
VFP trimite sir gol pentru campul necompletat, iar in Oracle sirul gol **este NULL**; `'XXXX' = NULL`
da UNKNOWN, deci zero randuri. Corect e pe amandoua:
AND NVL(A.CONT, 'XXXX') = NVL(V_CONT, 'XXXX')
Pe `ID_GESTIUNE` acelasi tipar merge, fiindca acolo VFP chiar trimite santinela `-1000`.
Cauza inrudita, acelasi simptom: un camp lipsa din lista de insert a cursorului, pe o coloana
numerica **fara `NULL`** - ramane `0` tacit, nu NULL si nu eroare, si predicatul cade pe `0`.
## Ce se face, in ordinea asta
1. **Intai garda, apoi cauza.** Infasoara `SELECT ... INTO` in
`BEGIN ... EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20000, '... (FACT-0xx : ' || <cheia> || ')')`.
Fara ea, orice reparatie de cauza ramane neverificabila: mecanismul care ascunde defectul e inca
acolo. Codul `FACT-0xx` **se cauta liber in `USER_SOURCE`**, nu se presupune ca e liber.
2. Abia apoi simetrizeaza predicatul.
3. **Asertiune pe NUMARUL DE LINII** in testul de flux. Exact piesa care lipsea: identitatea
documentului si legaturile lui se pastrau corect, deci toate asertiunile existente treceau.
## Cum se cauta preventiv
In `USER_SOURCE`: fiecare `SELECT ... INTO` fara `EXCEPTION` in ramura lui, si fiecare predicat de
forma `NVL(<coloana>, <santinela>) = <parametru>`.
Precedent: `PACK_FACTURARE.adauga_articol_factura`, ramura `ntip = 4` (facturare din avize) - un
document reemis cu 2 linii din 4, nedetectat de doua sweep-uri la rand. Reparat 04.09.2026 cu
`FACT-030`.

View File

@@ -40,7 +40,13 @@ od -An -tx1 <fisier> | tr ' ' '\n' | grep -v '^$' | awk '$1>"7f"' | sort | uniq
La stricare censul CRESTE (un octet devine trei) - nu urmari doar scaderile. Cauta explicit
secventa `EF BF BD`, nu tiparul generic `C3`/`C4`/`C5`/`C8` (acela apare si in UTF-8 legitim
din cod).
din cod). Decodat cp1250, `EF BF BD` apare ca "�" in caption.
Varianta veche, utila cand cauti pozitia exacta (linia) a unui octet suspect:
```bash
perl -ne 'print "$.\n" if /[\x80-\xFF]/' <fisier>
```
## Reparare
@@ -50,7 +56,12 @@ oarba cu 0xBA strica alte litere din alte pozitii. Ia octetul corect per pozitie
PowerShell 5.1 (adauga BOM si re-encodeaza). Scrie inapoi ca bytes cp1250 explicit, apoi
`txt2vcx.ps1` + fidelity check.
Cazul simplu (s-a pierdut doar 0xBA), inlocuire punctuala pe octet:
Coruperea se repeta la FIECARE scriere, nu doar la prima: editeaza tot ce ai de editat, verifica
byte-level, si repara o singura data DUPA ultima scriere - nu intre editari.
Cazul simplu (s-a pierdut doar un octet, cel original cunoscut, ex. 0xBA pentru s-cu-virgula),
inlocuire punctuala pe secventa corupta - acelasi risc de coliziune poate afecta si alte fisiere
cu acelasi octet, nu doar pozitia curenta:
```bash
perl -e 'binmode(STDIN);binmode(STDOUT);local $/;$_=<STDIN>;s/\xEF\xBF\xBD/\xBA/g;print' < f > f.tmp

View File

@@ -158,3 +158,11 @@ Cand un bug apare "de azi", compara cu clasa veche fara sa atingi SVN:
Platit pe testarea VIES (23.08.2026): doua blocaje de 90s+; dupa stergerea celor doua fisiere,
exact acelasi script a rulat in 1.19s. Completeaza punctul (1) din capcana precedenta: nu doar
"exista `.ERR`?", ci si "e `.ERR`-ul de la rularea asta sau de la una anterioara?".
- **`TYPE()` pe un obiect nu intoarce `'O'` pentru orice membru.** `.Objects` la un container
(`Form`, `Container`, `Grid`) e *Objects Array*: `TYPE('loO.Objects')` da `'A'`, nu `'O'`. O
garda `IF TYPE('loO.Objects') = 'O'` e deci mereu falsa, iar `AND`-ul scurtcircuiteaza testul
corect de dupa ea - recursia pe arborele de controale nu porneste niciodata, **fara eroare si
fara nimic in log**; singurul simptom e un dump care contine doar nivelul 1. Testeaza pe ce
folosesti efectiv: `TYPE('loO.Objects.Count') = 'N'` e `'U'` daca lantul punctat nu exista,
deci e si suficient, si independent de litera de tip. Aceeasi prudenta la `TYPE('loO.Value')`
(tipul variaza cu continutul) si `TYPE('loO.Visible')`.

View File

@@ -0,0 +1,50 @@
# Instalare plugin Ponytail (Claude Code)
Plugin de nivel user (nu de proiect) care activeaza modul "lazy senior developer" descris in
`~/.claude/CLAUDE.md`. Se instaleaza o singura data per calculator, in contul Windows al
utilizatorului.
## Pasi
Din orice sesiune `claude` (sau `claude -p` cu `--dangerously-skip-permissions` daca ruleaza
neatended):
```
claude plugin marketplace add DietrichGebert/ponytail
claude plugin install ponytail@ponytail
```
Reporneste sesiunea Claude Code dupa instalare (plugin-urile se incarca la pornire).
## Verificare
```
claude plugin list
```
Trebuie sa apara `ponytail@ponytail` ca instalat si activ. Sau verifica direct in
`~/.claude/settings.json`:
```json
"enabledPlugins": {
"ponytail@ponytail": true
},
"extraKnownMarketplaces": {
"ponytail": {
"source": { "source": "github", "repo": "DietrichGebert/ponytail" }
}
}
```
## Nivel implicit
Nivelul (`lite|full|ultra`) e setat per sesiune cu `/ponytail <nivel>` sau ramane pe default-ul
plugin-ului. Regulile de scara YAGNI/reuse-first pentru proiectele ROA sunt in
`reguli_lucru.md`, punctul 3 ("Scara ponytail") — se aplica dupa instalare, nu fac parte din
instalarea in sine.
## Dezinstalare
```
claude plugin uninstall ponytail@ponytail
```

View File

@@ -0,0 +1,246 @@
# Prompt pentru alta sesiune: recreeaza statusline-ul Claude Code
Copiaza tot ce urmeaza si trimite-l ca prompt intr-o sesiune Claude Code noua
(pe alta masina/user), ca sa recreeze exact statusline-ul curent (Windows / Git Bash).
---
Vreau sa configurezi un statusline custom pentru Claude Code, pe Windows cu Git Bash.
1. Verifica ca exista `jq.exe` in `~/.claude/bin/jq.exe`. Daca nu exista, descarca
binarul oficial jq pentru Windows (jq-win64.exe de pe github.com/jqlang/jq/releases)
si salveaza-l acolo ca `jq.exe`.
2. Creeaza fisierul `~/.claude/statusline.sh` (bash, LF, executabil) cu continutul de mai jos.
3. In `~/.claude/settings.json`, adauga/actualizeaza cheia de nivel radacina:
```json
"statusLine": {
"type": "command",
"command": "C:/Users/<USER>/.claude/statusline.sh"
}
```
(inlocuieste `<USER>` cu userul curent; foloseste slash-uri, nu backslash).
Ce face scriptul:
- Linia 1: model | ctx folosit/total si % din fereastra | proiect (branch git, cu `*` daca e dirty)
- Linia 2: trei bare de puncte (10 puncte fiecare) pentru consum curent (5h), saptamanal (7 zile)
si sonnet (7 zile) — procent + timp pana la reset, in format `●●●○○○○○○○ 30% ↺ 2hr 15min`
- Cele trei procente vin din `/api/oauth/usage` (acelasi endpoint ca ecranul `/usage`),
cu cache de 10 minute in `~/.claude/.statusline-usage.json` si backoff la 429/eroare
(20 min, respectiv 5 min), ca sa nu loveasca rate-limit-ul la fiecare prompt.
- Pana la primul fetch reusit, current/weekly cad back pe `rate_limits` din JSON-ul primit pe stdin.
- Token-ul OAuth se ia din `~/.claude/.credentials.json` (`claudeAiOauth.accessToken`).
- La inceput reface PATH-ul (`$HOME/.claude/bin:/usr/bin:/bin:$PATH`), pentru ca Claude Code
lanseaza scriptul ca shell non-login/non-interactiv, deci profilul Git Bash nu se incarca
si PATH-ul nu are coreutils.
Continutul complet al `~/.claude/statusline.sh`:
```bash
#!/bin/bash
# Claude Code Statusline (Windows / Git Bash)
# Line 1: Model | ctx 33K/1M 3% | project (branch*)
# Line 2: current <bar> 24% ↺ 3hr │ weekly <bar> 4% ↺ Thu 7pm │ sonnet <bar> 2% ↺ Thu 7pm
#
# All three usage figures come from /api/oauth/usage -- the same source as the
# `/usage` screen -- so the numbers match it exactly. That endpoint is rate-
# limited, so the result is cached for 10 min; on failure the last good values
# are kept. Until the first successful fetch, current/weekly fall back to the
# `rate_limits` object on stdin (slightly different snapshot, but never blank).
set -o pipefail
# Claude Code spawns this as a non-login, non-interactive shell, so Git Bash's
# profile is never sourced and PATH has no coreutils. Restore them explicitly,
# plus the bundled jq.exe in ~/.claude/bin.
export PATH="$HOME/.claude/bin:/usr/bin:/bin:$PATH"
input=$(cat)
# Validate JSON
if ! echo "$input" | jq -e . >/dev/null 2>&1; then
printf '\033[90mLoading...\033[0m'
exit 0
fi
# --- Context / project (line 1) ---
model=$(echo "$input" | jq -r '.model.display_name // "?"')
workdir=$(echo "$input" | jq -r '.workspace.current_dir // ""')
project=$(basename "$workdir" 2>/dev/null) || project="?"
ctx_pct=$(echo "$input" | jq -r '(.context_window.used_percentage // 0) | floor')
[[ "$ctx_pct" =~ ^[0-9]+$ ]] || ctx_pct=0
ctx_size=$(echo "$input" | jq -r '.context_window.context_window_size // 0')
ctx_input=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0')
ctx_output=$(echo "$input" | jq -r '.context_window.current_usage.output_tokens // 0')
ctx_cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0')
ctx_cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
ctx_used=$(( ctx_input + ctx_output + ctx_cache_create + ctx_cache_read ))
fmt_tokens() {
local n=$1
if [ "$n" -ge 1000000 ]; then printf "%dM" $(( n / 1000000 ))
elif [ "$n" -ge 1000 ]; then printf "%dK" $(( n / 1000 ))
else printf "%d" "$n"; fi
}
ctx_used_fmt=$(fmt_tokens "$ctx_used")
ctx_size_fmt=$(fmt_tokens "$ctx_size")
# Git branch with dirty marker
git_branch=""
if [ -n "$workdir" ] && [ -d "$workdir" ]; then
git_branch=$(cd "$workdir" 2>/dev/null && git -c gc.auto=0 rev-parse --abbrev-ref HEAD 2>/dev/null) || git_branch=""
if [ -n "$git_branch" ]; then
git_dirty=$(cd "$workdir" 2>/dev/null && git -c gc.auto=0 status --porcelain 2>/dev/null | head -1)
[ -n "$git_dirty" ] && git_branch="${git_branch}*"
fi
fi
# --- Usage: all three figures from /api/oauth/usage, cached ---
USAGE_CACHE="$HOME/.claude/.statusline-usage.json"
USAGE_REFRESH=600 # refresh at most every 10 min
USAGE_BACKOFF_429=1200 # after a rate-limit, wait 20 min before retrying
USAGE_BACKOFF_ERR=300 # after any other error, wait 5 min
now=$(date +%s)
c5p=""; c5r=""; c7p=""; c7r=""; csp=""; csr=""; fetched=0; retry=0
read_usage_cache() {
[ -f "$USAGE_CACHE" ] || return
c5p=$(jq -r '.five_hour_pct // ""' "$USAGE_CACHE" 2>/dev/null)
c5r=$(jq -r '.five_hour_reset // ""' "$USAGE_CACHE" 2>/dev/null)
c7p=$(jq -r '.seven_day_pct // ""' "$USAGE_CACHE" 2>/dev/null)
c7r=$(jq -r '.seven_day_reset // ""' "$USAGE_CACHE" 2>/dev/null)
csp=$(jq -r '.sonnet_pct // ""' "$USAGE_CACHE" 2>/dev/null)
csr=$(jq -r '.sonnet_reset // ""' "$USAGE_CACHE" 2>/dev/null)
fetched=$(jq -r '(.fetched_at // 0) | floor' "$USAGE_CACHE" 2>/dev/null || echo 0)
retry=$(jq -r '(.retry_until // 0) | floor' "$USAGE_CACHE" 2>/dev/null || echo 0)
}
read_usage_cache
[[ "$fetched" =~ ^[0-9]+$ ]] || fetched=0
[[ "$retry" =~ ^[0-9]+$ ]] || retry=0
write_usage_cache() { # 5p 5r 7p 7r sp sr fetched_at retry_until
printf '{"five_hour_pct":"%s","five_hour_reset":"%s","seven_day_pct":"%s","seven_day_reset":"%s","sonnet_pct":"%s","sonnet_reset":"%s","fetched_at":%s,"retry_until":%s}\n' \
"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" > "$USAGE_CACHE"
}
refresh_usage() {
local creds="$HOME/.claude/.credentials.json" token tmp http
[ -f "$creds" ] || return
token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds" 2>/dev/null)
[ -n "$token" ] || return
tmp="$HOME/.claude/.statusline-usage.tmp.$$"
http=$(curl -s -o "$tmp" -w '%{http_code}' --max-time 3 \
-H "Authorization: Bearer $token" \
-H "anthropic-beta: oauth-2025-04-20" \
-H "Content-Type: application/json" \
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
if [ "$http" = "200" ]; then
local p5 r5 p7 r7 ps rs
p5=$(jq -r 'if .five_hour.utilization!=null then (.five_hour.utilization|floor) else "" end' "$tmp" 2>/dev/null)
r5=$(jq -r '.five_hour.resets_at // ""' "$tmp" 2>/dev/null)
p7=$(jq -r 'if .seven_day.utilization!=null then (.seven_day.utilization|floor) else "" end' "$tmp" 2>/dev/null)
r7=$(jq -r '.seven_day.resets_at // ""' "$tmp" 2>/dev/null)
ps=$(jq -r 'if .seven_day_sonnet.utilization!=null then (.seven_day_sonnet.utilization|floor) else "" end' "$tmp" 2>/dev/null)
rs=$(jq -r '.seven_day_sonnet.resets_at // ""' "$tmp" 2>/dev/null)
write_usage_cache "$p5" "$r5" "$p7" "$r7" "$ps" "$rs" "$now" 0
elif [ "$http" = "429" ]; then
write_usage_cache "$c5p" "$c5r" "$c7p" "$c7r" "$csp" "$csr" "$fetched" "$(( now + USAGE_BACKOFF_429 ))"
else
write_usage_cache "$c5p" "$c5r" "$c7p" "$c7r" "$csp" "$csr" "$fetched" "$(( now + USAGE_BACKOFF_ERR ))"
fi
rm -f "$tmp"
}
if [ "$(( now - fetched ))" -gt "$USAGE_REFRESH" ] && [ "$now" -gt "$retry" ]; then
refresh_usage
read_usage_cache
fi
# current / weekly: use API cache; fall back to stdin rate_limits if not yet fetched
if [ -n "$c5p" ]; then
five_hr_pct=$c5p; five_hr_reset=$c5r
else
five_hr_pct=$(echo "$input" | jq -r '(.rate_limits.five_hour.used_percentage // 0) | floor')
five_hr_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // ""')
fi
if [ -n "$c7p" ]; then
weekly_pct=$c7p; weekly_reset=$c7r
else
weekly_pct=$(echo "$input" | jq -r '(.rate_limits.seven_day.used_percentage // 0) | floor')
weekly_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // ""')
fi
# sonnet: only available from the API
sonnet_pct=${csp:-0}; sonnet_reset=$csr
[[ "$five_hr_pct" =~ ^[0-9]+$ ]] || five_hr_pct=0
[[ "$weekly_pct" =~ ^[0-9]+$ ]] || weekly_pct=0
[[ "$sonnet_pct" =~ ^[0-9]+$ ]] || sonnet_pct=0
# --- reset-time formatting (accepts epoch seconds or ISO string) ---
to_epoch() {
local v="${1%%.*}"
if [ -z "$v" ] || [ "$v" = "null" ]; then return 1; fi
if [[ "$v" =~ ^[0-9]+$ ]]; then printf '%s' "$v"
else date -d "$1" +%s 2>/dev/null || return 1; fi
}
fmt_reset() {
# No TZ= : Git Bash's date has no zoneinfo DB, but with TZ unset it uses the
# Windows system timezone correctly. Setting TZ=Europe/... falls back to UTC.
local e
e=$(to_epoch "$1") || { printf '%s' "--"; return; }
date -d "@$e" "+%a %-I:%M%P" 2>/dev/null || printf '%s' "--"
}
fmt_remaining() {
local e now_ts rem rh rm rd
e=$(to_epoch "$1") || { printf '%s' "--"; return; }
now_ts=$(date +%s)
if [ "$e" -gt "$now_ts" ]; then
rem=$(( e - now_ts )); rh=$(( rem / 3600 )); rm=$(( (rem % 3600) / 60 ))
if [ "$rh" -gt 24 ]; then
rd=$(( rh / 24 )); rh=$(( rh % 24 )); printf "%dd %dh" "$rd" "$rh"
elif [ "$rh" -gt 0 ]; then printf "%dhr %dmin" "$rh" "$rm"
else printf "%dmin" "$rm"; fi
else printf "resetting"; fi
}
five_hr_remain=$(fmt_remaining "$five_hr_reset")
weekly_reset_str=$(fmt_reset "$weekly_reset")
sonnet_reset_str=$(fmt_reset "$sonnet_reset")
# --- dot bar ---
DOT_TOTAL=10
make_dots() {
local pct=$1 filled i dots=""
filled=$(( pct * DOT_TOTAL / 100 ))
[ "$filled" -gt "$DOT_TOTAL" ] && filled=$DOT_TOTAL
[ "$filled" -lt 0 ] && filled=0
for (( i=0; i<DOT_TOTAL; i++ )); do
if [ "$i" -lt "$filled" ]; then dots="${dots}●"; else dots="${dots}○"; fi
done
printf "%s" "$dots"
}
# --- build & output ---
if [ -n "$git_branch" ]; then
proj_display="${project} (${git_branch})"
else
proj_display="${project}"
fi
line1=$(printf "%s │ ctx %s/%s %d%% │ %s" "$model" "$ctx_used_fmt" "$ctx_size_fmt" "$ctx_pct" "$proj_display")
line2=$(printf "current %s %d%% ↺ %s │ weekly %s %d%% ↺ %s │ sonnet %s %d%% ↺ %s" \
"$(make_dots "$five_hr_pct")" "$five_hr_pct" "$five_hr_remain" \
"$(make_dots "$weekly_pct")" "$weekly_pct" "$weekly_reset_str" \
"$(make_dots "$sonnet_pct")" "$sonnet_pct" "$sonnet_reset_str")
printf "%s\n%s" "$line1" "$line2"
```
Dupa ce salvezi fisierul si actualizezi `settings.json`, deschide o sesiune noua Claude
Code (sau `/statusline` refresh) ca sa vezi statusline-ul aplicat.

View File

@@ -50,8 +50,34 @@
`clase\anaf_efactura.vcx`. Motivul e de intretinere: un `.prg` se editeaza direct si diff-ul lui
se citeste in git, pe cand codul pus ca metoda in binar trece prin FoxBin2Prg si write-back si
se urmareste greu.
**Scara ponytail** (plugin activ implicit pe `full`, injectat si in subagenti; `ultra` nu se
foloseste pe cod legacy partajat): opreste-te la prima treapta care tine - 1) trebuie sa existe?
2) exista deja (`inventar-comun.md`, `COMUN\programe`, `COMUN\clase`) -> refolosesti; 3) o
functie VFP nativa o face; 4) se rezolva pe Oracle (view, constrangere, pachet) in loc de cod
client; 5) o linie; 6) abia apoi minimul care merge. Scurteaza SOLUTIA, nu cititul - intai
urmaresti fluxul real atins. Nu se simplifica niciodata: garzile pe NULL, validarile, tratarea
erorilor, drepturile de acces, ce s-a cerut explicit.
Abateri obligatorii fata de plugin: (a) **fara comentarii `ponytail:`** in cod (regula 2) -
scurtatura deliberata si limita ei se noteaza in `docs\progres.md`, deci `/ponytail-debt` nu
are ce culege aici; (b) proba unei logici noi e un script headless (regulile 4 si 8), nu
`test_*.py`; (c) handoff-urile, rapoartele din `docs\` si patch-urile sunt output cerut
explicit - regula "cod intai, maxim trei randuri" nu li se aplica; (d) `/ponytail-review` pe
diff-ul rundei inainte de commit e util, dar `delete:`/`yagni:` sunt IPOTEZE, nu constatari: in
`COMUN` apelantii sunt in toate produsele, deci cauti in tot `D:\ROA` inainte sa stergi, iar o
garda fara caz in datele de test nu e garda moarta (regula 6); `/ponytail-audit` pe tot
arborele nu se ruleaza aici.
4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell.
Mediu, sabloane, capcane, depanare: `depanare_testare_vfp.md`.
Rularile intermediare acopera doar familiile de teste atinse de modificarea curenta; suita
completa, inclusiv testele de garda pe zonele vecine, se ruleaza doar la rularea finala —
garzile exista fiindca schimbarile cad de regula in cod partajat (`COMUN`), vizibil in toate
produsele, dar costul lor nu se plateste la fiecare rulare intermediara. Ideal, doar testele
atinse direct (de regula 3-10), nu toata familia.
Un test normal dureaza 1-5s — ce umfla o rulare nu e testarea, ci asteptarea unui test atarnat.
La rulari intermediare: timeout **90s**/test (ce trece de atat e atarnat, nu lent) si pauza
**0,5s** intre teste, nu implicitul de 12 minute / 3s, rezervat rularii finale unde chiar
conteaza sa distingi "atarnat" de "lent". Tinta: o rulare intermediara sta in secunde-minute,
nu ore — daca depaseste, lista e prea larga sau timeout-ul prea mare.
5. Editare .vcx/.scx pe text (cache, cp1250 byte-safe, fidelity-check): `flux-editare-vfp-text.md`.
Cautare in binare: `cautare_vcx_vct.md`. Versiunile `.??2` sunt instantanee, pot fi mai vechi
decat binarul — verifica mtime inainte de concluzii; continutul real e in `.PJX`.
@@ -61,12 +87,14 @@
tokens/subagent), nu unul singur cu context acumulat; handoff compact pe disc. Verificarea a
ce se intoarce si modelul de lucru (backlog de story-uri mici): `orchestrare-subagenti.md`.
7. Conventii obligatorii, de citit cand atingi zona respectiva:
- editezi `.vc2`/`.sc2` sau `.prg` cu diacritice (ex. `programe\ocautare.prg`) -> fisierele
sunt **cp1250** desi antetul FoxBin2Prg declara `CPID="1252"`; Edit/Write corup TOT fisierul
(nu doar linia atinsa) la fiecare scriere - scrie continut nou strict ASCII. Cens obligatoriu
- editezi `.vc2`/`.sc2` sau `.prg` cu diacritice (ex. `programe\ocautare.prg`, unde `s`-urile cu
virgula din `masina`/`si contul`/`transa` sunt octetul `0xBA`) -> fisierele sunt **cp1250**
desi antetul FoxBin2Prg declara `CPID="1252"`; Edit/Write corup TOT fisierul (nu doar linia
atinsa), ireversibil, la fiecare scriere - scrie continut nou strict ASCII. Cens obligatoriu
**inainte SI dupa** fiecare editare (la stricare CRESTE, nu scade):
`od -An -tx1 <fisier> | tr ' ' '\n' | grep -v '^$' | awk '$1>"7f"' | sort | uniq -c`. Tabel
de octeti si reparare -> `conventie_encoding_cp1252.md`;
`od -An -tx1 <fisier> | tr ' ' '\n' | grep -v '^$' | awk '$1>"7f"' | sort | uniq -c`. Tabelul
complet de octeti, sensul censului la stricare si procedura de recuperare din git/svn ->
`conventie_encoding_cp1252.md`;
- adaugi o PROPRIETATE sau o METODA noua intr-o clasa `.vc2`/`.sc2` -> `flux-editare-vfp-text.md`,
sectiunea "Membri noi de clasa": fara intrarea `*p:`/`*m:` in `*<DefinedPropArrayMethod>`
membrul trece fidelity-check-ul, dar VFP nu-l vede si prima salvare din IDE il sterge tacut;
@@ -80,6 +108,8 @@
- te conectezi la Oracle pe dev/test, alegi schema sau rulezi un script de pachet ->
`conventie_mediu_oracle.md`;
- garzi pe valori NULL din Oracle -> `conventie_null_vfp.md`;
- procedura PL/SQL cu `SELECT ... INTO` chemata din VFP (linii pierdute tacut) ->
`capcana_sqlexec_no_data_found.md`;
- export date din Oracle -> `oracle_export.md`;
- actualizarea ROA nu se finalizeaza (job update, PACK_UPDATE) -> `depanare-pack-update.md`;
- modifici schema Oracle (tabele/view-uri/pachete) -> `scripturi-migrare-db.md`.

View File

@@ -112,6 +112,28 @@ fluxuri valorice.
in urma. Inainte de a te baza pe o linie din el pentru o modificare, confirm-o pe cod
(`initializeaza_date_factura`, `CASE`-urile din view-uri) sau pe `XSETS`.
## Domeniul regenerabil (planul #13)
Planul #13 introduce editarea articolelor unui document deja emis prin stergere + reemitere
(acelasi numar de document, rand nou in `VANZARI`). Domeniul acestui mecanism nu acopera tot
`VANZARI.TIP`:
- **In afara domeniului, prin decizie explicita a lui Marius** (confirmat de inventarul de FK din
S11): documentele legate de `REST_NOTE_PLATA` (modul restaurant, `TIP` 46) si de
`IPS_VOYAGES_VANZARI` (facturarea voiajelor din ROAACNPRO, `TIP` 51). Pentru ele ramane calea
veche de editare pe loc (#6); intrarea in formularul nou le refuza explicit, nu doar le ignora.
- **Declarate explicit neacoperite** (recomandare "nu acum"): tipurile **48/49** (custodie) -
incarcarea unui document existent in formularul nou nu e implementata pentru ele. Tinta unica
pentru editare ramane `frm_facturare_articole2` (formularul nou) - `frm_facturare_articole`
(formularul vechi) nu mai primeste cod nou.
- **Datorie deschisa, nu excludere**: documentele CONTRACT cu linii de rata
(`VANZARI_DETALII.ID_RATA <> 0`) esueaza la reemitere cu eroarea Oracle `Too many columns.` -
19 din cele 21 de documente CONTRACT vii sunt in acest perimetru. Cauza-radacina **nu e
dovedita**; nu exista azi o reparatie.
Restul tipurilor din tabelele de mai sus sunt in domeniul regenerabil, verificat pe cele patru
familii de scriere (AVIZ, COMANDA, CONTRACT, ELSE).
## Legaturi
- `scripturi-migrare-db.md` — sursa de referinta pentru DDL e `MARIUSM_AUTO`, nu o schema de client.

View File

@@ -24,7 +24,7 @@ DONE 9. ROAGEST - MODIFICARE REGISTRU JURNAL - SA SE POATA MODIFICA SI "NNIR" in
10. ROAFACTURARE - Integrare pagina contracte si rapoarte contracte in ROAFACTURARE, similar COMENZI in ROAFACTURARE - facturare pe baza de comenzi/contracte. trebuie comasate si drepturile pe obiectele din roacontracte cu obiectele noi din ROAFACTURARE.
11. ROAFACTURARE - Integrare politici de preturi in ROAFACTURARE - sunt numai editari de liste de preturi, note contabile, nomenclator articole, drepturi pe liste de preturi, care toate se folosesc numai in programul ROAFACTURARE
11. ROAFACTURARE - Integrare politici de preturi in ROAFACTURARE - sunt numai editari de liste de preturi, note contabile, nomenclator articole, drepturi pe liste de preturi, care toate se folosesc numai in programul ROAFACTURARE.
12. ROAFACTURARE - sa pot sa folosesc direct nomenclatorul de articole pe post de lista de preturi, sa nu mai definesc liste de preturi, note contabile asociate. Acum am un echivalent (lista de articole din stoc ca o lista de preturi virtuala)
@@ -90,3 +90,14 @@ DONE 21. ROACONT - in formularul de verificare coduri fiscale, ar trebui sa fie
39. ROA - asistent de suport pe documentatia proprie; butonul de chat exista deja in mesajele de eroare, ii lipseste continutul (manual, versiuni, dictionar de erori). (rec_directie_roacont_2026_09.md, 3.6)
40. ROACONT - e-Transport: azi nu exista nimic, concurenta are modul dedicat. (rec_directie_roacont_2026_09.md, 3.7)
41. ROACONT - daca se permite modificarea manuala a sumelor de la TVA, nu se poate si o atentionare daca TVA este altul decat procentul din explicatia de TVA selectata?
42. ROAFACTURARE - configurarea initiala pentru a putea factura un articol - este foarte complexa si vreau mai fluid, poate si cu un wizzard
- definire grup TOTAL in ROADEF si asociere utilizatori in grupul TOTAL
- creare articol in ROAPRETURI
- creare nota contabila vanzare
- creare politica preturi si introducere articol
- definire serii numere facturi
- completare optiuni document factura, aviz, documente incasare, bon fiscal, bon pos
Poate un wizzard