# Store Profiles - OCR Extraction

Sistem de profile specifice pentru extracție OCR cu hot-reload.

---

## Quick Start: Adaugă un profil nou

```bash
# 1. Generează profil din PDF-uri (dry-run pentru preview)
python scripts/generate_store_profile.py \
  --name "Magazin Nou SRL" \
  --cui "12345678" \
  --receipts "docs/data-entry/MagazinNou*.pdf" \
  --dry-run

# 2. Generează și salvează
python scripts/generate_store_profile.py \
  --name "Magazin Nou SRL" \
  --cui "12345678" \
  --receipts "docs/data-entry/MagazinNou*.pdf" \
  --output backend/modules/data_entry/services/ocr/profiles/magazin_nou.py

# 3. Hot-reload (fără restart server)
curl -X POST http://localhost:8000/api/data-entry/ocr/profiles/reload

# 4. Verifică
curl http://localhost:8000/api/data-entry/ocr/profiles
```

---

## Structura directorului

```
profiles/
├── __init__.py        # ProfileRegistry + hot-reload (~390 linii)
├── base.py            # BaseStoreProfile + pattern-uri generice (~410 linii)
├── lidl.py            # Multi-rate TVA (A/B)
├── omv.py             # B2B, date YYYY.MM.DD
├── socar.py           # B2B, date YYYY.MM.DD
├── brick.py           # Standard TVA
├── dedeman.py         # E-factura support
├── kineterra.py       # Non-VAT payer
├── gama_ink.py        # Standard TVA (toner/cartușe)
├── electrobering.py   # Standard TVA (electronice)
├── pictus_velum.py    # Standard TVA (rechizite)
├── unlimited_keys.py  # Standard TVA, NUMERAR payment
├── best_print.py      # Non-VAT payer (neplătitor TVA)
├── stepout_market.py  # TVA 5% (cărți/librărie)
└── README.md          # Acest fișier
```

---

## Profile existente (12 profile)

> **Note**: Pattern-urile TVA sunt **flexibile** și acceptă ORICE cotă (5%, 9%, 11%, 19%, 21%, etc.)
> pentru a gestiona atât datele istorice cât și schimbările viitoare ale legislației.

| Magazin | CUI | Fișier | Caracteristici |
|---------|-----|--------|----------------|
| LIDL DISCOUNT S.R.L. | 22891860 | `lidl.py` | Multi-rate TVA (coduri A, B, C, D) |
| OMV PETROM MARKETING S.R.L. | 11201891 | `omv.py` | B2B (client CUI), date YYYY.MM.DD |
| SOCAR PETROLEUM S.A. | 12546600 | `socar.py` | B2B (client CUI), date YYYY.MM.DD |
| FIVE-HOLDING S.A. (BRICK) | 10562600 | `brick.py` | Standard TVA |
| DEDEMAN SRL | 2816464 | `dedeman.py` | E-factura support |
| KINETERRA CONCEPT SRL | 31180432 | `kineterra.py` | Non-VAT payer (returnează `[]`) |
| GAMA INK SERVICE SRL | 17741882 | `gama_ink.py` | Standard TVA (toner, cartușe) |
| ELECTROBERING S.R.L. | 2744937 | `electrobering.py` | Standard TVA (electronice) |
| PICTUS VELUM SRL | 39634534 | `pictus_velum.py` | Standard TVA (rechizite) |
| UNLIMITED KEYS S.R.L. | 18993187 | `unlimited_keys.py` | Standard TVA, **NUMERAR** plată |
| BEST PRINT TRADE ACTIV SRL | 45417955 | `best_print.py` | **Non-VAT payer** (neplătitor TVA) |
| STEPOUT MARKET SRL | 35532655 | `stepout_market.py` | TVA 5% (cărți, librărie) |

---

## API Endpoints

| Endpoint | Metodă | Descriere |
|----------|--------|-----------|
| `/api/data-entry/ocr/profiles` | GET | Lista toate profilele |
| `/api/data-entry/ocr/profiles/{cui}` | GET | Detalii profil (acceptă RO prefix) |
| `/api/data-entry/ocr/profiles/reload` | POST | Hot-reload toate profilele |

### Exemple API

```bash
# Lista profile
curl http://localhost:8000/api/data-entry/ocr/profiles \
  -H "Authorization: Bearer <token>"

# Detalii profil (cu sau fără RO prefix)
curl http://localhost:8000/api/data-entry/ocr/profiles/22891860
curl http://localhost:8000/api/data-entry/ocr/profiles/RO22891860

# Hot-reload după modificări
curl -X POST http://localhost:8000/api/data-entry/ocr/profiles/reload \
  -H "Authorization: Bearer <token>"

# Response reload:
{
  "success": true,
  "reloaded_modules": 12,
  "profiles_count": 12,
  "registered_cuis": ["22891860", "11201891", "12546600", "10562600", ...],
  "last_reload": "2026-01-06T22:37:05.000000"
}
```

---

## Cum funcționează sistemul

### Flow de extracție

