Compare commits
2 Commits
be0ac66399
...
db4b57f5a3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db4b57f5a3 | ||
|
|
f184b2b179 |
13
AGENTS.md
13
AGENTS.md
@@ -231,6 +231,19 @@ Pe Discord/WhatsApp, folosesc reacții emoji natural:
|
||||
|
||||
---
|
||||
|
||||
## 🧾 Procesare Bonuri (OBLIGATORIU)
|
||||
|
||||
Când Marius trimite un **PDF** și scrie "procesează bon" / "bon" / "adaugă bon":
|
||||
1. **Găsesc PDF-ul** în media/inbound (ultimul primit)
|
||||
2. **Rulez dry run:** `python3 tools/process_bon.py <pdf_path>`
|
||||
3. **Arăt rezultatul:** partener, total, TVA, note contabile
|
||||
4. **Aștept confirmare:** "ok" / "salvează" / "da"
|
||||
5. **Salvez:** `python3 tools/process_bon.py <pdf_path> --save`
|
||||
|
||||
**Cuvinte cheie:** "procesează bon", "bon fiscal", "adaugă bon", "înregistrează bon"
|
||||
|
||||
---
|
||||
|
||||
## 🎬 YouTube Notes (OBLIGATORIU)
|
||||
|
||||
Când primesc un link YouTube:
|
||||
|
||||
51
TOOLS.md
51
TOOLS.md
@@ -44,6 +44,40 @@
|
||||
|
||||
**Pentru orice altă adresă:** Citesc și raportez, aștept aprobare.
|
||||
|
||||
### Transcriere Audio/Video (Whisper)
|
||||
- **Model:** OpenAI Whisper (local, CPU)
|
||||
- **Dependințe:** PyTorch CPU, ffmpeg (static binary în ~/bin/)
|
||||
- **Venv:** `~/clawd/venv/`
|
||||
|
||||
**Utilizare:**
|
||||
```bash
|
||||
cd ~/clawd && source venv/bin/activate
|
||||
export PATH="$HOME/bin:$PATH"
|
||||
|
||||
# Transcriere directă
|
||||
python3 -c "
|
||||
import whisper
|
||||
model = whisper.load_model('base')
|
||||
result = model.transcribe('/path/to/audio.mp3', language='ro')
|
||||
print(result['text'])
|
||||
"
|
||||
|
||||
# Download de pe Google Drive + transcriere
|
||||
gdown 'FILE_ID' -O /tmp/audio.mp3
|
||||
```
|
||||
|
||||
**Modele disponibile:**
|
||||
- `tiny` - cel mai rapid, mai puțin precis
|
||||
- `base` - echilibru bun (folosit default)
|
||||
- `small`, `medium`, `large` - mai precise, mai lente
|
||||
|
||||
**Formate suportate:** mp3, mp4, wav, m4a, webm, etc. (orice ffmpeg poate procesa)
|
||||
|
||||
**Note:**
|
||||
- Pe CPU durează mai mult (~1x real-time pentru base)
|
||||
- Pentru română, base e suficient de precis
|
||||
- Transcrierea poate avea erori minore de recunoaștere
|
||||
|
||||
### Dashboard
|
||||
- **URL:** https://moltbot.tailf7372d.ts.net/echo/
|
||||
- **Task add:** `python3 dashboard/update_task.py add in-progress "titlu"`
|
||||
@@ -97,6 +131,23 @@ memory_get path="memory/file.md" from=1 lines=50
|
||||
3. Re-indexează DOAR fișierul modificat (incremental)
|
||||
4. Celelalte fișiere rămân neatinse
|
||||
|
||||
### Procesare Bonuri Fiscale (PDF → Oracle)
|
||||
- **Script:** `python3 tools/process_bon.py <pdf_path> [--save]`
|
||||
- **Comandă:** Când Marius trimite PDF + "procesează bon" sau "bon fiscal"
|
||||
- **Dry run:** fără `--save` - arată ce ar salva
|
||||
- **Salvare:** cu `--save` - salvează efectiv în Oracle
|
||||
|
||||
**Flux:**
|
||||
1. Marius trimite PDF pe WhatsApp/Discord
|
||||
2. Marius scrie: "procesează bon" / "bon" / "adaugă bon"
|
||||
3. Echo rulează dry run, arată rezultatul
|
||||
4. Marius confirmă "ok" / "salvează" → Echo rulează cu --save
|
||||
|
||||
**Ce face scriptul:**
|
||||
- OCR via roa2web API
|
||||
- SQLite: receipt complet
|
||||
- Oracle: partener + note contabile (ID_JTVA, TAXCODE, etc.)
|
||||
|
||||
### Git
|
||||
- **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd
|
||||
- **Commit:** `python3 tools/git_commit.py --push`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-02T22:27:06.452Z",
|
||||
"lastUpdated": "2026-02-03T17:20:07.199Z",
|
||||
"programs": [
|
||||
"ROACONT",
|
||||
"ROAGEST",
|
||||
@@ -21,10 +21,11 @@
|
||||
"program": "ROACONT",
|
||||
"owner": "robert",
|
||||
"priority": "urgent-important",
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"created": "2026-02-02T11:25:18.115Z",
|
||||
"deadline": "2026-02-02",
|
||||
"updated": "2026-02-02T22:27:06.428Z"
|
||||
"updated": "2026-02-02T22:27:06.428Z",
|
||||
"completed": "2026-02-03T17:20:07.195Z"
|
||||
},
|
||||
{
|
||||
"id": "ROA-001",
|
||||
|
||||
@@ -1,5 +1,44 @@
|
||||
# 3 Februarie 2026
|
||||
|
||||
## roa2web WhatsApp Import - COMPLET
|
||||
|
||||
### Ce s-a realizat:
|
||||
1. **OCR prin API** - doctr-plus, ~4 sec per bon (nu 30 sec ca PaddleOCR cold start)
|
||||
2. **Flux complet testat:** PDF WhatsApp → OCR → SQLite → Oracle
|
||||
3. **Scripturi în repo:** `roa2web/backend/scripts/whatsapp_import/`
|
||||
4. **Commit:** `1366dbc` pe main
|
||||
|
||||
### Flux final:
|
||||
```
|
||||
PDF (WhatsApp) → OCR API (~4sec) → SQLite (draft) → Aprobare frontend → Oracle
|
||||
```
|
||||
|
||||
### Probleme rezolvate:
|
||||
- **Oracle pool "SID not found"** - trebuia restart complet backend (kill -9)
|
||||
- **Frontend fără server dropdown** - Marius a fixat și făcut commit
|
||||
- **Server ID** - acum e `central` nu `test`
|
||||
|
||||
### Endpoint-uri API folosite:
|
||||
- `POST /api/auth/login` - cu server_id="central"
|
||||
- `POST /api/auth/check-identity` - verifică user și returnează servere
|
||||
- `POST /api/data-entry/ocr/extract` - submit OCR job
|
||||
- `GET /api/data-entry/ocr/jobs/{id}` - rezultat OCR
|
||||
- `POST /api/data-entry/receipts/` - creare receipt în SQLite
|
||||
|
||||
### Test real efectuat:
|
||||
- Bon Dedeman (RO10562600) primit pe WhatsApp
|
||||
- OCR: 5.2 sec, confidence 96%
|
||||
- Salvat în SQLite: ID=73, status=draft
|
||||
- Salvat și în Oracle: COD=1140631, luna 01/2026
|
||||
|
||||
### Locații importante (claude-agent LXC 171):
|
||||
- Backend: http://localhost:8000 (sau claude-agent:8000)
|
||||
- Frontend: http://localhost:3000 (sau claude-agent:3000)
|
||||
- Scripturi: `/workspace/roa2web/backend/scripts/whatsapp_import/`
|
||||
- Start: `./start.sh central`
|
||||
|
||||
---
|
||||
|
||||
## Decizii
|
||||
- (în așteptare raport dimineață)
|
||||
|
||||
@@ -13,6 +52,10 @@
|
||||
- [ ] A2: Sistemul 5 pași pentru frici (15 min) - de programat
|
||||
- [ ] Verificare securitate Clawdbot (din insights tehnice)
|
||||
- [ ] Verificare email replies (flux nefuncțional?)
|
||||
- [ ] **BON DE SALVAT:** CUI RO11201891, 310.98 RON, 02.02.2026
|
||||
- PDF: `2831eeeb-f331-4fb1-a7b1-ede1c954eadb.pdf`
|
||||
- Partener nou - de verificat numele real
|
||||
- Dry run făcut, așteaptă confirmare
|
||||
|
||||
## Insights disponibile (din 2026-02-03.md)
|
||||
- ⚡ Heartbeat cost optimization - VERIFICAT, monitorizăm
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"lastChecks": {
|
||||
"agents_sync": "2026-02-02",
|
||||
"email": 1770044415,
|
||||
"calendar": null,
|
||||
"git": 1769965200,
|
||||
"agents_sync": "2026-02-03",
|
||||
"email": 1770206400,
|
||||
"calendar": 1770206400,
|
||||
"git": 1770220800,
|
||||
"kb_index": 1770022820
|
||||
},
|
||||
"notes": {
|
||||
"2026-02-02": "15:00 UTC - Email OK (nimic nou). Cron jobs funcționale toată ziua."
|
||||
"2026-02-02": "15:00 UTC - Email OK (nimic nou). Cron jobs funcționale toată ziua.",
|
||||
"2026-02-03": "12:00 UTC - Calendar: sesiune 15:00 alertată. Emailuri răspuns rapoarte în inbox (deja read)."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@
|
||||
"project": null,
|
||||
"subdir": null,
|
||||
"video": "",
|
||||
"tldr": "*Surse: Video-uri tehnice Clawdbot/Claude Code*"
|
||||
"tldr": "*Surse: Video-uri tehnice Clawdbot/Claude Code/Lead Generation*"
|
||||
},
|
||||
{
|
||||
"file": "notes-data/projects/analiza-telegram-whatsapp-roa2web.md",
|
||||
"title": "Analiză: Telegram/WhatsApp → roa2web → Contabilitate ROA",
|
||||
"file": "notes-data/projects/roa2web-telegram-import/README.md",
|
||||
"title": "Proiect: Import Bonuri Fiscale via Telegram/WhatsApp → ROA",
|
||||
"date": "2026-02-03",
|
||||
"tags": [],
|
||||
"domains": [
|
||||
@@ -78,27 +78,55 @@
|
||||
"project"
|
||||
],
|
||||
"category": "projects",
|
||||
"project": null,
|
||||
"project": "roa2web-telegram-import",
|
||||
"subdir": null,
|
||||
"video": "",
|
||||
"tldr": "Integrare canale messaging (Telegram/WhatsApp) cu roa2web pentru import documente în contabilitatea ROA. OCR prin Doctr (cost zero, local). Flux cu aprobare contabil."
|
||||
"tldr": "Sistem pentru importul bonurilor fiscale de achiziție din Telegram/WhatsApp în contabilitatea ROA. OCR prin Doctr (cost zero, local). Integrare cu Oracle prin proceduri existente (PACK_CONTAFIN)."
|
||||
},
|
||||
{
|
||||
"file": "notes-data/projects/analiza-import-bonuri-pdf.md",
|
||||
"title": "Analiză: Sistem Import Bonuri PDF via Telegram/Discord/WhatsApp → roa2web",
|
||||
"file": "notes-data/projects/roa2web-telegram-import/schema-oracle.md",
|
||||
"title": "Schema Oracle - ROA (MARIUSM_AUTO)",
|
||||
"date": "2026-02-03",
|
||||
"tags": [],
|
||||
"domains": [
|
||||
"work"
|
||||
],
|
||||
"types": [
|
||||
"project"
|
||||
],
|
||||
"domains": [],
|
||||
"types": [],
|
||||
"category": "projects",
|
||||
"project": null,
|
||||
"project": "roa2web-telegram-import",
|
||||
"subdir": null,
|
||||
"video": "",
|
||||
"tldr": "Sistem pentru importul bonurilor fiscale (PDF/imagine) în ERP ROA prin canale de mesagerie. Utilizatorul trimite poza bonului → OCR extrage datele → roa2web validează și importă în Oracle."
|
||||
"tldr": "*Schema documentată de Echo • 2026-02-03*"
|
||||
},
|
||||
{
|
||||
"file": "notes-data/projects/roa2web-telegram-import/flux-contabil.md",
|
||||
"title": "Flux Contabil - Import Bonuri Fiscale Achiziție",
|
||||
"date": "2026-02-03",
|
||||
"tags": [],
|
||||
"domains": [],
|
||||
"types": [],
|
||||
"category": "projects",
|
||||
"project": "roa2web-telegram-import",
|
||||
"subdir": null,
|
||||
"video": "",
|
||||
"tldr": "*Flux documentat de Echo • 2026-02-03*"
|
||||
},
|
||||
{
|
||||
"file": "notes-data/projects/grup-sprijin/biblioteca/meditatie-vizualizare-motivatie.md",
|
||||
"title": "Meditație: Vizualizare pentru Motivație",
|
||||
"date": "2026-02-03",
|
||||
"tags": [
|
||||
"grup-sprijin"
|
||||
],
|
||||
"domains": [
|
||||
"sprijin"
|
||||
],
|
||||
"types": [
|
||||
"meditatie"
|
||||
],
|
||||
"category": "projects",
|
||||
"project": "grup-sprijin",
|
||||
"subdir": "biblioteca",
|
||||
"video": "",
|
||||
"tldr": "Exercițiu de vizualizare care leagă o acțiune pentru care vrei motivație de o stare de plăcere intensă din trecut. Folosește tehnica \"fissurii în ecran\" pentru a transfera emoțional motivația."
|
||||
},
|
||||
{
|
||||
"file": "notes-data/youtube/2026-02-03_openclaw-72-hours-full-breakdown.md",
|
||||
@@ -1689,12 +1717,12 @@
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"total": 92,
|
||||
"total": 94,
|
||||
"by_domain": {
|
||||
"work": 27,
|
||||
"work": 26,
|
||||
"health": 16,
|
||||
"growth": 33,
|
||||
"sprijin": 26,
|
||||
"sprijin": 27,
|
||||
"scout": 2
|
||||
},
|
||||
"by_category": {
|
||||
@@ -1702,7 +1730,7 @@
|
||||
"emails": 1,
|
||||
"health": 1,
|
||||
"insights": 8,
|
||||
"projects": 23,
|
||||
"projects": 25,
|
||||
"reflectii": 3,
|
||||
"retete": 1,
|
||||
"youtube": 38,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Insights - 3 Februarie 2026
|
||||
|
||||
**Surse procesate:** 3 note tehnice noi + 1 insight anterior
|
||||
**Focus:** Optimizări Clawdbot + Multi-agent orchestration
|
||||
**Actualizat:** 06:00 UTC
|
||||
**Surse procesate:** 5 note tehnice noi + insights anterioare
|
||||
**Focus:** Optimizări Clawdbot + Multi-agent + **Lead Generation pentru clienți noi**
|
||||
**Actualizat:** 17:00 UTC (19:00 București)
|
||||
|
||||
---
|
||||
|
||||
## 🔗 CONEXIUNE: De la Tool la Companion
|
||||
## 🔗 CONEXIUNE: De la Tool la Companion → la CLIENȚI NOI
|
||||
|
||||
**Pattern descoperit:** Notele tehnice de azi completează un cerc important:
|
||||
|
||||
@@ -16,10 +16,17 @@ TOOL (Clawdbot) ← COST OPTIMIZATION ← MULTI-AGENT ← SECURITATE
|
||||
MARIUS: 80/20 mindset
|
||||
↓
|
||||
APLICARE: Delegare eficientă, nu micromanagement
|
||||
↓
|
||||
⚡ NOU: Automatizare lead generation =
|
||||
deblocare "nu caut clienți noi"
|
||||
```
|
||||
|
||||
**Insight cheie seară:** Nota despre "Unlimited Leads with Claude Code" atacă DIRECT provocarea principală a lui Marius: inacțiunea în căutarea clienților noi.
|
||||
|
||||
Ironia: Clawdbot (pe care rulăm) e exemplul perfect de "do things, not suggest things" - exact ce Marius vrea de la angajatul nou!
|
||||
|
||||
**Și acum:** Poate face lead generation automat, eliminând FRICȚIA care probabil cauzează inacțiunea.
|
||||
|
||||
---
|
||||
|
||||
## @work - Tehnic și business
|
||||
@@ -158,6 +165,64 @@ MULTI-AGENT (dorit):
|
||||
|
||||
---
|
||||
|
||||
### [ ] ⚡ **COLD EMAIL AUTOMATIZAT - Soluția pentru "nu caut clienți noi" (prioritate: ⚡urgent)**
|
||||
|
||||
**Context:** Din video-ul "How I Get Unlimited Leads Using Claude Code" - o agenție a construit sistem de lead generation care procesează 272,000 leads/secundă.
|
||||
|
||||
**Esența PROFUNDĂ:**
|
||||
James, care NU știa să codeze, a construit întregul sistem într-o săptămână după ce a învățat Claude Code timp de 3 săptămâni. Nu e vorba de "învață programare", ci de "descrie ce vrei și lasă AI-ul să construiască".
|
||||
|
||||
**Conexiune DIRECTĂ cu Marius:**
|
||||
|
||||
1. **Credința limitativă:** "Clienți noi = mai multă muncă"
|
||||
- **Realitate:** Sistemul automatizat ELIMINĂ munca manuală de prospecting
|
||||
- Cold email la scară = AI face screening-ul, tu vorbești doar cu cei interesați
|
||||
|
||||
2. **Inacțiune în căutarea clienților:**
|
||||
- **Cauza profundă:** Probabil nu e lene, ci FRICȚIE - e obositor să faci manual
|
||||
- **Soluția 80/20:** Automatizează partea grea (găsit leads, validat emails, trimis), rămâi doar cu conversațiile
|
||||
|
||||
3. **Model de business ROA:**
|
||||
- Clienții lui sunt software houses cu ERP-uri
|
||||
- Cold email către companii care au nevoie de soluții Oracle/contabilitate
|
||||
- Google Ads library scraper → găsești companii care rulează ads (= au buget)
|
||||
|
||||
**Ce au construit ei (și ce s-ar putea adapta):**
|
||||
- Lead Processor: validare email în timp real
|
||||
- Ad Library Scrapers: găsesc companii care rulează ads Google/LinkedIn
|
||||
- Auto-Refill: când rămâi fără leads, se reîncarcă automat
|
||||
- Executive Summary: raport AI despre ce funcționează
|
||||
|
||||
**Rezultate lor:**
|
||||
- RB2B: $4M ARR în 4 luni (42% din cold email)
|
||||
- Fixer AI: $4.3M pipeline anual
|
||||
- 8.8 milioane emails/lună
|
||||
|
||||
**Acțiune concretă propusă:**
|
||||
|
||||
**Varianta MINIMĂ (80/20):**
|
||||
1. Echo creează un scraper simplu care găsește companii românești care:
|
||||
- Au anunțuri de angajare pentru contabil/economist
|
||||
- Sau postează despre ERP/software contabilitate pe LinkedIn
|
||||
2. Lista → manual review de Marius (5 min/zi)
|
||||
3. Template email personalizat per industrie
|
||||
4. Trimitere semi-automată
|
||||
|
||||
**Efort:** Echo ~4h setup, Marius ~30 min/săptămână review
|
||||
**Potențial:** 5-10 leads calificate/săptămână
|
||||
|
||||
**⚠️ ÎNTREBARE pentru Marius:**
|
||||
"Dacă ai avea o listă de 10 companii/săptămână care au nevoie DEMONSTRABILĂ de soluții ROA, și un email template gata de trimis, ai acționa?"
|
||||
|
||||
Dacă răspunsul e DA → construiesc sistemul.
|
||||
Dacă răspunsul e "tot nu aș face" → problema nu e lipsa lead-urilor, ci altceva mai profund.
|
||||
|
||||
**✅ RECOMAND** - direct pe provocarea principală, efort mic pentru varianta minimă
|
||||
|
||||
**Sursă:** [How I Get Unlimited Leads Using Claude Code](files.html#memory/kb/youtube/2026-02-03_unlimited-leads-claude-code-cold-email.md)
|
||||
|
||||
---
|
||||
|
||||
### [ ] 💡 **DON'T WORK ON APP, WORK ON AGENTS (prioritate: 💡nice)**
|
||||
|
||||
**Context:** Citat transformator:
|
||||
@@ -241,33 +306,47 @@ MULTI-AGENT (dorit):
|
||||
| Angajat nou | Control vs autonomie | Nivele de trust progresive |
|
||||
| Clienți noi | Efort vs venit | Automatizează prospectarea |
|
||||
|
||||
### Tema: INACȚIUNE CLIENȚI NOI (NOU!)
|
||||
|
||||
| Barieră percepută | Realitate | Soluție |
|
||||
|-------------------|-----------|---------|
|
||||
| "E prea multă muncă" | Munca manuală da, automatizat nu | Sistem lead gen automat |
|
||||
| "Nu știu unde să caut" | AI poate găsi semnale (ads, hiring) | Scrapers LinkedIn/Google |
|
||||
| "Cold email nu funcționează" | La ei: 42% din revenue = cold email | Template + personalizare |
|
||||
| "Nu am timp" | 30 min/săptămână pentru review | Echo face restul |
|
||||
|
||||
---
|
||||
|
||||
## ❓ Întrebări pentru Marius
|
||||
|
||||
1. **Vrei să verificăm configurația de securitate Clawdbot?** E meta - video-ul e despre tool-ul pe care îl folosim.
|
||||
1. **CLIENȚI NOI (cea mai importantă):** Dacă ai avea o listă de 10 companii/săptămână care au nevoie demonstrabilă de soluții ROA, și un email template gata de trimis, ai acționa? (Răspunsul sincer la asta ne spune dacă problema e fricțiune sau altceva mai profund)
|
||||
|
||||
2. **Pentru angajat: ce nivel de sandbox ar fi confortabil?** Definit, Parametrizat, sau Autonom?
|
||||
2. **Vrei să verificăm configurația de securitate Clawdbot?** E meta - video-ul e despre tool-ul pe care îl folosim.
|
||||
|
||||
3. **Ai experimentat cu "coding overnight"?** Descrii seara, review dimineața?
|
||||
3. **Pentru angajat: ce nivel de sandbox ar fi confortabil?** Definit, Parametrizat, sau Autonom?
|
||||
|
||||
4. **Ce "agenți" (documentație/template) ar putea face training-ul pentru tine?**
|
||||
4. **Ai experimentat cu "coding overnight"?** Descrii seara, review dimineața?
|
||||
|
||||
5. **Ce "agenți" (documentație/template) ar putea face training-ul pentru tine?**
|
||||
|
||||
---
|
||||
|
||||
## 📊 Statistici procesare
|
||||
|
||||
**Surse noi:** 3 note tehnice
|
||||
**Surse procesate azi:** 5 note tehnice
|
||||
- OpenClaw 72h Breakdown
|
||||
- Clawdbot Cost Optimization
|
||||
- Claude Code Task System
|
||||
- **NOU:** Unlimited Leads Claude Code Cold Email
|
||||
- OpenClaw Use Cases Automations
|
||||
|
||||
**Insights extrase:** 7 total (+ 1 anterior păstrat)
|
||||
- ⚡ Urgent: 2 (securitate, cost)
|
||||
**Insights extrase:** 8 total
|
||||
- ⚡ Urgent: 3 (securitate, cost, **COLD EMAIL/CLIENȚI NOI**)
|
||||
- 📌 Important: 4 (delegare, multi-agent, overnight, fundamentele)
|
||||
- 💡 Nice: 1 (meta-level work)
|
||||
|
||||
**Conexiuni cu provocările lui Marius:**
|
||||
- **Inacțiune clienți noi → 1 insight DIRECT și acționabil**
|
||||
- Angajat nou și training → 3 insights directe
|
||||
- Stil 80/20 → 2 insights directe
|
||||
- Securitate infrastructură → 1 insight
|
||||
@@ -277,5 +356,6 @@ MULTI-AGENT (dorit):
|
||||
|
||||
---
|
||||
|
||||
*Actualizat: 2026-02-03 06:00 UTC*
|
||||
*Surse: Video-uri tehnice Clawdbot/Claude Code*
|
||||
*Actualizat: 2026-02-03 17:00 UTC (19:00 București)*
|
||||
*Run: insights-extract seară*
|
||||
*Surse: Video-uri tehnice Clawdbot/Claude Code/Lead Generation*
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
# Analiză: Sistem Import Bonuri PDF via Telegram/Discord/WhatsApp → roa2web
|
||||
|
||||
**Data:** 2026-02-03
|
||||
**Status:** Analiză conceptuală
|
||||
**Tags:** @work @project
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Sistem pentru importul bonurilor fiscale (PDF/imagine) în ERP ROA prin canale de mesagerie. Utilizatorul trimite poza bonului → OCR extrage datele → roa2web validează și importă în Oracle.
|
||||
|
||||
---
|
||||
|
||||
## 1. Arhitectură Propusă
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ Telegram │ │ │ │ │ │ │
|
||||
│ Discord │────▶│ Clawdbot │────▶│ OCR Engine │────▶│ roa2web │
|
||||
│ WhatsApp │ │ (Router) │ │ (Parsare) │ │ (FastAPI) │
|
||||
└─────────────┘ └─────────────┘ └──────────────┘ └─────────────┘
|
||||
│ │ │
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
• Primește fișier • Tesseract/Mistral • Validare date
|
||||
• Identifică tip • Extrage câmpuri • Import Oracle
|
||||
• Rutare canal • Structurează JSON • Confirmare user
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Componente Tehnice
|
||||
|
||||
### 2.1 Canale Inbound (Clawdbot)
|
||||
|
||||
| Canal | Cum primește | Format acceptat |
|
||||
|-------|--------------|-----------------|
|
||||
| Telegram | Bot API / file_id | PDF, JPG, PNG |
|
||||
| Discord | Attachment | PDF, JPG, PNG |
|
||||
| WhatsApp | Media message | PDF, JPG, PNG |
|
||||
|
||||
**Clawdbot poate:**
|
||||
- Detecta atașamente pe orice canal
|
||||
- Descărca fișierul local temporar
|
||||
- Ruta către procesare OCR
|
||||
|
||||
### 2.2 OCR Engine
|
||||
|
||||
**Opțiuni (în ordinea complexității):**
|
||||
|
||||
| Soluție | Pro | Contra | Efort |
|
||||
|---------|-----|--------|-------|
|
||||
| **Tesseract + regex** | Gratuit, local | Acuratețe medie, layout-uri diverse | Mic |
|
||||
| **Mistral OCR API** | Calitate bună, JSON direct | Cost per request | Mic |
|
||||
| **Claude Vision** | Excelent la context | Cost mai mare | Mic |
|
||||
| **Google Document AI** | Enterprise, structurat | Cost, setup complex | Mare |
|
||||
|
||||
**Recomandare:** Mistral OCR sau Claude Vision - calitate bună, integrare simplă cu Clawdbot.
|
||||
|
||||
### 2.3 Câmpuri de Extras din Bon
|
||||
|
||||
```json
|
||||
{
|
||||
"tip_document": "bon_fiscal",
|
||||
"data": "2026-02-03",
|
||||
"ora": "14:32",
|
||||
"furnizor": {
|
||||
"nume": "MEGA IMAGE SRL",
|
||||
"cui": "RO12345678",
|
||||
"adresa": "Str. Exemplu nr. 1"
|
||||
},
|
||||
"articole": [
|
||||
{"denumire": "Paine alba", "cantitate": 1, "pret_unitar": 4.50, "valoare": 4.50},
|
||||
{"denumire": "Lapte 1L", "cantitate": 2, "pret_unitar": 8.00, "valoare": 16.00}
|
||||
],
|
||||
"total": 20.50,
|
||||
"tva": {
|
||||
"cota_9": 1.50,
|
||||
"cota_19": 0.50
|
||||
},
|
||||
"numar_bon": "0001234",
|
||||
"casa_marcat": "ABC12345"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 roa2web Integration
|
||||
|
||||
**Endpoint propus:** `POST /api/data-entry/import-bon`
|
||||
|
||||
```python
|
||||
# FastAPI endpoint
|
||||
@router.post("/import-bon")
|
||||
async def import_bon(
|
||||
bon_data: BonFiscalSchema,
|
||||
user_id: str = Depends(get_current_user)
|
||||
):
|
||||
# 1. Validare date (CUI valid, sume corecte)
|
||||
# 2. Mapare furnizor în baza ROA
|
||||
# 3. Creare document intrare marfă
|
||||
# 4. Return confirmare + document_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Flux Utilizator
|
||||
|
||||
### 3.1 Happy Path
|
||||
|
||||
1. **Marius** face poză la bon în magazin
|
||||
2. **Trimite** pe Telegram la @ROABot (sau grup dedicat)
|
||||
3. **Clawdbot** detectează imagine, descarcă
|
||||
4. **OCR** extrage datele, validează structura
|
||||
5. **Clawdbot** trimite preview: "Am extras: Mega Image, 20.50 RON, 3 articole. Confirm import? ✅/❌"
|
||||
6. **Marius** confirmă (sau corectează)
|
||||
7. **roa2web** importă în Oracle
|
||||
8. **Confirmare**: "✅ Bon importat. Document #12345"
|
||||
|
||||
### 3.2 Edge Cases
|
||||
|
||||
| Situație | Handling |
|
||||
|----------|----------|
|
||||
| Poză neclară | "Nu am putut citi bonul. Retrimite o poză mai clară." |
|
||||
| Furnizor nou | "Furnizor MEGA IMAGE nu există. Creez? [Da/Nu]" |
|
||||
| Articol necunoscut | "Articol 'Paine alba' nu are corespondent. Alege: [1] Paine [2] Produse panificatie [3] Skip" |
|
||||
| PDF protejat | "PDF-ul e protejat. Trimite ca imagine." |
|
||||
|
||||
---
|
||||
|
||||
## 4. Provocări și Soluții
|
||||
|
||||
### 4.1 Calitatea imaginii
|
||||
- **Problemă:** Poze făcute pe fugă, iluminate prost
|
||||
- **Soluție:**
|
||||
- Pre-procesare imagine (contrast, deskew)
|
||||
- Fallback la input manual dacă OCR confidence < 70%
|
||||
|
||||
### 4.2 Varietatea formatelor
|
||||
- **Problemă:** Fiecare comerciant are alt layout
|
||||
- **Soluție:**
|
||||
- LLM (Claude/Mistral) extrage semantic, nu pe poziție
|
||||
- Template-uri pentru comercianți frecvenți (Mega, Lidl, Kaufland)
|
||||
|
||||
### 4.3 Mapare articole
|
||||
- **Problemă:** "Lapte Zuzu 1L 3.5%" vs cod ROA "LAPTE_001"
|
||||
- **Soluție:**
|
||||
- Fuzzy matching pe denumire
|
||||
- Tabel mapări (bon_text → cod_roa)
|
||||
- Learning: salvează mapările confirmate
|
||||
|
||||
### 4.4 Rate limiting canale
|
||||
- **Problemă:** WhatsApp/Telegram pot limita
|
||||
- **Soluție:**
|
||||
- Queue local pentru procesare
|
||||
- Confirmare async ("Procesez, te anunț în 30 sec")
|
||||
|
||||
---
|
||||
|
||||
## 5. Plan Implementare
|
||||
|
||||
### Faza 1: POC (2-3 zile)
|
||||
- [ ] Endpoint Clawdbot pentru primire fișier
|
||||
- [ ] Integrare Mistral OCR / Claude Vision
|
||||
- [ ] Parsare bon simplu (1 comerciant test)
|
||||
- [ ] Răspuns pe canal cu datele extrase
|
||||
|
||||
### Faza 2: Integrare roa2web (3-5 zile)
|
||||
- [ ] Endpoint FastAPI `/api/import-bon`
|
||||
- [ ] Validare și mapare furnizor
|
||||
- [ ] Creare document Oracle
|
||||
- [ ] Confirmare utilizator
|
||||
|
||||
### Faza 3: Polish (2-3 zile)
|
||||
- [ ] Handling edge cases
|
||||
- [ ] Template-uri comercianți mari
|
||||
- [ ] Tabel mapări articole
|
||||
- [ ] Logging și statistici
|
||||
|
||||
### Faza 4: Extindere (opțional)
|
||||
- [ ] Suport pentru mai multe tipuri documente (facturi, chitanțe)
|
||||
- [ ] Batch import (multiple bonuri)
|
||||
- [ ] Dashboard statistici achiziții
|
||||
|
||||
---
|
||||
|
||||
## 6. Efort Estimat
|
||||
|
||||
| Componentă | Ore | Cine |
|
||||
|------------|-----|------|
|
||||
| Clawdbot file handler | 2-4 | Echo/Claude |
|
||||
| OCR integration | 2-3 | Echo/Claude |
|
||||
| roa2web endpoint | 4-6 | Marius + Claude |
|
||||
| Mapări și validări | 4-8 | Marius |
|
||||
| **Total MVP** | **12-21 ore** | Mix |
|
||||
|
||||
**Cost OCR estimat:** ~$0.01-0.05 per bon (Claude Vision sau Mistral)
|
||||
|
||||
---
|
||||
|
||||
## 7. Beneficii
|
||||
|
||||
- **Timp economisit:** 2-5 min/bon → 10 sec/bon
|
||||
- **Erori reduse:** OCR consistent vs. tastare manuală
|
||||
- **Mobilitate:** Import din teren, nu doar de la birou
|
||||
- **Trasabilitate:** Fiecare bon are sursa (poza originală)
|
||||
|
||||
---
|
||||
|
||||
## 8. Următorii Pași
|
||||
|
||||
1. **Marius decide:** Merită efortul? Câte bonuri/lună?
|
||||
2. **Test rapid:** Un bon de la Mega Image → Claude Vision → vezi output
|
||||
3. **Prototip:** Clawdbot + Claude Vision → răspuns formatat
|
||||
|
||||
---
|
||||
|
||||
## 9. Întrebări pentru Marius
|
||||
|
||||
1. Câte bonuri/documente procesezi lunar manual?
|
||||
2. Care sunt cei mai frecvenți furnizori?
|
||||
3. Ce câmpuri sunt obligatorii în ROA pentru intrare marfă?
|
||||
4. Preferi confirmare înainte de import sau import direct cu corecție ulterioară?
|
||||
|
||||
---
|
||||
|
||||
*Analiză generată de Echo • 2026-02-03 03:00*
|
||||
@@ -1,263 +0,0 @@
|
||||
# Analiză: Telegram/WhatsApp → roa2web → Contabilitate ROA
|
||||
|
||||
**Data:** 2026-02-03
|
||||
**Status:** Analiză tehnică actualizată după review cod
|
||||
**Tags:** @work @project
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Integrare canale messaging (Telegram/WhatsApp) cu roa2web pentru import documente în contabilitatea ROA. OCR prin Doctr (cost zero, local). Flux cu aprobare contabil.
|
||||
|
||||
**UPDATE:** După analiza codului, roa2web are deja:
|
||||
- ✅ OCR complet (Doctr + PaddleOCR + Tesseract)
|
||||
- ✅ API `/api/data-entry/ocr/extract` funcțional
|
||||
- ✅ Bot Telegram pentru dashboard/facturi/sold
|
||||
- ❌ **LIPSEȘTE:** Handler fișiere în bot Telegram
|
||||
- ❌ **LIPSEȘTE:** PDF text layer extraction (optimizare pentru Adobe Scan)
|
||||
|
||||
---
|
||||
|
||||
## 1. Ce Există Deja
|
||||
|
||||
### roa2web
|
||||
- **OCR:** Doctr (local, gratuit, rezultate bune)
|
||||
- **Storage:** SQLite local (bonuri procesate)
|
||||
- **API:** FastAPI endpoints
|
||||
|
||||
### Clawdbot
|
||||
- **Canale:** Telegram ✅, WhatsApp ✅, Discord ✅
|
||||
- **Capabilități:** Primire fișiere, rutare, răspuns
|
||||
|
||||
### ROA (ERP)
|
||||
- **DB:** Oracle
|
||||
- **Contabilitate:** Module existente pentru intrări/facturi
|
||||
|
||||
---
|
||||
|
||||
## 2. Ce Lipsește (Gap Analysis)
|
||||
|
||||
| Component | Status | Ce trebuie |
|
||||
|-----------|--------|------------|
|
||||
| Telegram → roa2web | ❌ | Endpoint webhook sau polling |
|
||||
| WhatsApp → roa2web | ❌ | Endpoint webhook sau polling |
|
||||
| roa2web → Oracle | ❌ | API salvare în contabilitate |
|
||||
| Workflow aprobare | ❌ | UI contabil + status draft/approved |
|
||||
|
||||
---
|
||||
|
||||
## 3. Arhitectură Propusă
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Telegram │ │ │ │ │ │ │
|
||||
│ WhatsApp │────▶│ Clawdbot │────▶│ roa2web │────▶│ ROA Oracle │
|
||||
└─────────────┘ │ (Bridge) │ │ (OCR+API) │ │ (Contab) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
• Primește fișier • Doctr OCR • Salvare draft
|
||||
• Forward la API • Extrage date • Aprobare contabil
|
||||
• Răspuns user • Validare • Înregistrare finală
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Opțiuni Implementare
|
||||
|
||||
### Opțiunea A: Clawdbot ca Bridge (RECOMANDAT)
|
||||
|
||||
**Flux:**
|
||||
1. User trimite bon pe Telegram/WhatsApp
|
||||
2. Clawdbot detectează fișier, îl descarcă
|
||||
3. Clawdbot trimite fișierul la `roa2web/api/upload`
|
||||
4. roa2web procesează cu Doctr, returnează JSON
|
||||
5. Clawdbot trimite răspuns user: "Bon procesat: Mega Image, 45.50 RON"
|
||||
6. roa2web salvează draft în Oracle (status: pending)
|
||||
7. Contabil vede în UI, aprobă → status: approved
|
||||
|
||||
**Pro:**
|
||||
- Folosește Clawdbot existent
|
||||
- Nu modifică roa2web prea mult
|
||||
- Flexibilitate pe canale
|
||||
|
||||
**Contra:**
|
||||
- Clawdbot trebuie să știe să ruteze fișiere
|
||||
|
||||
**Efort:** 8-12 ore
|
||||
|
||||
### Opțiunea B: Webhook Direct în roa2web
|
||||
|
||||
**Flux:**
|
||||
1. Telegram/WhatsApp webhook direct la roa2web
|
||||
2. roa2web procesează și salvează
|
||||
3. roa2web trimite răspuns înapoi pe canal
|
||||
|
||||
**Pro:**
|
||||
- Mai direct, fără intermediar
|
||||
|
||||
**Contra:**
|
||||
- Trebuie implementat handler pentru fiecare canal
|
||||
- Duplicare logică cu Clawdbot
|
||||
|
||||
**Efort:** 15-20 ore
|
||||
|
||||
### Opțiunea C: Shared Folder / Email
|
||||
|
||||
**Flux:**
|
||||
1. User trimite pe canal → Clawdbot salvează în folder
|
||||
2. roa2web monitorizează folder, procesează automat
|
||||
|
||||
**Pro:**
|
||||
- Simplu, decuplat
|
||||
|
||||
**Contra:**
|
||||
- Fără feedback instant la user
|
||||
- Polling inefficient
|
||||
|
||||
**Efort:** 4-6 ore
|
||||
|
||||
---
|
||||
|
||||
## 5. Recomandare: Opțiunea A (Clawdbot Bridge)
|
||||
|
||||
### 5.1 Ce trebuie în Clawdbot
|
||||
|
||||
```python
|
||||
# Pseudo-cod: handler pentru fișiere pe Telegram/WhatsApp
|
||||
async def on_file_received(channel, file, user):
|
||||
# 1. Descarcă fișierul
|
||||
local_path = await download_file(file)
|
||||
|
||||
# 2. Trimite la roa2web
|
||||
response = await http_post(
|
||||
"https://roa2web.romfast.ro/api/ocr/process",
|
||||
files={"file": open(local_path, "rb")},
|
||||
data={"user_id": user.id, "source": channel}
|
||||
)
|
||||
|
||||
# 3. Răspuns la user
|
||||
if response.ok:
|
||||
data = response.json()
|
||||
await reply(f"✅ Procesat: {data['furnizor']}, {data['total']} RON")
|
||||
else:
|
||||
await reply("❌ Eroare procesare. Încearcă din nou.")
|
||||
```
|
||||
|
||||
### 5.2 Ce trebuie în roa2web
|
||||
|
||||
**Endpoint nou:** `POST /api/ocr/process`
|
||||
- Primește fișier (PDF/imagine)
|
||||
- Procesează cu Doctr (existent)
|
||||
- Salvează în SQLite (existent) + Oracle (NOU)
|
||||
- Returnează JSON cu datele extrase
|
||||
|
||||
**Endpoint nou:** `POST /api/contabilitate/save-draft`
|
||||
- Primește datele extrase
|
||||
- Creează înregistrare draft în Oracle
|
||||
- Status: pending_approval
|
||||
|
||||
**Endpoint nou:** `POST /api/contabilitate/approve/{id}`
|
||||
- Contabil aprobă
|
||||
- Status: approved → înregistrare finală
|
||||
|
||||
### 5.3 UI Contabil (opțional, faza 2)
|
||||
|
||||
- Lista documente pending
|
||||
- Preview date extrase vs. imagine originală
|
||||
- Buton Approve / Reject / Edit
|
||||
|
||||
---
|
||||
|
||||
## 6. Integrare Oracle - Detalii
|
||||
|
||||
### Ce tabele în ROA?
|
||||
|
||||
**Întrebare pentru Marius:**
|
||||
- Unde se salvează intrările de marfă/bonuri în Oracle?
|
||||
- Ce câmpuri sunt obligatorii?
|
||||
- Există API/proceduri Oracle existente pentru insert?
|
||||
|
||||
### Propunere structură draft
|
||||
|
||||
```sql
|
||||
-- Tabel nou pentru documente OCR pending
|
||||
CREATE TABLE roa_ocr_drafts (
|
||||
id NUMBER PRIMARY KEY,
|
||||
source VARCHAR2(20), -- 'telegram', 'whatsapp'
|
||||
user_id VARCHAR2(50),
|
||||
file_path VARCHAR2(500),
|
||||
extracted_data CLOB, -- JSON cu datele OCR
|
||||
status VARCHAR2(20), -- 'pending', 'approved', 'rejected'
|
||||
created_at TIMESTAMP,
|
||||
approved_by VARCHAR2(50),
|
||||
approved_at TIMESTAMP,
|
||||
roa_document_id NUMBER -- FK la documentul creat în ROA după aprobare
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Plan Implementare
|
||||
|
||||
### Faza 1: Conectare canale (3-4 ore)
|
||||
- [ ] Clawdbot: handler fișiere Telegram
|
||||
- [ ] Clawdbot: handler fișiere WhatsApp
|
||||
- [ ] Forward la roa2web API
|
||||
|
||||
### Faza 2: roa2web API (4-6 ore)
|
||||
- [ ] Endpoint `/api/ocr/process` (extinde existent)
|
||||
- [ ] Returnare JSON standardizat
|
||||
- [ ] Logging și error handling
|
||||
|
||||
### Faza 3: Salvare Oracle (4-6 ore)
|
||||
- [ ] Conexiune Oracle din roa2web (cx_Oracle/oracledb)
|
||||
- [ ] Tabel `roa_ocr_drafts`
|
||||
- [ ] Endpoint `/api/contabilitate/save-draft`
|
||||
|
||||
### Faza 4: Aprobare (2-3 ore)
|
||||
- [ ] Endpoint `/api/contabilitate/approve`
|
||||
- [ ] Notificare user după aprobare
|
||||
|
||||
### Faza 5: UI Contabil (opțional, 4-8 ore)
|
||||
- [ ] Pagină listare drafts
|
||||
- [ ] Aprobare/respingere din UI
|
||||
|
||||
---
|
||||
|
||||
## 8. Estimare Totală
|
||||
|
||||
| Fază | Ore | Cine |
|
||||
|------|-----|------|
|
||||
| Conectare canale | 3-4 | Echo (Clawdbot config) |
|
||||
| roa2web API | 4-6 | Marius + Claude |
|
||||
| Salvare Oracle | 4-6 | Marius (cunoaște schema) |
|
||||
| Aprobare | 2-3 | Marius + Claude |
|
||||
| **Total MVP** | **13-19 ore** | |
|
||||
| UI Contabil (opț.) | 4-8 | Marius |
|
||||
|
||||
**Cost:** 0 RON (Doctr local, fără API externe)
|
||||
|
||||
---
|
||||
|
||||
## 9. Întrebări pentru Marius
|
||||
|
||||
1. **Schema Oracle:** În ce tabel/modul se salvează bonurile în contabilitate?
|
||||
2. **Câmpuri obligatorii:** Ce date TREBUIE să existe pentru o înregistrare validă?
|
||||
3. **Contabil:** Cine aprobă? Un singur user sau mai mulți?
|
||||
4. **Notificări:** Contabilul vrea notificare când vine ceva nou? (email/Telegram?)
|
||||
5. **roa2web deploy:** Unde rulează? Are acces la Oracle-ul de producție?
|
||||
|
||||
---
|
||||
|
||||
## 10. Următorul Pas
|
||||
|
||||
Când ai 30 min, hai să:
|
||||
1. Clarificăm schema Oracle pentru bonuri
|
||||
2. Verificăm dacă roa2web poate conecta la Oracle
|
||||
3. Facem un test: Telegram → Clawdbot → roa2web → JSON response
|
||||
|
||||
---
|
||||
|
||||
*Analiză generată de Echo • 2026-02-03*
|
||||
@@ -0,0 +1,121 @@
|
||||
# Meditație: Vizualizare pentru Motivație
|
||||
|
||||
**Sursă:** MP3 de la Marius (Google Drive)
|
||||
**Durată:** ~10-12 minute
|
||||
**Domenii:** @sprijin @growth
|
||||
**Tip:** meditație ghidată NLP
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Exercițiu de vizualizare care leagă o acțiune pentru care vrei motivație de o stare de plăcere intensă din trecut. Folosește tehnica "fissurii în ecran" pentru a transfera emoțional motivația.
|
||||
|
||||
---
|
||||
|
||||
## Pași
|
||||
|
||||
1. **Relaxare** - Găsește o poziție confortabilă, închide ochii
|
||||
|
||||
2. **Identifică imaginea de plăcere**
|
||||
- Caută în memorie o imagine din trecut care îți produce plăcere extremă
|
||||
- Poate fi un moment, o acțiune, un loc de relaxare
|
||||
- Orice simți că îți produce plăcere intensă
|
||||
|
||||
3. **Vizualizează pe ecranul mental**
|
||||
- Proiectează imaginea pe un ecran uriaș (ca la cinematograf)
|
||||
- Vezi-te pe tine în scenă, filmat din lateral
|
||||
- Fii atent la ce vezi, ce auzi, ce simți
|
||||
|
||||
4. **Amplifică starea**
|
||||
- Imaginează-ți o telecomandă în mână
|
||||
- Apasă butonul și crește luminozitatea
|
||||
- Fă scena mai caldă, mai luminoasă
|
||||
- Simte cum se amplică starea de plăcere
|
||||
|
||||
5. **Suprapune ecranul cu acțiunea**
|
||||
- Între tine și scena cu plăcere, apare un nou ecran
|
||||
- Pe noul ecran: tu făcând acțiunea pentru care vrei motivație
|
||||
- Poate fi: să înveți ceva, să faci o acțiune, să lucrezi la dezvoltare personală
|
||||
|
||||
6. **Tehnica fissurii** (repetă de 3 ori)
|
||||
- Creează o fissură în centrul imaginii cu acțiunea
|
||||
- Lărgește fissura până vezi complet scena de plăcere din spate
|
||||
- Închide rapid fissura
|
||||
- Observă cum se schimbă emoția față de acțiune
|
||||
|
||||
7. **Proiectează în viitor**
|
||||
- Lasă să curgă emoția spre viitorul tău
|
||||
- De-a lungul secundelor, minutelor, orelor, zilelor
|
||||
- Acțiunea rămâne definitiv legată de starea de plăcere
|
||||
|
||||
8. **Revenire** - Deschide ochii când ești gata
|
||||
|
||||
---
|
||||
|
||||
## Transcriere completă
|
||||
|
||||
> O să te rog să te relaxezi și să închizi ochii, să îți găsești o poziție cât mai confortabilă și să identifici în memoria ta, o imagine de undeva din trecut, îndepărtată sau mai apropiată, o imagine care îți place extrem de mult, ceva care te motivează foarte, foarte tare.
|
||||
>
|
||||
> Poate să fie absolut orice, poate să fie un anumit element, poate să fie o acțiune, poate să fie un moment în care te relaxezi, orice simți tu că îți produce o plăcere extremă.
|
||||
>
|
||||
> Și când ai găsit această imagine, o să te rog să o vizualizezi, să ți-o imaginezi pe ecranul minții tale, cât mai clar, și doar să o privești, și să te vezi și pe tine în acea imagine ca și cum cineva cu un aparat de filmat ar fi filmat din lateral acea scenă.
|
||||
>
|
||||
> Și acum ai proiectat-o pe un ecran uriaș, ca al unui cinematograf chiar în mintea ta. Fii acum atent la tot ce vezi în această scenă. Fii acum atent la tot ce auzi, fii atent la tot ce simți.
|
||||
>
|
||||
> Și imaginează-ți acum că ții în mână o telecomandă și că apăși pe un buton și intensifici, crești luminozitatea, și scena pe care o vezi în minte, fă-o mai luminoasă, mai caldă, și o să simți acum cum se amplifică chiar și mai mult, starea de plăcere pe care o ai privind acea imagine.
|
||||
>
|
||||
> O să te las pentru câteva momente să savurezi această stare de plăcere pe care o ai în timp ce privești această scenă.
|
||||
>
|
||||
> Foarte bine. Păstrează acum în minte această scenă și imaginează-ți că între această scenă și tine apare un alt ecran care acoperă complet scena cu starea de plăcere.
|
||||
>
|
||||
> Și pe acest ecran care a apărut acum între tine și această scenă inițială, așază o imagine cu tine, făcând acțiunea pentru care ai zis că să te simți mai motivat, să ai mai mult entuziasm, mai multă dorință de a o face.
|
||||
>
|
||||
> Poate vrei să înveți ceva, sau poate vrei să faci o anumită acțiune, sau poate chiar vrei să lucrezi pentru dezvoltarea ta personală.
|
||||
>
|
||||
> Orice ai dori, alege o imagine care să fie caracteristică pentru acea acțiune și proiecteaz-o pe acest nou ecran.
|
||||
>
|
||||
> Când o privești acum în minte această nouă scenă, îți creează poate emoții contrare, pe de o parte te atrage, ai vrea să mergi spre ea și să faci acțiunea, de altă parte ceva nu te atrage suficient de mult, nu te motivează.
|
||||
>
|
||||
> Ce o să facem în continuare, este să încărcăm cu motivație chiar și această imagine pe care creierul tău o percepe lipsită de motivație.
|
||||
>
|
||||
> Vreau acum să te relaxezi, chiar și mai mult, și să fii atent la cele două ecrane suprapuse din interiorul minții tale, și să îți folosești imaginația și creativitatea, privind aceste ecrane, privind pe ecranul de deasupra.
|
||||
>
|
||||
> Și o să te rog acum să creezi cu puterea minții și a imaginației tale o fissură chiar în centrul acestei imagini, chiar în centrul ecranului, fissură pe care să o lărgești, suficient de mult, încât prin ea să se vadă clar și complet, scena din spate, scena cu plăcerea imensă pe care ai descris-o inițial.
|
||||
>
|
||||
> Foarte bine, acum închide rapid acea fissură și recreează imaginea inițială, privește acum iarăși scena pentru care vrei să creezi motivație, și observă cum s-a schimbat, ușor, starea de plăcere, pe care o ai în timp ce privești această scenă.
|
||||
>
|
||||
> Folosește-ți iarăși imaginația și creează o fissură în centrul ei, în centrul imaginii, suficient de mare încât prin ea să se vadă complet și clar, scena care îți provoca plăcerea și motivația.
|
||||
>
|
||||
> Foarte bine, închide iarăși, imaginează-ți fissura și privește iarăși acea scenă, acțiunea pentru care vrei să îți crești motivația și observă cum s-a schimbat emoția.
|
||||
>
|
||||
> Folosește-ți încă o dată pentru a treia oară imaginația și creează iarăși o fissură în mijlocul ecranului mental, suficient de mare încât să vezi prin ea, scena care pentru tine este plină de plăcere și motivație.
|
||||
>
|
||||
> Foarte bine, închide acum rapid fissura și privește cum această... doua scenă care în acest moment o simți foarte plăcută și motivată.
|
||||
>
|
||||
> Creierul tău o percepe ca fiind plină de motivație, pentru mintea ta, pentru creierul tău această imagine, conține, foarte multă plăcere și motivație.
|
||||
>
|
||||
> E posibil chiar din acest moment, după ce vei deschide ochii să simți nevoia să faci acea acțiune.
|
||||
>
|
||||
> Păstrează pentru câteva momente o stare de relaxare și o să te rog acum să lași să curgă, spre viitorul tău, toată această emoție pe care ai legat-o de această acțiune.
|
||||
>
|
||||
> Lasă să curgă această emoție, acest entuziasm, motivația, de-a lungul secundelor tale viitoare, de-a lungul minutelor, de-a lungul orelor, de-a lungul zilelor, de oricât de mult ai nevoie.
|
||||
>
|
||||
> Și simte cum această acțiune rămâne acum definitiv legată de această stare de plăcere, de-a lungul întregii tale vieți.
|
||||
>
|
||||
> Să fii cine poți deschide ochii.
|
||||
|
||||
---
|
||||
|
||||
## Când să folosești
|
||||
|
||||
- Când ai o acțiune importantă dar nu găsești motivația
|
||||
- La începutul zilei, pentru a te pregăti mental
|
||||
- Înainte de task-uri pe care le tot amâni
|
||||
- În grup sprijin, ca exercițiu de auto-motivare
|
||||
|
||||
## Note
|
||||
|
||||
- Tehnica e din NLP (Neuro-Linguistic Programming)
|
||||
- Similar cu "ancorarea" - leagă o stare emoțională de un trigger
|
||||
- Funcționează mai bine cu practică repetată
|
||||
386
memory/kb/projects/roa2web-telegram-import/README.md
Normal file
386
memory/kb/projects/roa2web-telegram-import/README.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# Proiect: Import Bonuri Fiscale via Telegram/WhatsApp → ROA
|
||||
|
||||
**Data:** 2026-02-03
|
||||
**Status:** Analiză completă
|
||||
**Tags:** @work @project
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Sistem pentru importul bonurilor fiscale de achiziție din Telegram/WhatsApp în contabilitatea ROA. OCR prin Doctr (cost zero, local). Integrare cu Oracle prin proceduri existente (PACK_CONTAFIN).
|
||||
|
||||
---
|
||||
|
||||
## 1. Obiective
|
||||
|
||||
- **Input:** Bonuri fiscale trimise pe Telegram/WhatsApp (PDF/imagine)
|
||||
- **Procesare:** OCR local (Doctr) - cost zero
|
||||
- **Output:** Note contabile în Oracle (ACT, BAL, etc.)
|
||||
- **Aprobare:** Opțional - contabil verifică înainte de salvare finală
|
||||
|
||||
---
|
||||
|
||||
## 2. Arhitectură
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Telegram │ │ │ │ │ │ │
|
||||
│ WhatsApp │────▶│ Clawdbot │────▶│ roa2web │────▶│ ROA Oracle │
|
||||
└─────────────┘ │ (Bridge) │ │ (OCR+API) │ │ (PACK_ │
|
||||
└─────────────┘ └─────────────┘ │ CONTAFIN) │
|
||||
│ │ └─────────────┘
|
||||
▼ ▼ │
|
||||
• Primește fișier • Doctr OCR • ACT_TEMP
|
||||
• Forward la API • PDF text layer • ACT, BAL
|
||||
• Răspuns user • JSON extrase • IREG_PART
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Componente Existente
|
||||
|
||||
### 3.1 roa2web (LXC 171 - claude-agent)
|
||||
|
||||
| Component | Status | Locație |
|
||||
|-----------|--------|---------|
|
||||
| **OCR Engine** | ✅ Complet | `/workspace/roa2web/backend/modules/data_entry/services/ocr_engine.py` |
|
||||
| **Doctr** | ✅ Instalat | PyTorch backend, db_resnet50 + crnn_vgg16_bn |
|
||||
| **PaddleOCR** | ✅ Instalat | Backup engine |
|
||||
| **API OCR** | ✅ Funcțional | `POST /api/data-entry/ocr/extract` |
|
||||
| **Job Queue** | ✅ Complet | Async processing cu worker pool |
|
||||
| **Bot Telegram** | ⚠️ Parțial | Dashboard/sold, NU handler fișiere |
|
||||
|
||||
### 3.2 Schema Date OCR (ExtractionData)
|
||||
|
||||
```python
|
||||
ExtractionData:
|
||||
partner_name: str # nume furnizor
|
||||
cui: str # CUI furnizor
|
||||
receipt_date: date # data bon
|
||||
receipt_number: str # număr bon
|
||||
receipt_series: str # serie bon
|
||||
amount: Decimal # total
|
||||
tva_entries: List[TvaEntry] # TVA pe cote (A=19%, B=9%, etc.)
|
||||
tva_total: Decimal # total TVA
|
||||
payment_methods: List # CARD/NUMERAR
|
||||
address: str # adresă furnizor
|
||||
confidence_*: float # scoruri încredere
|
||||
```
|
||||
|
||||
### 3.3 Oracle (MARIUSM_AUTO)
|
||||
|
||||
**Tabele principale:**
|
||||
|
||||
| Tabel | Scop |
|
||||
|-------|------|
|
||||
| **ACT** | Note contabile |
|
||||
| **ACT_TEMP** | Staging pentru note |
|
||||
| **RUL** | Rulaje gestiuni |
|
||||
| **STOC** | Solduri stoc |
|
||||
| **BAL** | Balanță verificare |
|
||||
| **IREG_PARTENERI** | Evidență parteneri |
|
||||
| **BALANTA_PARTENERI** | Balanță parteneri |
|
||||
| **ATAS_ATASAMENTE** | Fișiere atașate (BLOB) |
|
||||
| **ATAS_REFERINTE** | Legături atașamente |
|
||||
| **NOM_FDOC** | Nomenclator tipuri documente |
|
||||
|
||||
**Package-uri relevante:**
|
||||
|
||||
| Package | Scop |
|
||||
|---------|------|
|
||||
| **PACK_CONTAFIN** | Salvare note contabile (principal) |
|
||||
| **PACK_FACTURARE** | Exemple de salvare (pentru vânzări) |
|
||||
| **PACK_PARTENERI** | Gestiune parteneri |
|
||||
|
||||
---
|
||||
|
||||
## 4. Formula Contabilă - Bon Fiscal Achiziție
|
||||
|
||||
### 4.1 Bon simplu (plătit cash)
|
||||
|
||||
```
|
||||
Cheltuială = Furnizor: 6xx = 401 (valoare fără TVA)
|
||||
TVA deductibil = Furn: 4426 = 401 (TVA)
|
||||
Plată cash: 401 = 5311 (total cu TVA)
|
||||
```
|
||||
|
||||
**Exemplu bon benzină 119 RON (100 + 19 TVA):**
|
||||
```sql
|
||||
-- Linia 1: Cheltuială combustibil
|
||||
SCD='6022', SCC='401', SUMA=100.00
|
||||
|
||||
-- Linia 2: TVA deductibil
|
||||
SCD='4426', SCC='401', SUMA=19.00, PROC_TVA=1.19
|
||||
|
||||
-- Linia 3: Plată din casă
|
||||
SCD='401', SCC='5311', SUMA=119.00
|
||||
```
|
||||
|
||||
### 4.2 Bon cu TVA la încasare
|
||||
|
||||
```
|
||||
Cheltuială = Furnizor: 6xx = 401
|
||||
TVA neexigibil = Furn: 4428 = 401
|
||||
Plată cash: 401 = 5311
|
||||
Exigibilizare TVA: 4426 = 4428
|
||||
```
|
||||
|
||||
### 4.3 Conturi cheltuieli uzuale
|
||||
|
||||
| Tip | Cont | Descriere |
|
||||
|-----|------|-----------|
|
||||
| Combustibil | 6022 | Combustibili |
|
||||
| Materiale | 6021 | Materiale auxiliare |
|
||||
| Rechizite | 6021 | Materiale auxiliare |
|
||||
| Piese | 6024 | Piese schimb |
|
||||
| Întreținere | 611 | Cheltuieli întreținere |
|
||||
| Transport | 624 | Cheltuieli transport |
|
||||
|
||||
---
|
||||
|
||||
## 5. Flux Oracle - Salvare Note Contabile
|
||||
|
||||
### 5.1 Proceduri PACK_CONTAFIN
|
||||
|
||||
```sql
|
||||
-- 1. INIȚIALIZARE SESIUNE
|
||||
PACK_CONTAFIN.INITIALIZEAZA_SCRIERE_ACT_RUL(
|
||||
TNIDUTIL NUMBER, -- ID utilizator
|
||||
TDDATAORA DATE, -- Data și ora
|
||||
TNAN NUMBER, -- An
|
||||
TNLUNA NUMBER, -- Luna
|
||||
TNSUPRASCRIERECOD NUMBER, -- 0/1
|
||||
TNSUPRASCRIEREANLUNA NUMBER, -- 0/1
|
||||
TNSCRIESTERGE NUMBER, -- 0=scrie, 2=șterge
|
||||
TNIDSUCURSALA NUMBER -- ID sucursală
|
||||
);
|
||||
|
||||
-- 2. INSERT ÎN ACT_TEMP (pentru fiecare linie)
|
||||
INSERT INTO ACT_TEMP (
|
||||
LUNA, AN, COD,
|
||||
DATAIREG, DATAACT, DATASCAD,
|
||||
NRACT, SERIE_ACT,
|
||||
EXPLICATIA,
|
||||
SCD, ASCD, -- cont debit, analitic
|
||||
SCC, ASCC, -- cont credit, analitic
|
||||
SUMA,
|
||||
PROC_TVA,
|
||||
ID_FDOC, -- tip document
|
||||
ID_PARTD, ID_PARTC, -- parteneri
|
||||
ID_FACT,
|
||||
ID_VALUTA,
|
||||
ID_SUCURSALA
|
||||
) VALUES (...);
|
||||
|
||||
-- 3. FINALIZARE (transferă în ACT, actualizează BAL, etc.)
|
||||
PACK_CONTAFIN.FINALIZEAZA_SCRIERE_ACT_RUL(
|
||||
TNIDUTIL NUMBER, -- ID utilizator
|
||||
TNCOD NUMBER, -- Cod document
|
||||
TNSCRIESTERGE NUMBER, -- 0=scrie
|
||||
TNMODIFICARENOTA NUMBER, -- 0/1
|
||||
TNSCRIECUMPVANZ NUMBER, -- 0/1
|
||||
TCMESAJREFACERENOTA OUT VARCHAR2 -- Mesaj rezultat
|
||||
);
|
||||
```
|
||||
|
||||
### 5.2 Ce face FINALIZEAZA intern
|
||||
|
||||
```sql
|
||||
-- La linia 8059 în PACK_CONTAFIN:
|
||||
pack_contafin.SCRIE_IN_ACT(user); -- ACT_TEMP → ACT + BAL
|
||||
pack_contafin.SCRIE_IN_RUL(user); -- RUL_TEMP → RUL (dacă există)
|
||||
pack_contafin.SCRIE_IN_RUL_OBINV(user); -- pentru obiecte inventar
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Structura ACT_TEMP
|
||||
|
||||
```sql
|
||||
ACT_TEMP (
|
||||
LUNA NUMBER,
|
||||
AN NUMBER,
|
||||
COD NUMBER,
|
||||
DATAIREG DATE,
|
||||
NRACT NUMBER,
|
||||
DATAACT DATE,
|
||||
EXPLICATIA VARCHAR2(100),
|
||||
SCD VARCHAR2(10), -- Cont DEBIT
|
||||
ASCD VARCHAR2(20), -- Analitic debit
|
||||
SCC VARCHAR2(10), -- Cont CREDIT
|
||||
ASCC VARCHAR2(20), -- Analitic credit
|
||||
SUMA NUMBER,
|
||||
PROC_TVA NUMBER, -- Procent TVA (1.19, 1.09, etc.)
|
||||
ID_FDOC NUMBER, -- Tip document (din NOM_FDOC)
|
||||
ID_PARTD NUMBER, -- Partner debit
|
||||
ID_PARTC NUMBER, -- Partner credit
|
||||
ID_FACT NUMBER, -- ID factură (opțional)
|
||||
ID_VALUTA NUMBER,
|
||||
ID_SUCURSALA NUMBER,
|
||||
SERIE_ACT VARCHAR2(10),
|
||||
TVA_INCASARE NUMBER, -- 0/1 pentru TVA la încasare
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Optimizări Propuse
|
||||
|
||||
### 7.1 PDF Text Layer Extraction
|
||||
|
||||
Adobe Scan creează PDF-uri cu text layer. Verificăm înainte de OCR:
|
||||
|
||||
```python
|
||||
import pdfplumber
|
||||
|
||||
def extract_text_or_ocr(pdf_path):
|
||||
with pdfplumber.open(pdf_path) as pdf:
|
||||
text = ""
|
||||
for page in pdf.pages:
|
||||
page_text = page.extract_text()
|
||||
if page_text:
|
||||
text += page_text
|
||||
|
||||
if text.strip():
|
||||
# PDF are text layer - folosește-l direct
|
||||
return {"source": "pdf_layer", "text": text}
|
||||
else:
|
||||
# Nu are text - fallback la Doctr OCR
|
||||
return doctr_ocr(pdf_path)
|
||||
```
|
||||
|
||||
**Beneficii:**
|
||||
- Instant vs. 2-5 sec OCR
|
||||
- 100% acuratețe vs. ~95% OCR
|
||||
- Zero procesare GPU
|
||||
|
||||
### 7.2 Mapare CUI → Cont
|
||||
|
||||
Tabel pentru auto-detectare tip cheltuială:
|
||||
|
||||
```python
|
||||
CUI_CONT_MAP = {
|
||||
# Benzinării
|
||||
"RO1234567": "6022", # OMV
|
||||
"RO2345678": "6022", # Petrom
|
||||
"RO3456789": "6022", # Mol
|
||||
|
||||
# Magazine bricolaj
|
||||
"RO10562600": "6021", # Dedeman
|
||||
|
||||
# Default
|
||||
"DEFAULT": "6028" # Alte cheltuieli
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Status Implementare (2026-02-03)
|
||||
|
||||
| Component | Status | Note |
|
||||
|-----------|--------|------|
|
||||
| OCR (Doctr/PaddleOCR) | ✅ Testat | 34 sec per PDF |
|
||||
| Script OCR standalone | ✅ Funcțional | `/workspace/roa2web-telegram-test/` |
|
||||
| Python: INSERT ACT_TEMP | ✅ Testat | 3 linii: cheltuială + TVA + plată |
|
||||
| Mapare CUI → cont | ✅ Bază | 6022=combustibil, 6021=materiale |
|
||||
| Găsire partener | ✅ Funcțional | Caută în NOM_PARTENERI |
|
||||
| Conexiune Oracle | ✅ Testat | Server 10.0.20.121 |
|
||||
| Handler WhatsApp | 🔄 În pregătire | Clawdbot poate primi fișiere |
|
||||
| CALL PACK_CONTAFIN | ⏳ TODO | Finalizare cu procedurile Oracle |
|
||||
| UI aprobare | ⏳ TODO | Opțional |
|
||||
|
||||
### Scripturi create:
|
||||
- `/workspace/roa2web-telegram-test/process_and_save.py` - OCR → Oracle
|
||||
- `/workspace/roa2web-telegram-test/save_to_oracle.py` - test salvare Oracle
|
||||
|
||||
### Test efectuat:
|
||||
```
|
||||
PDF "benzina 07 aug. 2024.pdf" → OCR → Oracle ACT_TEMP
|
||||
CUI: RO11201891
|
||||
Data: 2024-08-01
|
||||
Total: 263.28 RON
|
||||
TVA: 42.04 (19%)
|
||||
Note: 6022=401, 4426=401, 401=5311
|
||||
Status: DRY RUN OK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Plan Implementare
|
||||
|
||||
### Faza 1: Handler Telegram (3-4h)
|
||||
- [ ] MessageHandler pentru imagini/PDF în bot
|
||||
- [ ] Forward la `/api/data-entry/ocr/extract`
|
||||
- [ ] Răspuns cu datele extrase (preview)
|
||||
|
||||
### Faza 2: PDF Optimization (1-2h)
|
||||
- [ ] Verificare text layer în PDF
|
||||
- [ ] Extracție directă dacă există
|
||||
- [ ] Fallback la Doctr
|
||||
|
||||
### Faza 3: Integrare Oracle (5-7h)
|
||||
- [ ] Conexiune Oracle din roa2web
|
||||
- [ ] Găsire/creare partener după CUI
|
||||
- [ ] INSERT în ACT_TEMP
|
||||
- [ ] Apel PACK_CONTAFIN proceduri
|
||||
- [ ] Salvare atașament (ATAS_ATASAMENTE)
|
||||
|
||||
### Faza 4: WhatsApp Bridge (4-6h)
|
||||
- [ ] Clawdbot handler pentru fișiere
|
||||
- [ ] Forward la roa2web API
|
||||
- [ ] Răspuns pe canal
|
||||
|
||||
### Faza 5: Aprobare & Polish (3-5h)
|
||||
- [ ] Workflow aprobare (opțional)
|
||||
- [ ] Mapare automată CUI → cont
|
||||
- [ ] Logging și error handling
|
||||
|
||||
---
|
||||
|
||||
## 10. Credențiale Test
|
||||
|
||||
**Oracle Test Server:**
|
||||
```
|
||||
Host: 10.0.20.121
|
||||
Port: 1521
|
||||
SID: ROA
|
||||
User: CONTAFIN_ORACLE
|
||||
Pass: (în secrets/test.oracle_pass)
|
||||
Schema: MARIUSM_AUTO
|
||||
```
|
||||
|
||||
**roa2web:**
|
||||
```
|
||||
LXC: 171 (claude-agent)
|
||||
Path: /workspace/roa2web
|
||||
Start: ./start.sh test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Fișiere Proiect
|
||||
|
||||
```
|
||||
roa2web-telegram-import/
|
||||
├── README.md # Acest fișier
|
||||
├── schema-oracle.md # Detalii schema Oracle
|
||||
├── flux-contabil.md # Formule contabile detaliate
|
||||
├── api-spec.md # Specificații API (de creat)
|
||||
└── implementation-notes.md # Note implementare (de creat)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Întrebări Deschise
|
||||
|
||||
1. **Workflow aprobare:** E necesar ca un contabil să aprobe înainte de salvare?
|
||||
2. **Tip document (ID_FDOC):** Ce valoare pentru bonuri fiscale achiziție?
|
||||
3. **Analitice:** Sunt necesare analitice pe conturi (ASCD, ASCC)?
|
||||
4. **Sucursală:** Valoare default pentru ID_SUCURSALA?
|
||||
5. **Atașamente:** Unde se face legătura ATAS_REFERINTE (ID_ENTITATE = ID_ACT)?
|
||||
|
||||
---
|
||||
|
||||
*Analiză generată de Echo • 2026-02-03*
|
||||
229
memory/kb/projects/roa2web-telegram-import/flux-contabil.md
Normal file
229
memory/kb/projects/roa2web-telegram-import/flux-contabil.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# Flux Contabil - Import Bonuri Fiscale Achiziție
|
||||
|
||||
**Actualizat:** 2026-02-03
|
||||
|
||||
---
|
||||
|
||||
## 1. Formula Contabilă Generală
|
||||
|
||||
### Bon fiscal achiziție (plătit cash)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DEBIT │ CREDIT │ SUMA │ DESCRIERE │
|
||||
├──────────────────┼─────────────────┼──────────┼─────────────┤
|
||||
│ 6xx (cheltuială)│ 401 (furnizor) │ fără TVA│ Cheltuială │
|
||||
│ 4426 (TVA ded.) │ 401 (furnizor) │ TVA │ TVA deduct.│
|
||||
│ 401 (furnizor) │ 5311 (casa) │ cu TVA │ Plată cash │
|
||||
└──────────────────┴─────────────────┴──────────┴─────────────┘
|
||||
```
|
||||
|
||||
### Bon fiscal cu TVA la încasare
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DEBIT │ CREDIT │ SUMA │ DESCRIERE │
|
||||
├──────────────────┼─────────────────┼──────────┼─────────────┤
|
||||
│ 6xx (cheltuială)│ 401 (furnizor) │ fără TVA│ Cheltuială │
|
||||
│ 4428 (TVA neex.)│ 401 (furnizor) │ TVA │ TVA neexig.│
|
||||
│ 401 (furnizor) │ 5311 (casa) │ cu TVA │ Plată cash │
|
||||
│ 4426 (TVA ded.) │ 4428 (TVA neex)│ TVA │ Exigibiliz.│
|
||||
└──────────────────┴─────────────────┴──────────┴─────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Conturi Cheltuieli (6xx)
|
||||
|
||||
| Cont | Denumire | Utilizare |
|
||||
|------|----------|-----------|
|
||||
| 6021 | Cheltuieli cu materialele auxiliare | Rechizite, materiale consumabile |
|
||||
| 6022 | Cheltuieli privind combustibilii | Benzină, motorină, GPL |
|
||||
| 6024 | Cheltuieli privind piesele de schimb | Piese auto, componente |
|
||||
| 6028 | Cheltuieli privind alte materiale consumabile | Diverse materiale |
|
||||
| 604 | Cheltuieli privind materialele nestocate | Materiale directe în consum |
|
||||
| 611 | Cheltuieli cu întreținerea și reparațiile | Service, reparații |
|
||||
| 612 | Cheltuieli cu redevențele | Licențe, abonamente |
|
||||
| 613 | Cheltuieli cu primele de asigurare | Asigurări |
|
||||
| 614 | Cheltuieli cu studiile și cercetările | Consultanță |
|
||||
| 622 | Cheltuieli privind comisioanele | Comisioane bancare |
|
||||
| 623 | Cheltuieli de protocol, reclamă | Protocol, publicitate |
|
||||
| 624 | Cheltuieli cu transportul | Transport bunuri/persoane |
|
||||
| 625 | Cheltuieli cu deplasările | Diurnă, cazare, transport |
|
||||
| 626 | Cheltuieli poștale și telecomunicații | Telefon, internet |
|
||||
| 627 | Cheltuieli cu serviciile bancare | Comisioane bancare |
|
||||
| 628 | Alte cheltuieli cu serviciile | Diverse servicii |
|
||||
|
||||
---
|
||||
|
||||
## 3. Mapare Automată CUI → Cont
|
||||
|
||||
### Benzinării
|
||||
|
||||
| CUI | Denumire | Cont |
|
||||
|-----|----------|------|
|
||||
| RO1590082 | OMV PETROM | 6022 |
|
||||
| RO1025tried | ROMPETROL | 6022 |
|
||||
| RO14991381 | MOL ROMANIA | 6022 |
|
||||
| RO524186 | LUKOIL | 6022 |
|
||||
|
||||
### Magazine Bricolaj
|
||||
|
||||
| CUI | Denumire | Cont |
|
||||
|-----|----------|------|
|
||||
| RO10562600 | DEDEMAN | 6021/6028 |
|
||||
| RO6323780 | HORNBACH | 6021/6028 |
|
||||
| RO14688790 | LEROY MERLIN | 6021/6028 |
|
||||
|
||||
### Supermarket-uri
|
||||
|
||||
| CUI | Denumire | Cont |
|
||||
|-----|----------|------|
|
||||
| RO15tried | MEGA IMAGE | 6028 |
|
||||
| RO5765323 | KAUFLAND | 6028 |
|
||||
| RO3891449 | CARREFOUR | 6028 |
|
||||
| RO6334171 | LIDL | 6028 |
|
||||
|
||||
---
|
||||
|
||||
## 4. Exemplu Complet - Bon Benzină
|
||||
|
||||
**Bon:**
|
||||
- Furnizor: OMV PETROM (CUI: RO1590082)
|
||||
- Data: 2026-02-03
|
||||
- Număr bon: 12345
|
||||
- Total: 250.00 RON (210.08 + 39.92 TVA 19%)
|
||||
|
||||
### 4.1 Date extrase OCR
|
||||
|
||||
```json
|
||||
{
|
||||
"partner_name": "OMV PETROM MARKETING SRL",
|
||||
"cui": "RO1590082",
|
||||
"receipt_date": "2026-02-03",
|
||||
"receipt_number": "12345",
|
||||
"amount": 250.00,
|
||||
"tva_entries": [
|
||||
{"code": "A", "percent": 19, "amount": 39.92}
|
||||
],
|
||||
"tva_total": 39.92,
|
||||
"payment_methods": [{"method": "NUMERAR", "amount": 250.00}]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Note Contabile Generate
|
||||
|
||||
```sql
|
||||
-- LINIA 1: Cheltuială combustibil
|
||||
INSERT INTO ACT_TEMP (
|
||||
LUNA, AN, COD, DATAIREG, DATAACT, NRACT,
|
||||
EXPLICATIA,
|
||||
SCD, SCC, SUMA,
|
||||
ID_PARTC, ID_FDOC
|
||||
) VALUES (
|
||||
2, 2026, :cod, SYSDATE, TO_DATE('2026-02-03', 'YYYY-MM-DD'), 12345,
|
||||
'Combustibil OMV bon 12345',
|
||||
'6022', '401', 210.08,
|
||||
:id_part_omv, :id_fdoc_bon
|
||||
);
|
||||
|
||||
-- LINIA 2: TVA deductibil
|
||||
INSERT INTO ACT_TEMP (
|
||||
LUNA, AN, COD, DATAIREG, DATAACT, NRACT,
|
||||
EXPLICATIA,
|
||||
SCD, SCC, SUMA, PROC_TVA,
|
||||
ID_PARTC, ID_FDOC
|
||||
) VALUES (
|
||||
2, 2026, :cod, SYSDATE, TO_DATE('2026-02-03', 'YYYY-MM-DD'), 12345,
|
||||
'TVA combustibil OMV bon 12345',
|
||||
'4426', '401', 39.92, 1.19,
|
||||
:id_part_omv, :id_fdoc_bon
|
||||
);
|
||||
|
||||
-- LINIA 3: Plată din casă
|
||||
INSERT INTO ACT_TEMP (
|
||||
LUNA, AN, COD, DATAIREG, DATAACT, NRACT,
|
||||
EXPLICATIA,
|
||||
SCD, SCC, SUMA,
|
||||
ID_PARTD, ID_FDOC
|
||||
) VALUES (
|
||||
2, 2026, :cod, SYSDATE, TO_DATE('2026-02-03', 'YYYY-MM-DD'), 12345,
|
||||
'Plata bon OMV 12345',
|
||||
'401', '5311', 250.00,
|
||||
:id_part_omv, :id_fdoc_bon
|
||||
);
|
||||
```
|
||||
|
||||
### 4.3 Flux Complet Python
|
||||
|
||||
```python
|
||||
import oracledb
|
||||
|
||||
def import_bon_achizitie(extraction_data, conn):
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 1. Găsește sau creează partenerul
|
||||
id_part = find_or_create_partner(cursor, extraction_data['cui'], extraction_data['partner_name'])
|
||||
|
||||
# 2. Determină contul de cheltuială
|
||||
cont_cheltuiala = get_cont_by_cui(extraction_data['cui']) # ex: '6022'
|
||||
|
||||
# 3. Calculează sumele
|
||||
total_cu_tva = extraction_data['amount']
|
||||
tva = extraction_data['tva_total']
|
||||
total_fara_tva = total_cu_tva - tva
|
||||
|
||||
# 4. Inițializare
|
||||
cursor.callproc('MARIUSM_AUTO.PACK_CONTAFIN.INITIALIZEAZA_SCRIERE_ACT_RUL', [
|
||||
id_util, # ID utilizator
|
||||
datetime.now(),
|
||||
an,
|
||||
luna,
|
||||
0, # suprascriere_cod
|
||||
0, # suprascriere_anluna
|
||||
0, # scrie_sterge (0=scrie)
|
||||
id_sucursala
|
||||
])
|
||||
|
||||
# 5. INSERT în ACT_TEMP (cele 3 linii)
|
||||
# ... INSERT-uri ca mai sus ...
|
||||
|
||||
# 6. Finalizare
|
||||
mesaj = cursor.var(oracledb.STRING)
|
||||
cursor.callproc('MARIUSM_AUTO.PACK_CONTAFIN.FINALIZEAZA_SCRIERE_ACT_RUL', [
|
||||
id_util,
|
||||
cod,
|
||||
0, # scrie_sterge
|
||||
0, # modificare_nota
|
||||
0, # scrie_cump_vanz
|
||||
mesaj
|
||||
])
|
||||
|
||||
conn.commit()
|
||||
return mesaj.getvalue()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Cote TVA România
|
||||
|
||||
| Cotă | Procent | PROC_TVA | Aplicare |
|
||||
|------|---------|----------|----------|
|
||||
| Standard | 19% | 1.19 | Majoritatea bunurilor/serviciilor |
|
||||
| Redus 1 | 9% | 1.09 | Alimente, medicamente, cărți |
|
||||
| Redus 2 | 5% | 1.05 | Locuințe sociale |
|
||||
| Zero | 0% | 1.00 | Export, anumite servicii |
|
||||
|
||||
---
|
||||
|
||||
## 6. Validări Necesare
|
||||
|
||||
1. **CUI valid** - verificare checksum
|
||||
2. **Data bon** - nu în viitor, nu mai veche de 1 an
|
||||
3. **Sumă** - pozitivă, format corect
|
||||
4. **TVA** - să corespundă cu cotele legale
|
||||
5. **Balanță** - SUMA(debit) = SUMA(credit)
|
||||
|
||||
---
|
||||
|
||||
*Flux documentat de Echo • 2026-02-03*
|
||||
275
memory/kb/projects/roa2web-telegram-import/schema-oracle.md
Normal file
275
memory/kb/projects/roa2web-telegram-import/schema-oracle.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Schema Oracle - ROA (MARIUSM_AUTO)
|
||||
|
||||
**Actualizat:** 2026-02-03
|
||||
|
||||
---
|
||||
|
||||
## Tabele Principale
|
||||
|
||||
### ACT - Note Contabile
|
||||
|
||||
```sql
|
||||
ACT (
|
||||
ID_ACT NUMBER PRIMARY KEY,
|
||||
LUNA NUMBER,
|
||||
AN NUMBER,
|
||||
COD NUMBER, -- Cod document unic
|
||||
DATAIREG DATE, -- Data înregistrare
|
||||
NRACT NUMBER, -- Număr act
|
||||
DATAACT DATE, -- Data act
|
||||
EXPLICATIA VARCHAR2(100), -- Descriere
|
||||
SCD VARCHAR2(10), -- Cont DEBIT
|
||||
ASCD VARCHAR2(20), -- Analitic debit
|
||||
SCC VARCHAR2(10), -- Cont CREDIT
|
||||
ASCC VARCHAR2(20), -- Analitic credit
|
||||
SUMA NUMBER, -- Sumă
|
||||
ID_FACTD NUMBER, -- Factură debit
|
||||
ID_FACTC NUMBER, -- Factură credit
|
||||
PERECHED NUMBER,
|
||||
PERECHEC NUMBER,
|
||||
SUMA_VAL NUMBER, -- Sumă valută
|
||||
CURS NUMBER, -- Curs valutar
|
||||
DATASCAD DATE, -- Data scadență
|
||||
ID_UTIL NUMBER, -- Utilizator creare
|
||||
DATAORA DATE, -- Data/ora creare
|
||||
ID_UTILS NUMBER, -- Utilizator modificare
|
||||
DATAORAS DATE, -- Data/ora modificare
|
||||
TVA_INCASARE NUMBER, -- Flag TVA la încasare
|
||||
SERIE_ACT VARCHAR2(10), -- Serie act
|
||||
ID_PART NUMBER, -- ID partener
|
||||
ID_CTR NUMBER, -- ID contract
|
||||
CONT VARCHAR2(10),
|
||||
ACONT VARCHAR2(20),
|
||||
ID_VALUTA NUMBER,
|
||||
ID_SUCURSALA NUMBER,
|
||||
ID_SET NUMBER,
|
||||
TIP_SAFT NUMBER
|
||||
)
|
||||
```
|
||||
|
||||
### ACT_TEMP - Staging Note Contabile
|
||||
|
||||
Aceeași structură ca ACT, folosită pentru inserare temporară înainte de transfer.
|
||||
|
||||
### RUL - Rulaje Gestiuni
|
||||
|
||||
```sql
|
||||
RUL (
|
||||
ID_RUL NUMBER PRIMARY KEY,
|
||||
AN NUMBER,
|
||||
LUNA NUMBER,
|
||||
COD NUMBER,
|
||||
NNIR NUMBER, -- Număr NIR
|
||||
ID_ARTICOL NUMBER,
|
||||
ID_GESTIUNE NUMBER,
|
||||
PRET NUMBER,
|
||||
PRETV NUMBER, -- Preț vânzare
|
||||
TVA NUMBER,
|
||||
TVAV NUMBER,
|
||||
CANT NUMBER, -- Cantitate
|
||||
CANTE NUMBER,
|
||||
CONT VARCHAR2(10),
|
||||
ACONT VARCHAR2(20),
|
||||
ADAOS NUMBER,
|
||||
ID_LUCRARE NUMBER,
|
||||
ID_RESPONSABIL NUMBER,
|
||||
DATAACT DATE,
|
||||
PROCENT NUMBER,
|
||||
CURS NUMBER,
|
||||
PRETD NUMBER,
|
||||
ID_UTIL NUMBER,
|
||||
DATAORA DATE,
|
||||
ID_SECTIE NUMBER,
|
||||
PROC_TVA NUMBER,
|
||||
ID_FACT NUMBER,
|
||||
STERS NUMBER,
|
||||
ID_TIP_RULAJ NUMBER, -- 0=intrare/ieșire reală
|
||||
ID_SET NUMBER,
|
||||
ID_SUCURSALA NUMBER,
|
||||
NRACT NUMBER,
|
||||
SERIE_ACT VARCHAR2(10),
|
||||
ID_VALUTA NUMBER,
|
||||
LOT VARCHAR2(50),
|
||||
ADATA_EXPIRARE DATE,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### NOM_TIP_RULAJ - Tipuri Rulaj
|
||||
|
||||
```sql
|
||||
(0, 'INTRARE/IESIRE REALA')
|
||||
(1, 'TRANSFER')
|
||||
(2, 'RULAJ CMP')
|
||||
(6, 'INVENTARIERE')
|
||||
```
|
||||
|
||||
### STOC - Stocuri
|
||||
|
||||
```sql
|
||||
STOC (
|
||||
ID_STOC NUMBER PRIMARY KEY,
|
||||
AN NUMBER,
|
||||
LUNA NUMBER,
|
||||
ID_ARTICOL NUMBER,
|
||||
PRET NUMBER,
|
||||
PRETV NUMBER,
|
||||
TVA NUMBER,
|
||||
TVAV NUMBER,
|
||||
CANTS NUMBER, -- Cantitate sold
|
||||
CANT NUMBER,
|
||||
CANTE NUMBER,
|
||||
CONT VARCHAR2(10),
|
||||
ID_GESTIUNE NUMBER,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### BAL - Balanță Verificare
|
||||
|
||||
```sql
|
||||
BAL (
|
||||
ID_BAL NUMBER PRIMARY KEY,
|
||||
CONT VARCHAR2(10),
|
||||
PRECDEB1 NUMBER, -- Precedent debit (an)
|
||||
PRECCRED1 NUMBER,
|
||||
PRECDEB NUMBER, -- Precedent debit (lună)
|
||||
PRECCRED NUMBER,
|
||||
RULDEB NUMBER, -- Rulaj debit
|
||||
RULCRED NUMBER, -- Rulaj credit
|
||||
AN NUMBER,
|
||||
LUNA NUMBER,
|
||||
ID_SUCURSALA NUMBER
|
||||
)
|
||||
```
|
||||
|
||||
### IREG_PARTENERI - Evidență Parteneri
|
||||
|
||||
```sql
|
||||
IREG_PARTENERI (
|
||||
ID_IREG_PART NUMBER PRIMARY KEY,
|
||||
AN NUMBER,
|
||||
LUNA NUMBER,
|
||||
ID_PART NUMBER,
|
||||
CONT VARCHAR2(10),
|
||||
ACONT VARCHAR2(20),
|
||||
DEBIT NUMBER,
|
||||
CREDIT NUMBER,
|
||||
VALDEBIT NUMBER,
|
||||
VALCREDIT NUMBER,
|
||||
CURS NUMBER,
|
||||
ID_FDOC NUMBER, -- Tip document
|
||||
DATAACT DATE,
|
||||
DATAIREG DATE,
|
||||
DATASCAD DATE,
|
||||
NRACT NUMBER,
|
||||
ID_RESPONSABIL NUMBER,
|
||||
PRECDEB NUMBER,
|
||||
PRECCRED NUMBER,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### ATAS_ATASAMENTE - Fișiere Atașate
|
||||
|
||||
```sql
|
||||
ATAS_ATASAMENTE (
|
||||
ID_ATAS NUMBER PRIMARY KEY,
|
||||
NUME_FISIER VARCHAR2(200),
|
||||
FISIER BLOB, -- Conținut fișier
|
||||
ID_UTIL NUMBER,
|
||||
DATAORA DATE,
|
||||
STERS NUMBER,
|
||||
ID_UTILS NUMBER,
|
||||
DATAORAS DATE,
|
||||
DESCRIERE VARCHAR2(500),
|
||||
ID_LINK NUMBER,
|
||||
ID_TIP_ENT_PREL NUMBER
|
||||
)
|
||||
```
|
||||
|
||||
### ATAS_REFERINTE - Legături Atașamente
|
||||
|
||||
```sql
|
||||
ATAS_REFERINTE (
|
||||
ID_REFERINTA NUMBER PRIMARY KEY,
|
||||
ID_ATAS NUMBER, -- FK la ATAS_ATASAMENTE
|
||||
ID_ENTITATE NUMBER, -- ID din tabela referită
|
||||
ID_UTIL NUMBER,
|
||||
DATAORA DATE,
|
||||
STERS NUMBER,
|
||||
ID_UTILS NUMBER,
|
||||
DATAORAS DATE,
|
||||
ID_PROGRAM NUMBER, -- Identificator tabel/modul
|
||||
ORDINE NUMBER
|
||||
)
|
||||
```
|
||||
|
||||
### NOM_FDOC - Nomenclator Tipuri Documente
|
||||
|
||||
```sql
|
||||
NOM_FDOC (
|
||||
ID_FDOC NUMBER PRIMARY KEY,
|
||||
FEL_DOCUMENT VARCHAR2(50),
|
||||
STERS NUMBER,
|
||||
ID_MOD NUMBER,
|
||||
INACTIV NUMBER,
|
||||
TIP_DOC VARCHAR2(5),
|
||||
PAYMENTCODE VARCHAR2(10)
|
||||
)
|
||||
|
||||
-- Exemple:
|
||||
(1, 'ABONAMENT')
|
||||
(3, 'AVANSURI')
|
||||
(5, 'AVIZ EXP')
|
||||
(6, 'BILET')
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Package-uri Oracle
|
||||
|
||||
### PACK_CONTAFIN (principal)
|
||||
|
||||
**Proceduri principale:**
|
||||
- `INITIALIZEAZA_SCRIERE_ACT_RUL` - Inițializare sesiune
|
||||
- `SCRIE_IN_ACT` - Transfer ACT_TEMP → ACT
|
||||
- `SCRIE_IN_BALANTA` - Actualizare balanță
|
||||
- `SCRIE_IN_RUL` - Transfer RUL_TEMP → RUL
|
||||
- `SCRIE_IN_STOC` - Actualizare stoc
|
||||
- `SCRIE_IN_IREG_PARTENERI` - Actualizare evidență parteneri
|
||||
- `FINALIZEAZA_SCRIERE_ACT_RUL` - Finalizare (apelează toate cele de mai sus)
|
||||
|
||||
### PACK_FACTURARE (referință)
|
||||
|
||||
**Exemple INSERT ACT_TEMP:**
|
||||
- Liniile 1000-1200 în package body
|
||||
- Model pentru structura datelor
|
||||
- NU pentru achiziții, dar util ca referință
|
||||
|
||||
### PACK_PARTENERI
|
||||
|
||||
- Gestiune parteneri (furnizori, clienți)
|
||||
- Căutare/creare partener după CUI
|
||||
|
||||
---
|
||||
|
||||
## Conexiune Python
|
||||
|
||||
```python
|
||||
import oracledb
|
||||
|
||||
conn = oracledb.connect(
|
||||
user="CONTAFIN_ORACLE",
|
||||
password="ROMFASTSOFT",
|
||||
dsn="10.0.20.121:1521/ROA"
|
||||
)
|
||||
|
||||
# Toate operațiile folosesc schema MARIUSM_AUTO
|
||||
cursor.execute("SELECT * FROM MARIUSM_AUTO.ACT WHERE ROWNUM <= 1")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Schema documentată de Echo • 2026-02-03*
|
||||
588
tools/process_bon.py
Normal file
588
tools/process_bon.py
Normal file
@@ -0,0 +1,588 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Procesare bon fiscal: PDF → OCR API → SQLite API → Oracle
|
||||
|
||||
Usage:
|
||||
python process_bon.py <pdf_path> [--save]
|
||||
|
||||
--save Salvează efectiv în Oracle (altfel dry run)
|
||||
|
||||
Fluxul:
|
||||
1. OCR extract via API (http://10.0.20.171:8000/api/data-entry/ocr/extract)
|
||||
2. Save receipt via API (http://10.0.20.171:8000/api/data-entry/receipts/) - TOATE datele
|
||||
3. Save to Oracle:
|
||||
- Verifică/creează partener
|
||||
- Verifică TVA la încasare (CALENDAR.TVA_INCASARE)
|
||||
- Generează note contabile corecte
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import requests
|
||||
import oracledb
|
||||
|
||||
# === CONFIG ===
|
||||
API_BASE = "http://10.0.20.171:8000"
|
||||
API_USER = "MARIUS M"
|
||||
API_PASS = "123"
|
||||
SERVER_ID = "central"
|
||||
COMPANY_ID = 110 # MARIUSM AUTO
|
||||
|
||||
ORACLE_CONFIG = {
|
||||
"user": "MARIUSM_AUTO",
|
||||
"password": "ROMFASTSOFT",
|
||||
"dsn": "10.0.20.121:1521/ROA"
|
||||
}
|
||||
|
||||
# Mapare CUI → cont cheltuială
|
||||
CUI_TO_CONT = {
|
||||
"11201891": "6022", # MOL
|
||||
"1590082": "6022", # OMV Petrom
|
||||
"14991381": "6022", # Rompetrol
|
||||
"10562600": "6021", # Dedeman / Five Holding (Brick)
|
||||
"1879865": "6021", # Five Holding
|
||||
}
|
||||
|
||||
# Mapare cotă TVA → (ID_JTVA baza, ID_JTVA tva, TAXCODE, TAXCODE_TVAI)
|
||||
# Pentru achiziții interne neexigibile (TVA la încasare)
|
||||
JTVA_NEEX = {
|
||||
21: (210, 211, 301104, 301305), # ACH. INT. NEEX. 21%
|
||||
19: (188, 189, 301101, 301301), # ACH. INT. NEEX. 19%
|
||||
11: (214, 215, 301105, 301306), # ACH. INT. NEEX. 11%
|
||||
9: (172, 173, 301102, 301302), # ACH. INT. NEEX. 9%
|
||||
5: (174, 175, 301103, 301303), # ACH. INT. NEEX. 5%
|
||||
}
|
||||
|
||||
# Pentru achiziții interne normale (fără TVA la încasare)
|
||||
JTVA_NORMAL = {
|
||||
21: (208, 209, 301104, 301305), # ACH. INT. 21%
|
||||
19: (None, None, 301101, 301301),
|
||||
9: (None, None, 301102, 301302),
|
||||
}
|
||||
|
||||
|
||||
def get_cont(cui: str) -> str:
|
||||
"""Mapare CUI → cont cheltuială."""
|
||||
cui_clean = (cui or "").upper().replace("RO", "").strip()
|
||||
return CUI_TO_CONT.get(cui_clean, "6028") # 6028 = alte cheltuieli
|
||||
|
||||
|
||||
class APIClient:
|
||||
"""Client pentru roa2web API."""
|
||||
|
||||
def __init__(self, base_url: str):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.token = None
|
||||
self.session = requests.Session()
|
||||
|
||||
def login(self, username: str, password: str, server_id: str) -> bool:
|
||||
"""Login și obține token."""
|
||||
r = self.session.post(
|
||||
f"{self.base_url}/api/auth/login",
|
||||
json={"username": username, "password": password, "server_id": server_id}
|
||||
)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
self.token = data.get("access_token")
|
||||
self.session.headers["Authorization"] = f"Bearer {self.token}"
|
||||
return True
|
||||
print(f"Login failed: {r.status_code} - {r.text}")
|
||||
return False
|
||||
|
||||
def ocr_extract(self, file_path: Path) -> dict:
|
||||
"""Submit OCR job și așteaptă rezultatul."""
|
||||
# Determine mime type
|
||||
suffix = file_path.suffix.lower()
|
||||
if suffix == ".pdf":
|
||||
mime_type = "application/pdf"
|
||||
elif suffix in (".jpg", ".jpeg"):
|
||||
mime_type = "image/jpeg"
|
||||
elif suffix == ".png":
|
||||
mime_type = "image/png"
|
||||
else:
|
||||
# Try to detect from content
|
||||
with open(file_path, "rb") as f:
|
||||
header = f.read(8)
|
||||
if header[:4] == b'%PDF':
|
||||
mime_type = "application/pdf"
|
||||
suffix = ".pdf"
|
||||
elif header[:3] == b'\xff\xd8\xff':
|
||||
mime_type = "image/jpeg"
|
||||
suffix = ".jpg"
|
||||
elif header[:8] == b'\x89PNG\r\n\x1a\n':
|
||||
mime_type = "image/png"
|
||||
suffix = ".png"
|
||||
else:
|
||||
mime_type = "application/pdf" # default
|
||||
suffix = ".pdf"
|
||||
|
||||
# Use proper filename with extension
|
||||
filename = file_path.stem + suffix if not file_path.suffix else file_path.name
|
||||
|
||||
# Submit
|
||||
with open(file_path, "rb") as f:
|
||||
r = self.session.post(
|
||||
f"{self.base_url}/api/data-entry/ocr/extract",
|
||||
files={"file": (filename, f, mime_type)}
|
||||
)
|
||||
if r.status_code != 200:
|
||||
return {"success": False, "error": f"OCR submit failed: {r.text}"}
|
||||
|
||||
job_id = r.json().get("job_id")
|
||||
print(f" OCR job: {job_id}")
|
||||
|
||||
# Wait for result (max 60s per request, retry if pending)
|
||||
for _ in range(4): # Max 4 retries = ~240s total
|
||||
r = self.session.get(
|
||||
f"{self.base_url}/api/data-entry/ocr/jobs/{job_id}/wait",
|
||||
params={"timeout": 60, "wait_for_terminal": "true"},
|
||||
timeout=70
|
||||
)
|
||||
if r.status_code != 200:
|
||||
return {"success": False, "error": f"OCR wait failed: {r.text}"}
|
||||
|
||||
data = r.json()
|
||||
status = data.get("status")
|
||||
|
||||
if status == "completed":
|
||||
return {"success": True, "result": data.get("result"), "time_ms": data.get("processing_time_ms")}
|
||||
elif status == "failed":
|
||||
return {"success": False, "error": data.get("error") or "OCR failed"}
|
||||
# Still pending/processing - will retry
|
||||
|
||||
return {"success": False, "error": "OCR timeout"}
|
||||
|
||||
def create_receipt(self, ocr_result: dict, company_id: int) -> dict:
|
||||
"""Creează receipt în SQLite via API cu TOATE datele."""
|
||||
# Parse date
|
||||
date_str = ocr_result.get("receipt_date")
|
||||
if date_str:
|
||||
receipt_date = date_str[:10] # YYYY-MM-DD
|
||||
else:
|
||||
receipt_date = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# Build TVA breakdown from OCR
|
||||
tva_breakdown = []
|
||||
for tva_entry in (ocr_result.get("tva_entries") or []):
|
||||
tva_breakdown.append({
|
||||
"code": tva_entry.get("code"),
|
||||
"percent": tva_entry.get("percent"),
|
||||
"amount": float(tva_entry.get("amount") or 0)
|
||||
})
|
||||
|
||||
# Build payment methods from OCR
|
||||
payment_methods = []
|
||||
for pm in (ocr_result.get("payment_methods") or []):
|
||||
payment_methods.append({
|
||||
"method": pm.get("method"),
|
||||
"amount": float(pm.get("amount") or 0)
|
||||
})
|
||||
|
||||
# Determine payment mode
|
||||
payment_mode = ocr_result.get("suggested_payment_mode") or "casa"
|
||||
# If has CARD payment, it's "banca"
|
||||
if any(pm.get("method", "").upper() == "CARD" for pm in payment_methods):
|
||||
payment_mode = "banca"
|
||||
elif any(pm.get("method", "").upper() == "NUMERAR" for pm in payment_methods):
|
||||
payment_mode = "casa"
|
||||
|
||||
payload = {
|
||||
"receipt_type": "bon_fiscal",
|
||||
"direction": "cheltuiala",
|
||||
"receipt_number": ocr_result.get("receipt_number"),
|
||||
"receipt_series": ocr_result.get("receipt_series"),
|
||||
"receipt_date": receipt_date,
|
||||
"amount": float(ocr_result.get("amount") or 0),
|
||||
"partner_name": ocr_result.get("partner_name"),
|
||||
"cui": ocr_result.get("cui"),
|
||||
"tva_total": float(ocr_result.get("tva_total") or 0),
|
||||
"tva_breakdown": tva_breakdown if tva_breakdown else None,
|
||||
"payment_methods": payment_methods if payment_methods else None,
|
||||
"payment_mode": payment_mode,
|
||||
"company_id": company_id,
|
||||
"vendor_address": ocr_result.get("address"),
|
||||
"items_count": ocr_result.get("items_count"),
|
||||
"ocr_raw_text": ocr_result.get("raw_text"),
|
||||
}
|
||||
|
||||
# Remove None values
|
||||
payload = {k: v for k, v in payload.items() if v is not None}
|
||||
|
||||
self.session.headers["X-Selected-Company"] = str(company_id)
|
||||
r = self.session.post(
|
||||
f"{self.base_url}/api/data-entry/receipts/",
|
||||
json=payload
|
||||
)
|
||||
|
||||
if r.status_code in (200, 201):
|
||||
return {"success": True, "receipt": r.json()}
|
||||
else:
|
||||
return {"success": False, "error": f"Create receipt failed: {r.text}"}
|
||||
|
||||
|
||||
def get_or_create_partner(cursor, cui: str, name: str, address: str = None) -> int:
|
||||
"""Găsește sau creează partener în Oracle. Returnează ID_PART."""
|
||||
cui_clean = (cui or "").upper().replace("RO", "").strip()
|
||||
|
||||
if not cui_clean:
|
||||
return 0 # No CUI, no partner
|
||||
|
||||
# Try to find existing partner
|
||||
cursor.execute("""
|
||||
SELECT ID_PART FROM NOM_PARTENERI
|
||||
WHERE COD_FISCAL = :cui OR COD_FISCAL = :cui2
|
||||
""", cui=cui_clean, cui2="RO" + cui_clean)
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row:
|
||||
return row[0] # Found existing partner
|
||||
|
||||
# Create new partner
|
||||
cursor.execute("SELECT SEQ_NOM_PARTENERI.NEXTVAL FROM DUAL")
|
||||
new_id = cursor.fetchone()[0]
|
||||
|
||||
# Clean name
|
||||
partner_name = (name or f"PARTENER {cui_clean}")[:100]
|
||||
partner_address = (address or "")[:200]
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO NOM_PARTENERI (ID_PART, NUME, COD_FISCAL, ADRESA, STERS, INACTIV)
|
||||
VALUES (:id_part, :nume, :cui, :adresa, 0, 0)
|
||||
""", id_part=new_id, nume=partner_name, cui=cui_clean, adresa=partner_address)
|
||||
|
||||
print(f" ➕ Partener nou creat: ID={new_id}, CUI={cui_clean}, Nume={partner_name}")
|
||||
return new_id
|
||||
|
||||
|
||||
def check_tva_incasare(cursor, an: int, luna: int) -> bool:
|
||||
"""Verifică dacă firma e plătitoare de TVA la încasare în perioada dată."""
|
||||
cursor.execute("""
|
||||
SELECT NVL(TVA_INCASARE, 0) FROM CALENDAR
|
||||
WHERE AN = :an AND LUNA = :luna
|
||||
""", an=an, luna=luna)
|
||||
row = cursor.fetchone()
|
||||
return row[0] == 1 if row else False
|
||||
|
||||
|
||||
def save_to_oracle(ocr_result: dict, do_commit: bool = False) -> dict:
|
||||
"""Salvează nota contabilă în Oracle cu toate regulile."""
|
||||
conn = oracledb.connect(**ORACLE_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# Parse date
|
||||
date_str = ocr_result.get("receipt_date")
|
||||
if date_str:
|
||||
receipt_date = datetime.strptime(date_str[:10], "%Y-%m-%d").date()
|
||||
else:
|
||||
receipt_date = datetime.now().date()
|
||||
|
||||
an, luna = receipt_date.year, receipt_date.month
|
||||
|
||||
# 1. Get or create partner
|
||||
id_part = get_or_create_partner(
|
||||
cursor,
|
||||
ocr_result.get("cui"),
|
||||
ocr_result.get("partner_name"),
|
||||
ocr_result.get("address")
|
||||
)
|
||||
print(f" Partner ID: {id_part}")
|
||||
|
||||
# 2. Check TVA la încasare
|
||||
tva_incasare = check_tva_incasare(cursor, an, luna)
|
||||
cont_tva = "4428" if tva_incasare else "4426"
|
||||
print(f" TVA la încasare: {'DA (4428)' if tva_incasare else 'NU (4426)'}")
|
||||
|
||||
# 3. Determine payment type
|
||||
payment_methods = ocr_result.get("payment_methods") or []
|
||||
has_cash = any(pm.get("method", "").upper() == "NUMERAR" for pm in payment_methods)
|
||||
has_card = any(pm.get("method", "").upper() == "CARD" for pm in payment_methods)
|
||||
|
||||
# If no payment info, assume cash
|
||||
if not payment_methods:
|
||||
has_cash = True
|
||||
|
||||
print(f" Plată: {'NUMERAR' if has_cash else ''}{' + ' if has_cash and has_card else ''}{'CARD' if has_card else ''}")
|
||||
|
||||
# 4. Init PACK_CONTAFIN
|
||||
cursor.callproc('PACK_CONTAFIN.INITIALIZEAZA_SCRIERE_ACT_RUL',
|
||||
[0, datetime.now(), an, luna, 0, 0, 0, 0])
|
||||
|
||||
# 5. Get next COD
|
||||
cursor.execute(
|
||||
"SELECT NVL(MAX(COD), 0) + 1 FROM ACT WHERE AN = :an AND LUNA = :luna",
|
||||
an=an, luna=luna
|
||||
)
|
||||
cod = cursor.fetchone()[0]
|
||||
|
||||
# 6. Calculate amounts
|
||||
total = float(ocr_result.get("amount") or 0)
|
||||
tva = float(ocr_result.get("tva_total") or 0)
|
||||
fara_tva = total - tva
|
||||
|
||||
nract = ocr_result.get("receipt_number", "")
|
||||
nract = int(nract) if str(nract).isdigit() else 0
|
||||
|
||||
cont_cheltuiala = get_cont(ocr_result.get("cui") or "")
|
||||
expl = f"OCR: {ocr_result.get('partner_name') or 'N/A'}"[:100]
|
||||
|
||||
print(f" COD: {cod}, Cont: {cont_cheltuiala}")
|
||||
print(f" Total: {total}, Bază: {fara_tva}, TVA: {tva}")
|
||||
|
||||
# 7. Process TVA entries from OCR (pot fi mai multe cote TVA)
|
||||
tva_entries = ocr_result.get("tva_entries") or []
|
||||
|
||||
# 8. Build accounting lines
|
||||
lines = []
|
||||
|
||||
# Calculate base for each TVA rate
|
||||
if tva_entries:
|
||||
# Process each TVA entry separately
|
||||
for tva_entry in tva_entries:
|
||||
tva_rate = tva_entry.get("percent") or 21
|
||||
tva_amount = float(tva_entry.get("amount") or 0)
|
||||
|
||||
if tva_amount <= 0:
|
||||
continue
|
||||
|
||||
# Calculate base for this TVA rate
|
||||
base_amount = tva_amount / (tva_rate / 100)
|
||||
|
||||
# Get ID_JTVA_COLOANA and TAXCODE based on TVA rate and TVA la încasare
|
||||
if tva_incasare:
|
||||
jtva_data = JTVA_NEEX.get(tva_rate, (210, 211, 301104, 301305))
|
||||
else:
|
||||
jtva_data = JTVA_NORMAL.get(tva_rate, (208, 209, 301104, 301305))
|
||||
|
||||
jtva_baza, jtva_tva, taxcode_normal, taxcode_tvai = jtva_data
|
||||
taxcode = taxcode_tvai if tva_incasare else taxcode_normal
|
||||
|
||||
print(f" TVA {tva_rate}%: baza={base_amount:.2f}, tva={tva_amount:.2f}, JTVA=({jtva_baza},{jtva_tva}), TAXCODE={taxcode}")
|
||||
|
||||
# Linia cheltuială pentru această cotă
|
||||
lines.append({
|
||||
"scd": cont_cheltuiala, "scc": "401",
|
||||
"suma": base_amount, "expl": expl,
|
||||
"id_partc": id_part, "id_partd": 0,
|
||||
"id_jtva": jtva_baza,
|
||||
"taxcode": taxcode
|
||||
})
|
||||
|
||||
# Linia TVA pentru această cotă
|
||||
proc_tva = 1 + tva_rate / 100 # 1.21, 1.19, etc.
|
||||
lines.append({
|
||||
"scd": cont_tva, "scc": "401",
|
||||
"suma": tva_amount, "expl": f"TVA {tva_rate}% {expl}"[:100],
|
||||
"id_partc": id_part, "id_partd": 0,
|
||||
"proc_tva": proc_tva,
|
||||
"id_jtva": jtva_tva,
|
||||
"taxcode": taxcode
|
||||
})
|
||||
else:
|
||||
# Fallback: use total amounts if no tva_entries
|
||||
if fara_tva > 0:
|
||||
tva_rate = round(tva / fara_tva * 100) if fara_tva > 0 else 21
|
||||
else:
|
||||
tva_rate = 21
|
||||
|
||||
if tva_incasare:
|
||||
jtva_data = JTVA_NEEX.get(tva_rate, (210, 211, 301104, 301305))
|
||||
else:
|
||||
jtva_data = JTVA_NORMAL.get(tva_rate, (208, 209, 301104, 301305))
|
||||
|
||||
jtva_baza, jtva_tva, taxcode_normal, taxcode_tvai = jtva_data
|
||||
taxcode = taxcode_tvai if tva_incasare else taxcode_normal
|
||||
|
||||
print(f" TVA {tva_rate}% (estimat): JTVA=({jtva_baza},{jtva_tva}), TAXCODE={taxcode}")
|
||||
|
||||
lines.append({
|
||||
"scd": cont_cheltuiala, "scc": "401",
|
||||
"suma": fara_tva, "expl": expl,
|
||||
"id_partc": id_part, "id_partd": 0,
|
||||
"id_jtva": jtva_baza,
|
||||
"taxcode": taxcode
|
||||
})
|
||||
|
||||
if tva > 0:
|
||||
proc_tva = 1 + tva_rate / 100
|
||||
lines.append({
|
||||
"scd": cont_tva, "scc": "401",
|
||||
"suma": tva, "expl": f"TVA {tva_rate}% {expl}"[:100],
|
||||
"id_partc": id_part, "id_partd": 0,
|
||||
"proc_tva": proc_tva,
|
||||
"id_jtva": jtva_tva,
|
||||
"taxcode": taxcode
|
||||
})
|
||||
|
||||
# Linia plată din casă (DOAR dacă plată numerar)
|
||||
if has_cash and not has_card:
|
||||
lines.append({
|
||||
"scd": "401", "scc": "5311",
|
||||
"suma": total, "expl": f"Plata {expl}"[:100],
|
||||
"id_partc": 0, "id_partd": id_part,
|
||||
"id_jtva": None, # Nu are JTVA pentru plată
|
||||
"taxcode": None
|
||||
})
|
||||
# Dacă plată CARD - nu se face nota 401=5311 (se face la extras bancar)
|
||||
|
||||
# ID_FDOC = 17 pentru BON FISCAL
|
||||
id_fdoc = 17
|
||||
|
||||
# 9. Insert lines
|
||||
for line in lines:
|
||||
proc_tva = line.get("proc_tva") or 0 # Default 0 for non-TVA lines
|
||||
id_jtva = line.get("id_jtva") # Poate fi None pentru plăți
|
||||
taxcode = line.get("taxcode") # Poate fi None pentru plăți
|
||||
cursor.execute("""
|
||||
INSERT INTO ACT_TEMP (
|
||||
LUNA, AN, COD, DATAIREG, DATAACT, NRACT,
|
||||
EXPLICATIA, SCD, SCC, SUMA, PROC_TVA,
|
||||
ID_PARTC, ID_PARTD, ID_FDOC, ID_JTVA_COLOANA, TAXCODE, ID_UTIL, DATAORA
|
||||
) VALUES (
|
||||
:luna, :an, :cod, TRUNC(SYSDATE), :dataact, :nract,
|
||||
:expl, :scd, :scc, :suma, :proc_tva,
|
||||
:id_partc, :id_partd, :id_fdoc, :id_jtva, :taxcode, 0, SYSDATE
|
||||
)
|
||||
""",
|
||||
luna=luna, an=an, cod=cod, dataact=receipt_date, nract=nract,
|
||||
expl=line["expl"], scd=line["scd"], scc=line["scc"],
|
||||
suma=line["suma"], proc_tva=proc_tva,
|
||||
id_partc=line["id_partc"], id_partd=line["id_partd"],
|
||||
id_fdoc=id_fdoc, id_jtva=id_jtva, taxcode=taxcode
|
||||
)
|
||||
jtva_info = f" [JTVA={id_jtva}]" if id_jtva else ""
|
||||
taxcode_info = f" [TAX={taxcode}]" if taxcode else ""
|
||||
print(f" {line['scd']} = {line['scc']}: {line['suma']:.2f}{jtva_info}{taxcode_info}")
|
||||
|
||||
# 9. Finalize
|
||||
mesaj = cursor.var(oracledb.STRING, 4000)
|
||||
cursor.callproc('PACK_CONTAFIN.FINALIZEAZA_SCRIERE_ACT_RUL',
|
||||
[0, cod, 0, 0, 0, mesaj])
|
||||
|
||||
if do_commit:
|
||||
conn.commit()
|
||||
return {"success": True, "cod": cod, "luna": luna, "an": an, "saved": True,
|
||||
"id_part": id_part, "tva_incasare": tva_incasare}
|
||||
else:
|
||||
conn.rollback()
|
||||
return {"success": True, "cod": cod, "luna": luna, "an": an, "saved": False,
|
||||
"id_part": id_part, "tva_incasare": tva_incasare}
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
import traceback
|
||||
return {"success": False, "error": str(e), "traceback": traceback.format_exc()}
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
def process_bon(file_path: Path, do_save: bool = False, company_id: int = COMPANY_ID,
|
||||
api_user: str = API_USER, api_pass: str = API_PASS):
|
||||
"""Procesează un bon fiscal: OCR → SQLite → Oracle."""
|
||||
print("=" * 60)
|
||||
print(f"📄 Procesez: {file_path.name}")
|
||||
print("=" * 60)
|
||||
|
||||
# 1. Login
|
||||
print("\n🔑 Login API...")
|
||||
client = APIClient(API_BASE)
|
||||
if not client.login(api_user, api_pass, SERVER_ID):
|
||||
print("❌ Login failed!")
|
||||
return None
|
||||
print(" ✅ OK")
|
||||
|
||||
# 2. OCR
|
||||
print("\n🔍 OCR extract...")
|
||||
ocr_result = client.ocr_extract(file_path)
|
||||
if not ocr_result["success"]:
|
||||
print(f" ❌ {ocr_result['error']}")
|
||||
return None
|
||||
|
||||
ocr = ocr_result["result"]
|
||||
print(f" ✅ OK ({ocr_result.get('time_ms', '?')}ms)")
|
||||
print(f" CUI: {ocr.get('cui')}")
|
||||
print(f" Partner: {ocr.get('partner_name')}")
|
||||
print(f" Data: {ocr.get('receipt_date')}")
|
||||
print(f" Total: {ocr.get('amount')} RON")
|
||||
print(f" TVA: {ocr.get('tva_total')} RON")
|
||||
|
||||
# Show payment methods
|
||||
payment_methods = ocr.get("payment_methods") or []
|
||||
if payment_methods:
|
||||
pm_str = ", ".join(f"{pm.get('method')}: {pm.get('amount')}" for pm in payment_methods)
|
||||
print(f" Plăți: {pm_str}")
|
||||
|
||||
# Show TVA breakdown
|
||||
tva_entries = ocr.get("tva_entries") or []
|
||||
if tva_entries:
|
||||
tva_str = ", ".join(f"{t.get('code')}({t.get('percent')}%): {t.get('amount')}" for t in tva_entries)
|
||||
print(f" TVA detaliat: {tva_str}")
|
||||
|
||||
# 3. SQLite (via API) - cu TOATE datele
|
||||
print("\n💾 Save SQLite (via API)...")
|
||||
sqlite_result = client.create_receipt(ocr, company_id)
|
||||
if not sqlite_result["success"]:
|
||||
print(f" ❌ {sqlite_result['error']}")
|
||||
return None
|
||||
|
||||
receipt = sqlite_result["receipt"]
|
||||
print(f" ✅ Receipt ID: {receipt.get('id')}")
|
||||
print(f" Payment mode: {receipt.get('payment_mode')}")
|
||||
|
||||
# 4. Oracle (direct)
|
||||
mode = "SAVE" if do_save else "DRY RUN"
|
||||
print(f"\n🗄️ Save Oracle ({mode})...")
|
||||
oracle_result = save_to_oracle(ocr, do_commit=do_save)
|
||||
|
||||
if oracle_result["success"]:
|
||||
if oracle_result["saved"]:
|
||||
print(f" ✅ SALVAT: COD={oracle_result['cod']}, {oracle_result['luna']:02d}/{oracle_result['an']}")
|
||||
else:
|
||||
print(f" ⚠️ DRY RUN: ar fi COD={oracle_result['cod']}")
|
||||
else:
|
||||
print(f" ❌ {oracle_result.get('error')}")
|
||||
if oracle_result.get("traceback"):
|
||||
print(oracle_result["traceback"])
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
return {
|
||||
"ocr": ocr,
|
||||
"sqlite_receipt_id": receipt.get("id"),
|
||||
"oracle": oracle_result
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Procesare bon fiscal: OCR → SQLite → Oracle")
|
||||
parser.add_argument("file", help="Path către PDF sau imagine")
|
||||
parser.add_argument("--save", action="store_true", help="Salvează efectiv în Oracle")
|
||||
parser.add_argument("--company", type=int, default=COMPANY_ID, help="Company ID")
|
||||
parser.add_argument("--user", default=API_USER, help="API username")
|
||||
parser.add_argument("--password", default=API_PASS, help="API password")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
file_path = Path(args.file)
|
||||
if not file_path.exists():
|
||||
print(f"❌ File not found: {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
result = process_bon(file_path, do_save=args.save, company_id=args.company,
|
||||
api_user=args.user, api_pass=args.password)
|
||||
|
||||
if result:
|
||||
print("\n✅ Done!")
|
||||
else:
|
||||
print("\n❌ Failed!")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user