Un audit utile di un connettore Odoo non parte dai test. Parte dal log e da un'operazione reale da un capo all'altro: un ordine che entra, una spedizione che esce, un rimborso che torna indietro. Il connettore Mirakl passava la sua suite in verde su Odoo 19, 18 e 17 e nascondeva 18 difetti confermati; un altro connettore di marketplace faceva 236 su 236 su build reali di Odoo.sh e nascondeva 20 difetti di contratto e 12 di versione. Quell'articolo racconta il guasto; questo racconta il metodo: dieci punti in ordine, il sintomo che rivela ciascuno e la verifica che sta in un pomeriggio.
Idea chiave: il connettore che erediti ti dice già cosa non va, nella tabella di log e nei cron spenti.
Cosa raccogliere prima di sederti
Quattro dati che non dipendono da chi ha fatto il connettore. La versione reale di Odoo: SELECT latest_version FROM ir_module_module WHERE name = 'base';. La versione dell'API di terze parti che il codice presuppone, quasi sempre visibile nell'URL di base. La data dell'ultima modifica dei mock: git log -1 --format=%cd -- tests/. E chi riceve gli errori: un'e-mail, un'attività, un file o nessuno.
I dieci punti, in ordine
1. Il log scrive davvero?
Sintomo: la tabella di log ha zero righe dopo mesi di cron. Verifica: SELECT last_value FROM pg_sequences WHERE sequencename = '<tabla_log>_id_seq';. Un NULL lì significa che quella sequenza non è mai stata letta: nessuno ha cancellato le righe, semplicemente non ne è mai stata scritta nessuna. È successo in produzione con il connettore Mirakl. L'helper che restituisce il modello di log restituiva un recordset vuoto in caso di successo, e in Odoo un recordset vuoto è falso, quindi if not log_model: return False andava sempre a buon fine e ogni «questo lo registriamo» era un no-op. La correzione è if log_model is False.
2. La data di taglio della sincronizzazione
Sintomo: un ordine creato al mattino e spedito al pomeriggio resta in Odoo con lo stato del mattino. Verifica: tre ordini che ieri hanno cambiato stato sul marketplace, confrontati con write_date e con lo stato in Odoo. In Mirakl il connettore richiedeva start_date, che filtra per data di creazione, invece di start_update_date, che filtra per data di modifica.
3. Idempotenza: doppio ordine, doppio rimborso
Sintomo: due sale.order con lo stesso riferimento esterno, o un rimborso che compare due volte sul marketplace. Verifica: SELECT client_order_ref, count(*) FROM sale_order GROUP BY 1 HAVING count(*) > 1;, e creare un duplicato da odoo shell per vedere se il database lo rifiuta davvero: che il vincolo sia scritto nel modello non significa che esista in Postgres. In Odoo 19 un _sql_constraints ereditato non crea più nulla e l'ORM lascia solo un avviso nel log, quindi perdi la garanzia senza accorgertene; al contrario è rumoroso, perché models.Constraint non esiste in 17 né in 18 e lì il modulo non si importa nemmeno. E il client HTTP: in Mirakl si riprovava davanti a 5xx e timeout per qualunque metodo, anche per il PUT del rimborso.
4. Errori HTTP e retry
Sintomo: l'account si sveglia «non autorizzato» e tutta la sincronizzazione è ferma. Verifica: provoca un 401, un 429 e, se possibile, un 403 di quota. Nel secondo caso, il 403 di quota non arrivava nel formato di errore documentato e veniva letto come errore di permessi: un limite di velocità fermava tutto. Cosa deve vedersi: Retry-After rispettato e con un tetto, i 5xx e i timeout ritentati solo sulle letture, il 429 anche sulle scritture perché il server lo ha rifiutato senza elaborarlo, e l'account bloccato solo per un vero errore di autenticazione.
5. Mock contro contratto reale
Sintomo: un campo che arriva sempre vuoto, un filtro che «non filtra». Verifica: metti nel repository l'OpenAPI attuale del fornitore e confronta i parametri di ogni wrapper, le chiavi di ogni corpo di scrittura e i campi che legge ogni parser. Nel secondo caso sono emerse così 16 discrepanze su 88 operazioni, e altre quattro solo chiamando: un'intestazione di paginazione relativa impediva di importare anche un solo ordine dalla pagina uno in poi.
6. Permessi e SSRF tramite redirect
Sintomo: nessuno, ed è per questo che sta nella lista. Verifica: grep -rn "allow_redirects\|\.sudo()\|has_group" models/. Ogni chiamata in uscita deve portare allow_redirects=False e rifiutare un 3xx, perché requests segue i redirect per impostazione predefinita e un host compromesso può mandarti a un IP interno. E ogni action_* che lavora con sudo() deve controllare il gruppo sul server: il groups= del pulsante è solo interfaccia. A luglio 2026 lo abbiamo applicato a una sedicina di connettori nostri.
7. Cron: numbercall e intervalli
Sintomo: «il cron ha smesso di girare martedì», senza errore né traccia. Verifica in Odoo 17: SELECT cron_name, active, numbercall, nextcall FROM ir_cron WHERE cron_name ILIKE '%conector%';. In 17 numbercall vale 1 per impostazione predefinita, quindi un cron dichiarato senza di esso gira una volta e si disattiva da solo, come riportato nel ir_cron.py della serie 17.0. Odoo 18 ha eliminato il campo e 19 non ce l'ha, quindi chi ha provato su 18 o 19 non l'ha mai visto. E guarda l'intervallo: una sincronizzazione completa ogni dieci minuti finisce in un 429.
8. La versione di Odoo che il codice presuppone
Sintomo: un modulo senza chatter, una scheda «payload» vuota, un ordine annullato sul marketplace che in Odoo resta confermato. Verifica: grep -rn "<chatter/>\|widget=\"json\"\|read_group\|<tree\|<list" views/ models/. In Mirakl sono usciti tutti e quattro insieme: <chatter/> esiste dalla 18, widget="json" solo nella 19, read_group è deprecato nella 19, e sale.order.action_cancel() restituisce una procedura guidata in 17 e 18 per un ordine confermato, quindi l'annullamento non avveniva mai. È la lista di un modulo che compila in Odoo 19 e non si installa.
9. Migrazione dei dati storici
Sintomo: correggi il calcolo e gli ordini vecchi restano sbagliati, perché il connettore non ritocca un ordine esistente. Verifica: conta i record precedenti alla correzione che violano la nuova regola e decidi tra uno script di migrazione e una correzione una tantum, documentata. In Mirakl erano 18 ordini con l'IVA duplicata nel totale; sono stati corretti i 15 attivi, solo se il totale coincideva con quello del marketplace. E una trappola: i dati noupdate di base, gruppi compresi, non vengono riapplicati all'aggiornamento, quindi un cambio di appartenenza lascia il gruppo vuoto in produzione e pieno nel tuo database pulito.
10. Documentazione di terze parti contro comportamento reale
Sintomo: il codice fa ciò che dice il PDF e il server fa un'altra cosa. Verifica: una chiamata reale per famiglia di endpoint e una revisione di quali endpoint sono oggi deprecati. In Mirakl il modello di importazione tramite file era ancora valido, ma la messaggistica usava un endpoint deprecato. Nel secondo caso, un endpoint accettava un solo valore dove la documentazione diceva elenco, e quel referenziale era vuoto fin dall'inizio. Va per ultimo perché è il più costoso.
Il pomeriggio, in sintesi
| Punto | Sintomo | Verifica |
|---|---|---|
| Log | Zero righe dopo mesi di cron | count(*) e pg_sequences.last_value |
| Data di taglio | Stati congelati | Ordini di ieri contro write_date |
| Idempotenza | Duplicati, doppio rimborso | GROUP BY HAVING; il database rifiuta il duplicato? |
| Errori HTTP | «Non autorizzato» dopo un 429/403 | Provocare 401, 429, 403 |
| Mock | Campo sempre vuoto | OpenAPI attuale contro wrapper e parser |
| SSRF e permessi | Nessuno | grep allow_redirects, sudo(), has_group |
| Cron | Si spegne senza errore (17) | SELECT active, numbercall FROM ir_cron |
| Versione di Odoo | Chatter o payload vuoto | grep chatter, widget json, read_group, tree/list |
| Storico | Il vecchio resta sbagliato dopo la correzione | Contare i record precedenti che violano la regola |
| Documentazione | Il server non fa ciò che dice il PDF | Una chiamata reale per famiglia di endpoint |
Cosa esce dall'audit: un report con gravità, non una lista dei desideri
Il report ordina per danno: prima il denaro (doppio rimborso, ordine duplicato, IVA due volte), poi i dati (stato congelato, log che non scrive, cron spento), poi l'ergonomia. Ogni rilievo porta con sé la sua riproduzione e ciò che non si riproduce viene cancellato: nell'audit di Mirakl sono entrati 121 candidati, 33 sono stati confutati in un passaggio scettico e solo 18 sono sopravvissuti.
La seconda uscita è il gate: la suite che c'era, in verde prima e dopo, non prova la correzione. La prova è l'esecuzione sulle tre serie su build reali, 163 su 163 su 19, 18 e 17 per Mirakl, più una verifica dal vivo. È ciò che separa un connettore nativo fatto bene da uno strato intermedio che sopravvive evitando di impegnarsi.
Quando si corregge e quando si riscrive
Si corregge quando il modello dei dati è giusto (una tabella per oggetto di terze parti, un log, un riferimento esterno univoco) e i difetti stanno nel livello HTTP, nelle finestre e nelle versioni: sta in una release, come con Mirakl. Si riscrive quando a cedere è il fondamento: un'API che il fornitore ha ritirato, niente log né riferimento esterno, scritture non idempotenti per progetto, o un connettore legato a una serie di Odoo quando te ne servono tre. È la decisione che prepariamo per società di consulenza e partner tecnologici che ereditano integrazioni, e anche quando il connettore è quello del proprio software.
Domande frequenti
Perché non partire dalla suite di test?
Perché una suite in verde dice che il codice coincide con il suo mock, non con il fornitore né con la produzione. La suite va alla fine, come gate della correzione.
Serve l'accesso alla produzione?
Per i punti 1, 2, 3, 7 e 9 sì, o a una copia: la sequenza del log, gli stati congelati, i duplicati e i cron spenti si vedono solo su dati reali.
Cosa consegnate alla fine?
Un report con ogni rilievo provato e ordinato per denaro, dati ed ergonomia; la raccomandazione di correggere o riscrivere; e, se si procede alla correzione, la modifica con il suo gate sulle serie di Odoo del cliente. Il dettaglio è nei servizi.
Link utili dentro FlexigoTech
Cosa facciamo in merito
Hai ereditato un connettore che si rompe o di cui nessuno si fida?
Raccontaci cosa integra, su quale versione di Odoo gira e quale sintomo vedi. Ti diciamo quali punti della lista guarderemmo per primi e cosa serve per farlo. Scrivi a comercial@flexigobe.com o chiama il +34 616 809 504.

