You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Big release driven by the 2026 dichiarazione campaign:
- decaf.scripts.fill_rw + fill_rt_rm — Chrome DevTools Protocol scripts
that auto-populate Quadro RW, RT and RM31 on the AdE precompilata
- decaf archive / unarchive — portable backup of cache + reports
- ~/.cache/decaf/flexquery/ — perpetual gzipped archive of every IBKR
FlexQuery fetch (IBKR drops history after 365 days)
- CLI/PDF/XLS: dedicated "Per la dichiarazione precompilata" section
with per-rigo mapping and RL2-vs-RM31 comparison
Plus a real bug fix in compute_rl: WHT-to-income matching was naively
keyed on (currency, month), causing dividend WHT to be stolen by USD
broker interest credits posted in the same month. Now uses a two-pass
match with description+date and CREDIT INT period tags first.
See CHANGELOG for the full list.
- **Autofill della dichiarazione precompilata AdE via Chrome DevTools Protocol.** Nuovi script `python -m decaf.scripts.fill_rw` (Quadro RW — monitoraggio fiscale + IVAFE, un rigo per lotto, 5 righi per Modulo) e `python -m decaf.scripts.fill_rt_rm` (Quadro RT rigo RT11 col.1/col.2 totali plusvalenze 26% + Quadro RM Sez. II-A rigo RM31, un Modulo di Quadro RM per ogni coppia stato estero + tipo reddito). Pilota un Chrome aperto in `--remote-debugging-port=9222`, popola i campi della React app AdE bypassando il controllo dei controlled inputs (native value setter + invocazione diretta della prop `onChange`), naviga tra i Moduli rilevando il fallback URL quando la pagina richiesta non esiste ancora ed eseguendo "Aggiungi modulo + Conferma". Convenzioni di sicurezza: rifiuta di sovrascrivere campi pre-esistenti senza `--force`, abortisce se compare il banner "Salvataggio non effettuato", **non clicca mai "Calcola, stampa e invia"** — l'invio finale resta sempre una scelta manuale. Helpers CDP condivisi estratti in `decaf.scripts._cdp` per riuso. Vedi [`src/decaf/scripts/README.md`](https://github.com/vjt/decaf/blob/master/src/decaf/scripts/README.md) per prerequisiti, flag e workflow consigliato.
13
+
-**Sezione "Per la dichiarazione precompilata" nei report.** CLI, PDF e XLS espongono ora una mappa esplicita decaf → Modello Redditi PF: per ogni rigo/colonna dei quadri RW, RT, RL+RM è indicato il valore EUR e la sua origine nei dati decaf. Confronto fianco-a-fianco tra Opzione A (RL+CE, IRPEF marginale + credito imposta estera) e Opzione B (RM31, sostitutiva 26%) con simulazione del netto pagato in entrambi gli scenari ai tre scaglioni IRPEF (23/35/43%) e break-even aliquota marginale calcolato in automatico — utile per scegliere consapevolmente tra le due vie tassative per i redditi di capitale di fonte estera. Breakdown RM31 per coppia (stato, tipo reddito) con codice paese AdE, importo lordo, imposta sostitutiva, count delle entries aggregate.
14
+
-**`decaf archive` / `decaf unarchive`.** Pacchettizza in un singolo `.tgz` lo stato decaf perché sia portabile tra macchine o archiviabile come backup fiscale long-term: `~/.cache/decaf/statements.db`, `~/.cache/decaf/ecb_rates.db`, eventuali sotto-directory di cache (`flexquery/`), più qualsiasi directory extra passata via `--tree` (es. `--tree private/` per includere file sorgenti broker + report YAML/PDF/XLS generati). `decaf unarchive` ripristina i DB in `~/.cache/decaf/` e i tree sotto `--target-dir` (default: cwd) mantenendo i path originali, rifiutando di sovrascrivere file esistenti senza `--force`. Il tarball include un `metadata.yaml` con versione decaf, data di creazione, e indice del contenuto.
15
+
-**Archivio perpetuo XML FlexQuery IBKR su disco.** IBKR retiene solo ~365 giorni di storico delle FlexQuery; ad ogni `decaf load` riuscito via API, `_fetch_from_ibkr` salva ora una copia gzippata dell'XML scaricato in `~/.cache/decaf/flexquery/ibkr_<account>_<from>_<to>_<fetched_at>.xml.gz` (overridabile via `--flex-archive-dir`). Il salvataggio avviene **prima** del parsing, quindi anche un XML che decaf non riesce a ingerire sopravvive su disco e può essere riprovato in seguito con `decaf load --file`. L'account ID viene estratto con un regex senza richiedere un parse completo (fallback a `unknown` se assente). `decaf archive` include automaticamente la sotto-directory `flexquery/` nei bundle, quindi il backup completo del proprio storico fiscale è una singola invocazione.
16
+
-**`src/decaf/country_codes.py`**: mappa ISO 3166-1 alpha-2 → codice numerico AdE (US=069, IE=040, ...) per i quadri che richiedono il codice ministeriale (RM31 col.2, RW col.4). Esposta come `iso_to_ade_country_code()`.
17
+
18
+
### Fixed
19
+
20
+
- **Matching ritenute → redditi nel Quadro RL: doppio pass per evitare collisioni cross-security.** `compute_rl()` accoppia ora ogni entry di tipo `Withholding` con la corrispondente entry di reddito in due passate: (1) **strong match** — stesso `description` + stessa `date_time` (caso dividendi: WHT e dividendo postano lo stesso giorno con il nome del titolo come description), OPPURE stesso tag `CREDIT INT FOR <MMM>-<YYYY>` (caso interessi broker: la WHT e l'interesse maturato hanno descrizioni parallele del tipo `USD CREDIT INT FOR AUG-2025` / `WITHHOLDING @ 20% ON CREDIT INT FOR AUG-2025`); (2) **fallback** — stessa valuta + stesso mese, per qualunque WHT non ancora consumata. La logica precedente accoppiava solo per valuta+mese, causando due bug visibili nei broker statement reali: (a) WHT di un dividendo META in trimestre Q1 veniva "rubata" da un credito interessi USD dello stesso mese, lasciando il dividendo con WHT > gross apparente; (b) le quattro WHT trimestrali META si accumulavano tutte sulla prima riga dividendo USA del report. Sei regression test in `tests/test_quadro_rl.py` coprono i due scenari + casi misti. **Effetto sul Modello Redditi**: le righe RL e i totali aggregati per RM31 (`aggregate_rl_for_rm31`) sono ora corretti — chi ha dichiarato anni precedenti con `decaf < 0.6.0` e ha dividendi su intermediario estero + interessi sullo stesso conto dovrebbe ri-emettere il report e cross-checkare il Quadro RL/RM rispetto a quanto già dichiarato.
21
+
22
+
### Added (RW autofill — dettagli implementativi)
23
+
24
+
-**`fill_rw` field map RPF26.** Il Modulo di Quadro RW contiene 5 righi RW1-RW5; ogni rigo ha le colonne 1 (codice titolare = 1 proprietà), 3 (codice investimento), 4 (codice stato AdE numerico, NON ISO), 5 (% possesso = 100), 6 (criterio determinazione valore = 1 valore di mercato — campo *richiesto*, non server-computed), 7 (valore iniziale EUR), 8 (valore finale EUR), 10 (giorni di possesso). La colonna 30 (IVAFE dovuta) è computata server-side dopo `Salva`, non va inserita. Il form rifiuta lo `0` esplicito nel valore iniziale con "formato non corretto" — `fill_rw` usa un fallback a `1` EUR per i lotti con valore iniziale nullo (lotti acquisiti nello stesso anno di vendita). L'addressing dei field name è `RW{row:03d}{col:03d}` dove `row` è 1-5 (rigo dentro il Modulo), NON l'indice del lotto: 23 lotti → 5 Moduli (RW/1..RW/5), con righi sparsi nei vari Moduli.
25
+
- **`fill_rt_rm` field map RPF26.** Quadro RT Sez. II-A 26% = righi `RT11..RT16` (non RT21-RT27 della Sez. III-A partecipazioni qualificate). Un unico rigo RT11 aggregato col col.1 = `sum(proceeds_eur)` e col.2 = `sum(cost_basis_eur)` su tutti i `rt_lines`. Quadro RM Sez. II-A: RM31 è **un solo rigo per Modulo** — sorgenti diverse (interessi USD Schwab, dividendi META USA, interessi EUR IBKR Irlanda) richiedono Moduli di Quadro RM distinti (RM/1, RM/2, RM/3, ...). Field name = `RM031{col:03d}` dentro ogni Modulo. La colonna 8 (imposta sostitutiva = lordo × 26%) è inserita arrotondata all'intero come da prassi AdE; importi molto piccoli (≤ 0.49 EUR) cadono sullo `0` che il form rifiuta, decaf li scarta ma può essere che il form richieda comunque la colonna — controlla con *Verifica i dati*. Il form fa fallback alla `/RM/N-1` quando si naviga a `/RM/N` non ancora esistente: `fill_rt_rm` rileva la condizione confrontando `location.pathname` dopo il navigate e, se serve, torna alla `/RM/N-1` per cliccare "Aggiungi modulo" + "Conferma" prima di scrivere.
26
+
27
+
### Changed
28
+
29
+
-**Pre-commit hook allineato al CI.** Aggiunto `ruff format --check src/ tests/` al pre-commit (`.githooks/pre-commit`), per allineare le check eseguite localmente prima di un commit a quelle che girano in CI. Prima passava solo `ruff check` (lint), per cui un drift di formattazione (es. una `await cdp.eval_js(...)` spezzata su tre righe sotto i 100 char) sfuggiva al commit ma bloccava CI al push.
**De-CAF** — Generatore di report fiscale per investimenti esteri. Niente commercialista.
13
13
14
14
<palign="center">
15
-
<imgsrc="https://cdn.jsdelivr.net/gh/vjt/decaf@v0.5.0/doc/img/cover.png"alt="Mascetti, Mosconi e Magnotta alle prese con la dichiarazione dei redditi">
15
+
<imgsrc="https://cdn.jsdelivr.net/gh/vjt/decaf@v0.6.0/doc/img/cover.png"alt="Mascetti, Mosconi e Magnotta alle prese con la dichiarazione dei redditi">
16
16
</p>
17
17
18
18
Scarica i dati dai tuoi broker esteri e i tassi BCE, poi calcola tutto il necessario per il **Modello Redditi PF**:
@@ -26,12 +26,12 @@ Output: tabelle colorate nel terminale, Excel (un foglio per quadro), PDF e YAML
26
26
27
27
📝 **Articolo di presentazione**: [sindro.me — decaf: Modello Redditi PF su investimenti esteri](https://sindro.me/it/posts/2026-04-18-decaf-dichiarazione-redditi-investimenti-esteri/) ([🇬🇧 EN](https://sindro.me/posts/2026-04-18-decaf-dichiarazione-redditi-investimenti-esteri/)) — perché l'ho scritto, cosa fa in concreto, e il punto sulle plusvalenze valutarie che i broker non ti danno.
28
28
29
-
📖 **Manuale completo**: [doc/decaf_manual.pdf](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.5.0/doc/decaf_manual.pdf) — guida fiscale, normativa con riferimenti alla Gazzetta Ufficiale, architettura, internals per broker, setup Flex Query. Rigenerato ad ogni cambio in `doc/` via pre-commit hook.
29
+
📖 **Manuale completo**: [doc/decaf_manual.pdf](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.6.0/doc/decaf_manual.pdf) — guida fiscale, normativa con riferimenti alla Gazzetta Ufficiale, architettura, internals per broker, setup Flex Query. Rigenerato ad ogni cambio in `doc/` via pre-commit hook.
30
30
31
31
🎬 **Guarda un esempio di output** — fixture sintetica `mascetti` (anno 2025, stress test con soglia forex superata, multi-broker, 4 ritenute estere):
|`decaf_<year>.xlsx`| Excel | Un foglio per quadro + riepilogo |[xlsx](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.5.0/examples/mascetti/decaf_2025.xlsx)|
186
-
|`decaf_<year>.pdf`| PDF | Prospetto con tabelle e totali |[pdf](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.5.0/examples/mascetti/decaf_2025.pdf)|
187
-
|`decaf_<year>.yaml`| YAML | Dump completo del `TaxReport` — diffabile, stabile tra run |[yaml](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.5.0/examples/mascetti/decaf_2025.yaml)|
185
+
|`decaf_<year>.xlsx`| Excel | Un foglio per quadro + riepilogo |[xlsx](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.6.0/examples/mascetti/decaf_2025.xlsx)|
186
+
|`decaf_<year>.pdf`| PDF | Prospetto con tabelle e totali |[pdf](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.6.0/examples/mascetti/decaf_2025.pdf)|
187
+
|`decaf_<year>.yaml`| YAML | Dump completo del `TaxReport` — diffabile, stabile tra run |[yaml](https://cdn.jsdelivr.net/gh/vjt/decaf@v0.6.0/examples/mascetti/decaf_2025.yaml)|
0 commit comments