497 lines
18 KiB
Markdown
Executable File
497 lines
18 KiB
Markdown
Executable File
# Mini AI `.202` - riconciliazione banca/incassi
|
|
|
|
## Obiettivo
|
|
|
|
Usare la macchina `.202` come motore di suggerimenti per riconciliare incassi, movimenti bancari e scritture contabili. La mini AI non deve scrivere sul gestionale: deve restituire proposte controllabili dall'operatore.
|
|
|
|
## Primo perimetro reale
|
|
|
|
- Stabile: `0016` / `stabile_id=17`
|
|
- Fonte incassi iniziale: `netgescon.incassi`, importata da `singolo_anno.mdb.incassi`
|
|
- Fonte movimenti banca: `contabilita_movimenti_banca`, import Fucino validato
|
|
- Stato `in_da_ec`: opzionale; se vuota, il payload usa automaticamente `netgescon.incassi`
|
|
|
|
## Configurazione NetGescon
|
|
|
|
Sul nodo applicativo impostare:
|
|
|
|
```env
|
|
MINI_AI_ENABLED=true
|
|
MINI_AI_BASE_URL=http://192.168.0.202:8000
|
|
MINI_AI_RECONCILIATION_PATH=/api/v1/reconciliation/incassi
|
|
MINI_AI_TIMEOUT=30
|
|
```
|
|
|
|
Se la mini AI espone autenticazione bearer, aggiungere anche:
|
|
|
|
```env
|
|
MINI_AI_TOKEN=<token locale della macchina .202>
|
|
```
|
|
|
|
Poi eseguire:
|
|
|
|
```bash
|
|
php artisan config:clear
|
|
php artisan netgescon:mini-ai-incassi --codice-stabile=0016 --limit=2 --dry-run
|
|
php artisan netgescon:mini-ai-incassi --codice-stabile=0016 --limit=20
|
|
```
|
|
|
|
Se la UI `admin-filament/contabilita/incassi` mostra `Mini AI non abilitata`, il controllo locale e:
|
|
|
|
```bash
|
|
php artisan tinker --execute='dump(config("services.mini_ai"));'
|
|
php artisan config:clear
|
|
```
|
|
|
|
La pagina salva comunque la richiesta in `ai_requests`, ma non prova la POST verso `.202` finche `MINI_AI_ENABLED=true` non e attivo.
|
|
|
|
## Endpoint atteso su `.202`
|
|
|
|
La macchina `.202` deve esporre:
|
|
|
|
```text
|
|
POST /api/v1/reconciliation/incassi
|
|
```
|
|
|
|
Input: JSON prodotto da NetGescon con:
|
|
|
|
- `task = reconcile_incassi_movimenti_bancari`
|
|
- `mode = read_only_suggestions`
|
|
- `snapshot.meta`
|
|
- `snapshot.records[]`
|
|
- `snapshot.records[].payer_reference` quando il bonifico contiene `Coord.Ordinante`, `Banca Ordinante`, `Cro`
|
|
|
|
Output richiesto:
|
|
|
|
```json
|
|
{
|
|
"summary": "string",
|
|
"warnings": ["string"],
|
|
"suggestions": [
|
|
{
|
|
"legacy_key": "inc:11172",
|
|
"confidence": 0.82,
|
|
"suggested_incasso_id": 11172,
|
|
"suggested_movimento_id": 15800,
|
|
"suggested_action": "review",
|
|
"reason": "Importo coincidente; data lontana, richiede controllo umano.",
|
|
"allocations": [
|
|
{
|
|
"rate_id": 42230,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Acconto gestione corrente indicato nella causale."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Regole operative HUB incassi
|
|
|
|
- La coda operativa deve mostrare solo movimenti banca interni alla finestra delle gestioni ordinarie aperte.
|
|
- Per lo stabile `0016` la finestra verificata e `2024/25` + `2025/26`; la UI deve poter comunque spostare la competenza sulla gestione chiusa immediatamente precedente `2023/24` quando la causale banca indica saldi o conguagli dell anno precedente.
|
|
- I riferimenti `Coord.Ordinante`, `Banca Ordinante`, `BIC/SWIFT` e `CRO` vanno trattati come indizi forti: se l operatore conferma il soggetto corretto, il mapping deve essere memorizzato per accelerare i pagamenti successivi della stessa banca/IBAN.
|
|
- Nel blocco C/I dell HUB il nominativo operatore deve seguire questo ordine: `unita_immobiliari.denominazione`, poi `gescon_import.condomin.nom_cond`, solo in ultima istanza `soggetti` legacy.
|
|
- Le spese straordinarie aperte vanno tenute in una sezione separata dalle rate ordinarie e devono restare visibili fino a chiusura effettiva, anche se la coda operativa ordinaria lavora su una finestra di gestioni piu stretta.
|
|
- Nel riepilogo del C/I il gestionale deve esporre anche i parziali del dovuto per tipo (`ordinarie` / `straordinarie`), per gestione e il totale generale dovuto: servono per solleciti e chiusure contabili in partita doppia.
|
|
- Se una gestione straordinaria esiste in `gestioni_contabili` / `lavori_straordinari` ma non produce righe residue sull interno, la UI deve segnalarla come possibile buco di import/materializzazione delle spese straordinarie.
|
|
|
|
Azioni ammesse:
|
|
|
|
- `link`: proposta molto forte, comunque da confermare in NetGescon
|
|
- `review`: caso plausibile ma da verificare
|
|
- `ignore`: non sembra riconciliabile
|
|
- `duplicate`: sospetto duplicato o movimento gia coperto
|
|
|
|
## Prompt da dare all'agent sulla `.202`
|
|
|
|
```text
|
|
Sei la mini AI banca/contabilita di NetGescon. Devi esporre un servizio HTTP locale su /api/v1/reconciliation/incassi che riceve snapshot JSON read-only da NetGescon.
|
|
|
|
Regole:
|
|
- Non scrivere mai sul gestionale.
|
|
- Non chiamare API di update.
|
|
- Restituisci solo suggerimenti JSON.
|
|
- Usa importo, data, descrizione, nominativo, scala/interno, ricevuta, protocollo e candidati movimento.
|
|
- Le spese bancarie ricorrenti, bolli, commissioni e canoni banca vanno classificate come casi facili ma non collegate a incassi condominiali.
|
|
- I CBILL vanno riconosciuti dal codice/causale quando presente.
|
|
- Se la confidenza e bassa o ci sono piu candidati simili, usa suggested_action=review.
|
|
- Se un movimento sembra gia registrato o duplicato, usa suggested_action=duplicate.
|
|
- Rispondi sempre con JSON valido: summary, warnings, suggestions[].
|
|
|
|
Schema suggestion:
|
|
legacy_key, confidence, suggested_incasso_id, suggested_movimento_id, suggested_action, reason, allocations[].
|
|
|
|
Quando il record contiene `candidate_rates`, devi valorizzare `allocations[]` con il sottoinsieme di rate selezionato. Ogni elemento deve contenere almeno: `rate_id`, `amount`, `ci`, `gestione`, `reason`.
|
|
|
|
Nella UI di NetGescon, le allocazioni della risposta vengono mostrate nel pannello mini AI e possono essere trasferite sulle imputazioni manuali del movimento selezionato con il comando `Applica allocazioni AI alle rate`.
|
|
La chiusura della riconciliazione resta comunque bloccata alla quadratura esatta tra importo banca e totale imputato.
|
|
```
|
|
|
|
## Apprendimento progressivo
|
|
|
|
Nella prima fase l'apprendimento avviene salvando:
|
|
|
|
- payload inviato in `ai_requests.request_text`
|
|
- risposta in `ai_requests.response_text`
|
|
- feedback operatore nella UI incassi / feedback AI
|
|
|
|
Solo dopo una serie di risposte corrette si potra introdurre una tabella regole o una memoria dedicata per pattern ricorrenti come spese bancarie, CBILL, MAV e bonifici con causali standard.
|
|
|
|
## Servizio persistente su `.202` con systemd
|
|
|
|
Quando l'endpoint risponde correttamente ai test manuali, renderlo persistente con `systemd`. Esempio di unit, da adattare al percorso reale dell'app mini AI sulla `.202`:
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=NetGescon Mini AI Reconciliation API
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=michele
|
|
WorkingDirectory=/home/michele/mini-ai-reconciliation
|
|
Environment=MINI_AI_TOKEN=
|
|
ExecStart=/home/michele/mini-ai-reconciliation/.venv/bin/uvicorn app:app --host 0.0.0.0 --port 8000 --workers 2
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Comandi sulla `.202`:
|
|
|
|
```bash
|
|
sudo nano /etc/systemd/system/netgescon-mini-ai.service
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now netgescon-mini-ai.service
|
|
sudo systemctl status netgescon-mini-ai.service
|
|
journalctl -u netgescon-mini-ai.service -f
|
|
```
|
|
|
|
Se si abilita token bearer, impostare `MINI_AI_TOKEN` nella unit e configurare lo stesso valore sul nodo NetGescon con `MINI_AI_TOKEN=<token>`. Non salvare token nei documenti o in chat.
|
|
|
|
## Caso guida: Barone Michele, bonifico `1.285,70`
|
|
|
|
Movimento banca reale:
|
|
|
|
- `contabilita_movimenti_banca.id = 15523`
|
|
- data `2025-01-16`
|
|
- importo `1.285,70`
|
|
- descrizione banca:
|
|
|
|
```text
|
|
BONIFICO A VOSTRO FAVORE NETHOME DI BARONE MICHELE E C. SOCI Data Regolamento: 16/01/25 Coord.Ordinante: IT85 H010 3003 2710 0000 1540 577 Banca Ordinante: 01030/01697-PASCITMM Cro: A100267492801030480320003200IT Note: SALDO CONDOMINIO ANNO 2024 E ACC.TO 2025 E/C R IF. sc.B int.4 BARONE MICHELE Id.Operazione: 277385815
|
|
```
|
|
|
|
Comando NetGescon per generare il payload:
|
|
|
|
```bash
|
|
php artisan netgescon:mini-ai-incassi --movimento-id=15523 --limit=30 --dry-run > payload-barone-15523.json
|
|
curl -sS -X POST 'http://192.168.0.202:8000/api/v1/reconciliation/incassi' \
|
|
-H 'Content-Type: application/json' \
|
|
-d @payload-barone-15523.json
|
|
```
|
|
|
|
Regola attesa:
|
|
|
|
- leggere `sc.B int.4` e `BARONE MICHELE`
|
|
- attribuire il movimento al ramo `C` se le rate candidate sono `ci=C`
|
|
- interpretare `SALDO CONDOMINIO ANNO 2024 E ACC.TO 2025` come:
|
|
- saldo gestione chiusa/adiacente `2023/24`
|
|
- acconto gestione corrente `2024/25`
|
|
- non andare su gestioni molto vecchie
|
|
- non selezionare rate successive al pagamento se esiste una combinazione esatta sulle rate gia emesse alla data del versamento
|
|
- scegliere la combinazione che torna a `1.285,70`
|
|
|
|
Allocazione attesa per il caso Barone:
|
|
|
|
```json
|
|
{
|
|
"legacy_key": "mov:15523",
|
|
"confidence": 0.98,
|
|
"suggested_incasso_id": null,
|
|
"suggested_movimento_id": 15523,
|
|
"suggested_action": "link",
|
|
"reason": "La causale indica saldo condominio anno 2024 e acconto 2025; scala/interno e nominativo coincidono; la somma delle rate selezionate coincide con il bonifico.",
|
|
"allocations": [
|
|
{
|
|
"rate_id": 41225,
|
|
"amount": 87.84,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "Conguaglio esercizio precedente, saldo anno 2024."
|
|
},
|
|
{
|
|
"rate_id": 41457,
|
|
"amount": 87.84,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "Conguaglio esercizio precedente, saldo anno 2024."
|
|
},
|
|
{
|
|
"rate_id": 41261,
|
|
"amount": 87.84,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "Conguaglio esercizio precedente, saldo anno 2024."
|
|
},
|
|
{
|
|
"rate_id": 41077,
|
|
"amount": 241.00,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "Rata giugno-luglio 2024 inclusa nel saldo anno 2024."
|
|
},
|
|
{
|
|
"rate_id": 41517,
|
|
"amount": 241.00,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "Rata agosto-settembre 2024 inclusa nel saldo anno 2024."
|
|
},
|
|
{
|
|
"rate_id": 42230,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Prima rata gestione 2024/25, acconto 2025."
|
|
},
|
|
{
|
|
"rate_id": 42276,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Seconda rata gestione 2024/25, acconto 2025."
|
|
},
|
|
{
|
|
"rate_id": 41668,
|
|
"amount": 93.09,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "ATTO AeR ricevuto 05/07/24, prima rata."
|
|
},
|
|
{
|
|
"rate_id": 41597,
|
|
"amount": 93.09,
|
|
"ci": "C",
|
|
"gestione": "2023/24",
|
|
"reason": "ATTO AeR ricevuto 05/07/24, seconda rata."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Somma attesa `allocations.amount`: `1.285,70`.
|
|
|
|
Nota per l'agent `.202`: nel payload Barone sono presenti anche rate candidate non selezionate. Non vanno scelte se non servono alla quadratura o se sono fuori dalla causale. In particolare, con questa causale non selezionare rate provvisorie vecchie o la `3/6 Rata FEBBRAIO-MARZO 25` se la combinazione sopra quadra gia esattamente.
|
|
|
|
## Caso guida: Barone Michele, bonifico `960,79`
|
|
|
|
Movimento banca reale:
|
|
|
|
- `contabilita_movimenti_banca.id = 15953`
|
|
- data `2025-12-23`
|
|
- importo `960,79`
|
|
- descrizione banca:
|
|
|
|
```text
|
|
BONIFICO A VOSTRO FAVORE NETHOME DI BARONE MICHELE E C. SOCI Data Regolamento: 23/12/25 Coord.Ordinante: IT85 H010 3003 2710 0000 1540 577 Banca Ordinante: 01030/01697-PASCITMM Cro: A108446418101030480320003200IT Note: SALDO CONDOMINIO ANNO 2025 E ACC.TO 2026 E/C R IF. sc.B int.4 BARONE MICHELE Id.Operazione: 304017429
|
|
```
|
|
|
|
Comando NetGescon per generare il payload:
|
|
|
|
```bash
|
|
php artisan netgescon:mini-ai-incassi --movimento-id=15953 --limit=40 --dry-run > payload-barone-15953.json
|
|
curl -sS -X POST 'http://192.168.0.202:8000/api/v1/reconciliation/incassi' \
|
|
-H 'Content-Type: application/json' \
|
|
-d @payload-barone-15953.json
|
|
```
|
|
|
|
Regola attesa:
|
|
|
|
- leggere `sc.B int.4` e `BARONE MICHELE`
|
|
- attribuire il movimento al ramo `C` se le rate candidate sono `ci=C`
|
|
- interpretare `SALDO CONDOMINIO ANNO 2025 E ACC.TO 2026` come:
|
|
- saldo gestione `2024/25`
|
|
- acconto gestione `2025/26`
|
|
- includere i conguagli negativi se servono alla quadratura
|
|
- non selezionare rate successive non necessarie se esiste una combinazione esatta
|
|
- scegliere la combinazione che torna a `960,79`
|
|
|
|
Allocazione attesa:
|
|
|
|
```json
|
|
{
|
|
"legacy_key": "mov:15953",
|
|
"confidence": 0.98,
|
|
"suggested_incasso_id": null,
|
|
"suggested_movimento_id": 15953,
|
|
"suggested_action": "link",
|
|
"reason": "La causale indica saldo condominio anno 2025 e acconto 2026; scala/interno e nominativo coincidono; la somma delle rate selezionate coincide con il bonifico.",
|
|
"allocations": [
|
|
{
|
|
"rate_id": 41878,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "3/6 rata gestione 2024/25, saldo anno 2025."
|
|
},
|
|
{
|
|
"rate_id": 42355,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "4/6 rata gestione 2024/25, saldo anno 2025."
|
|
},
|
|
{
|
|
"rate_id": 42546,
|
|
"amount": -0.61,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Conguaglio negativo da includere nella quadratura."
|
|
},
|
|
{
|
|
"rate_id": 42468,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "5/6 rata gestione 2024/25, saldo anno 2025."
|
|
},
|
|
{
|
|
"rate_id": 42706,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "6/6 rata gestione 2024/25, saldo anno 2025."
|
|
},
|
|
{
|
|
"rate_id": 42803,
|
|
"amount": 177.00,
|
|
"ci": "C",
|
|
"gestione": "2025/26",
|
|
"reason": "Prima rata gestione 2025/26, acconto 2026."
|
|
},
|
|
{
|
|
"rate_id": 42134,
|
|
"amount": 38.20,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Lav. facciata lato parrocchia, prima rata capitolato."
|
|
},
|
|
{
|
|
"rate_id": 42194,
|
|
"amount": 38.20,
|
|
"ci": "C",
|
|
"gestione": "2024/25",
|
|
"reason": "Lav. facciata lato parrocchia, seconda rata capitolato."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Somma attesa `allocations.amount`: `960,79`.
|
|
|
|
Nota per l'agent `.202`: nel payload `mov:15953` sono presenti anche rate candidate non selezionate, come `1/6` e `2/6` 2024/25 o rate successive 2025/26. Non vanno scelte se il saldo indicato dalla causale quadra gia con la combinazione sopra.
|
|
|
|
## BUG risolto nel primo collaudo
|
|
|
|
Il payload da 20 righe supera `64 KB`; `ai_requests.request_text` e `response_text` devono essere `LONGTEXT`. La migration `2026_06_07_130000_expand_ai_requests_text_columns.php` applica questa correzione.
|
|
|
|
## Collaudo end-to-end 07/06/2026
|
|
|
|
Endpoint `.202` verificato:
|
|
|
|
```text
|
|
POST http://192.168.0.202:8000/api/v1/reconciliation/incassi
|
|
```
|
|
|
|
Esito con payload di esempio fornito dall'agent `.202`:
|
|
|
|
- HTTP `200`
|
|
- risposta valida con `summary`, `warnings`, `suggestions[]`
|
|
- match forte su esempio `inc:11172 -> movimento 15800`, `confidence=0.99`, `suggested_action=link`
|
|
|
|
Esito con payload reale prodotto da NetGescon:
|
|
|
|
```bash
|
|
MINI_AI_ENABLED=true MINI_AI_BASE_URL=http://192.168.0.202:8000 MINI_AI_RECONCILIATION_PATH=/api/v1/reconciliation/incassi php artisan netgescon:mini-ai-incassi --codice-stabile=0016 --limit=2
|
|
```
|
|
|
|
- `ai_request_id=2`
|
|
- risposta ricevuta e salvata in `ai_requests`
|
|
- `status=answered`
|
|
- `request_len=4600`
|
|
- `response_len=734`
|
|
- risposta: `2 record analizzati; 2 review`
|
|
- suggerimenti su `inc:11172 -> movimento 15800` e `inc:11170 -> movimento 15822`, entrambi `confidence=0.45` e `suggested_action=review`
|
|
|
|
Interpretazione: il collegamento funziona. La qualita del suggerimento e volutamente prudente per i primi dati reali, perche i candidati hanno importi uguali ma date distanti o ambigue.
|
|
|
|
Esito successivo con payload movimento Barone:
|
|
|
|
- comando: `php artisan netgescon:mini-ai-incassi --movimento-id=15523 --limit=30`
|
|
- richiesta generata: `legacy_key=mov:15523`, `candidate_rates=14`
|
|
- risposta `.202` attuale: link al movimento con `confidence=0.99`, ma senza `allocations[]`
|
|
- prossimo aggiornamento richiesto all'agent `.202`: usare `candidate_rates` e restituire la scomposizione rate nel formato indicato sopra.
|
|
|
|
Esito con payload movimento Barone `960,79`:
|
|
|
|
- comando: `php artisan netgescon:mini-ai-incassi --movimento-id=15953 --limit=40`
|
|
- richiesta generata: `legacy_key=mov:15953`, `candidate_rates=12`
|
|
- risposta `.202` attuale: link al movimento con `confidence=0.99`, ma `allocations=[]`
|
|
- prossimo aggiornamento richiesto all'agent `.202`: includere conguagli negativi e selezionare il sottoinsieme esatto da `960,79`.
|
|
|
|
## Caso guida: Caschetto Lucia / Curatola Antonio, bonifico `1.968,23`
|
|
|
|
Movimento banca reale:
|
|
|
|
- `contabilita_movimenti_banca.id = 15803`
|
|
- data `2026-04-30`
|
|
- importo `1.968,23`
|
|
- descrizione banca:
|
|
|
|
```text
|
|
BONIFICO A VOSTRO FAVORE CURATOLA ANTONIO Data Regolamento: 30/04/26 Coord.Ordinante: IT57 F020 0805 2120 0000 3789 819 Banca Ordinante: 01020/02080-UNCRITMM Cro: 1101261190461826 Note: estratto conto condominiale Germanico 96 del 0 8.04.2026 Id.Operazione: NOTPROVIDED
|
|
```
|
|
|
|
Particolarita anagrafica:
|
|
|
|
- il bonifico non indica `B/18`
|
|
- il nominativo banca e `Curatola Antonio`
|
|
- nel legacy l'unita corretta e `B/18 - Caschetto Lucia`
|
|
- `gescon_import.condomin.presso = c/o Avv. Curatola`
|
|
- `gescon_import.condomin.e_mail_condomino` contiene `curatola.antonio@libero.it,lcaschetto@gmail.com`
|
|
|
|
Regola attesa:
|
|
|
|
- usare `presso` ed email come alias di riconoscimento, senza cambiare il nominativo principale della unita
|
|
- mantenere `Caschetto Lucia` come intestatario principale
|
|
- usare le rate candidate `ci=C`
|
|
- scegliere tutte le 12 rate candidate perche la somma coincide con `1.968,23`
|
|
|
|
Esito test NetGescon:
|
|
|
|
```bash
|
|
php artisan netgescon:mini-ai-incassi --movimento-id=15803 --limit=40 --dry-run
|
|
```
|
|
|
|
- `legacy_key=mov:15803`
|
|
- `nominativo=Caschetto Lucia`
|
|
- `scala=B`, `interno=18`
|
|
- `candidate_rates=12`
|
|
- somma candidate `1.968,23`
|
|
|
|
Esito `.202` dopo aggiornamento agent:
|
|
|
|
- `ai_request_id=5`
|
|
- `confidence=0.98`
|
|
- `suggested_action=link`
|
|
- `allocations[]` valorizzato con le 12 rate candidate
|
|
- risposta corretta per il primo caso con alias `presso/email`
|