```
ReceiptExtractor.extract()
  │
  ├─► STEP 1: Extrage vendor + CUI
  │     └─► _extract_vendor(), _extract_cui()
  │
  ├─► ProfileRegistry.get_profile(cui)
  │     └─► Returnează profil specific sau None
  │
  ├─► STEP 2: Extracție cu profil (dacă există)
  │     ├─► profile.extract_total()
  │     ├─► profile.extract_date()
  │     ├─► profile.extract_receipt_number()
  │     ├─► profile.extract_tva_entries()
  │     ├─► profile.extract_payment_methods()
  │     └─► profile.extract_client_cui()
  │
  └─► STEP 3-4: Validare + post-procesare
```

### Fallback

Dacă nu există profil pentru CUI, se folosește logica generică din `ReceiptExtractor`.

---

## Structura unui profil

```python
from .base import BaseStoreProfile
from . import ProfileRegistry

@ProfileRegistry.register
class MagazinNouProfile(BaseStoreProfile):
    """Docstring cu descriere magazin."""

    CUI_LIST = ["12345678"]  # Poate avea mai multe CUI-uri
    NAME_PATTERNS = ["MAGAZIN", "MAGAZIN NOU", "MAG4ZIN"]  # OCR variants
    STORE_NAME = "Magazin Nou SRL"

    # Override doar ce e diferit de base class
    def extract_tva_entries(self, text: str) -> List[dict]:
        # Pattern-uri specifice magazinului
        ...

    def get_validation_hints(self) -> Dict[str, Any]:
        return {
            "has_multi_rate_tva": False,
            "card_equals_total": True,
            "has_client_cui": False,
            "has_efactura": False,
            "is_non_vat_payer": False,
        }
```

---

## Pattern-uri disponibile în base.py

BaseStoreProfile include pattern-uri generice OCR-tolerant:

| Pattern | Descriere |
|---------|-----------|
| `TOTAL_PATTERNS` | 8 variante pentru TOTAL (TOTAL:, TOTAL DE PLATA, etc.) |
| `DATE_PATTERNS` | 6 variante (DD.MM.YYYY, YYYY-MM-DD, DD/MM/YYYY) |
| `DATE_PATTERNS_OCR_SPACES` | 4 variante cu spații OCR ("2025. 08. 14") |
| `NUMBER_PATTERNS` | 11 variante pentru număr bon (NDS, BF, C3POS) |
| `PAYMENT_PATTERNS` | 8 variante pentru CARD/NUMERAR |
| `CLIENT_MARKERS` | 6 variante pentru secțiune CLIENT |
| `CLIENT_CUI_PATTERNS` | 7 variante pentru CUI client |

### Metode implementate în base class

- `extract_total(text)` → `Tuple[Decimal, float]`
- `extract_date(text)` → `Tuple[date, float]`
- `extract_receipt_number(text)` → `Tuple[str, float]`
- `extract_payment_methods(text)` → `List[dict]`
- `extract_client_cui(text)` → `Tuple[str, float]`
- `extract_client_name(text)` → `Tuple[str, float]`

---

## Când ai nevoie de profil custom?

| Situație | Exemplu | Ce trebuie override |
|----------|---------|---------------------|
| **Multi-rate TVA** | Lidl (TVA A, TVA B) | `extract_tva_entries()` |
| **Format dată special** | OMV/Socar (YYYY.MM.DD) | `DATE_PATTERNS_OCR_SPACES` |
| **B2B receipts** | Benzinării (au client CUI) | `extract_client_cui()` |
| **Non-VAT payer** | Kineterra | `extract_tva_entries()` returnează `[]` |
| **E-factura** | Dedeman | `extract_efactura_reference()` |

---

## Decizii de design

1. **Hot-reload manual** - endpoint `/profiles/reload` apelat când se modifică fișiere
2. **Persistență în Python** - profile în Git, version controlled
3. **Fallback graceful** - dacă nu există profil, folosește logica generică
4. **CUI normalization** - gestionează automat prefixul "RO" și whitespace
5. **Deduplicare TVA** - folosește `seen = set()` pentru a evita duplicate

---

## Comenzi utile

```bash
# Verifică syntax Python pentru toate profilele
for f in backend/modules/data_entry/services/ocr/profiles/*.py; do
  python3 -m py_compile "$f" && echo "✓ $(basename $f)"
done

# Lista profile
ls -la backend/modules/data_entry/services/ocr/profiles/

# Pornește backend pentru testare
cd backend && source venv/bin/activate
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1

# Test OCR pe un PDF
curl -X POST -F "file=@docs/data-entry/test.pdf" \
  -H "Authorization: Bearer <token>" \
  "http://localhost:8000/api/data-entry/ocr/extract?engine=doctr_plus"
```

---

## Script generare profile

`scripts/generate_store_profile.py` - generator automat de profile

```bash
# Vezi help
python scripts/generate_store_profile.py --help

# Funcționalități:
# - Analizează PDF-uri via OCR API
# - Detectează: TVA format, date format, payment patterns, B2B
# - Generează cod Python cu OCR error variants
# - Suportă glob patterns (*.pdf)
# - Verifică sintaxa după generare
```
