En validar un albarà amb transportista, Odoo automatitza quatre coses: la crida a l'API, l'etiqueta PDF adjunta a l'albarà, el número de seguiment a carrier_tracking_ref i el correu o SMS al client amb aquest número. No automatitza la recollida física ni la veritat del pes i els bultos. Aquí va el flux amb el model d'Odoo de cada pas i el codi dels nostres connectors de Correos Express i MRW, que fem servir al nostre propi magatzem. Sense Odoo al darrere, el mateix és a integrar l'API d'un transportista en una web pròpia.
Idea clau: la fallada cara no és l'etiqueta que no surt, sinó la que no surt i ningú se n'assabenta. Un connector seriós distingeix l'error de dades (el mostra i no reintenta) de l'error del transportista (l'encua, reintenta amb espera creixent i l'escriu al chatter).
Què cal abans
- Contracte i credencials de l'entorn correcte. Correos Express separa test (
www.test.cexpr.es) i producció (www.cexpr.es); MRW usa el servei web Sagec amb franquícia, abonat, departament, usuari i contrasenya. Tots dos porten un botó de prova de connexió (action_cex_test_connectioniaction_mrw_test_connection) per verificar-ho abans del primer enviament real. - Adreça normalitzada. Nom, carrer, població, CP de cinc dígits a Espanya i telèfon d'almenys nou dígits, en remitent i destinatari: la llista literal de
_cex_validate_shipment_inputs. - Pes i bultos a l'albarà. Els mòduls llegeixen els paquets (
package_level_ids/package_ids) o, si no n'hi ha, un bulto ambshipping_weightoweight. Pes zero no surt. - Tipus d'operació amb «Imprimir etiqueta». A Odoo 19 la crida automàtica en validar només passa amb
print_labelactivat. És la causa més comuna de «he validat i no ha passat res».
El flux pas a pas, amb el model d'Odoo a cada pas
- Validar (
stock.picking._action_done). Odoo 19 crida_send_confirmation_email, questock_deliverysobreescriu: amb transportistarate_and_ship, sense tracking encara i tipus d'operació que imprimeix etiqueta, executasend_to_shipper()abans de compondre el correu. - Cridar l'API (
delivery.carrier.send_shipping). Odoo despatxa acex_send_shippingomrw_send_shipping: JSON contraapiRestGrabacionEnviok8s/jsona Correos Express, SOAPTransmEnviocontrasagec.mrw.esa MRW. Si ja hi havia número d'enviament, es retorna l'existent. - Desar l'etiqueta (
ir.attachment). El PDF s'adjunta a l'albarà com aEtiqueta_CEX_<número>.pdfoEtiqueta_MRW_<número>.pdfi es publica al chatter. Amb diversos bultos, Correos Express en retorna diverses amb sufix_01,_02… - Escriure el tracking (
carrier_tracking_ref).send_to_shipperprentracking_numberde la resposta, l'escriu al camp estàndard i publica «Paquete enviado al transportista … con número de rastreo …». Els mòduls desen a més el seu número propi. - Avisar el client (
mail.template/sms.template).stockenvia «Shipping: Send by Email» si la companyia té activada la confirmació per correu, istock_smsl'SMS. Totes dues inclouen el tracking només sicarrier_tracking_refja està emplenat.

Validar abans de cridar: què es comprova i què retorna el transportista si no
El transportista valida, però tard i amb missatges per al seu equip. Els mòduls comproven primer a Odoo i només criden si no hi ha errors; si n'hi ha, un únic UserError amb tots. Si tot i així rebutja, la resposta es classifica per paraules clau i es tradueix a una frase per a l'operari; l'administrador veu el detall tècnic.
| Comprovació a Odoo | Si el transportista ho rebutja igualment | Què veu l'operari |
|---|---|---|
| Adreça, població, CP de 5 dígits (ES), telèfon ≥ 9 dígits | Resposta amb «dirección», «código postal», «teléfono», «destinatario», «población» o «país» | «CEX detectó errores de dirección/CP/teléfono en remitente o destinatario» |
| Pes major que zero, almenys un bulto, màxim 99 (CEX) | Resposta amb «peso», «kilos», «bulto», «volumen», «alto», «largo», «ancho» | «CEX rechazó peso o datos de bultos» / «MRW rechaza el peso del envío para el servicio seleccionado» |
| Servei coherent amb la destinació: internacional (90/91) no per a Espanya, PAQ Empresa (92) només a empreses | Codi de servei no contractat o no vàlid | MRW reintenta amb els codis alternatius del preset i del catàleg; si cap no entra, l'administrador veu «Servicios probados» a l'error |
| Codis de client i sol·licitant presents | «unauthorized», «forbidden», «credenciales» | «CEX rechazó las credenciales del transportista». No es reintenta: no és transitori |
Reintents: una fallada silenciosa és pitjor que una de visible
Un 503 en plena preparació de comandes no és estrany. Deixar l'albarà a mitges és la pitjor resposta; empassar-se l'error, la segona. Els mòduls en fan una tercera: decidir si la fallada és transitòria i reintentar amb espera creixent.
- Transitori a Correos Express és HTTP 408, 409, 423, 425, 429, 500, 502, 503 o 504, o un missatge amb «timeout», «vuelva a intentarlo», «service unavailable» o «error interno»; MRW usa una llista més curta: 408, 429, 500, 502, 503 i 504. La resta és error de dades: es marca i es mostra.
- A l'albarà queden
cex_retry_pending,cex_retry_count,cex_retry_next_attempt,cex_last_error_messageicex_last_attempt_at(a MRW, prefixmrw_), i al chatter «CEX temporalmente no disponible. Reintento automático #1 programado para …». - Un cron cada 5 minuts recull els pendents sense número d'enviament amb l'hora acomplerta, de 50 en 50, i els passa pel mateix codi del primer intent.
- Espera: 5, 15, 30, 60, 120 i 240 minuts a Correos Express; 5, 15, 30, 60, 180 i 360 a MRW. Sis intents per defecte, configurable. En esgotar-los, «Se alcanzó el máximo de reintentos automáticos»: aquí cal una persona.
- Qui se n'assabenta: l'operari, a l'error i al chatter. Odoo 19 afegeix la seva xarxa: si en un lot ja es va processar un albarà al transportista, el següent error no reverteix el lot; es converteix en una activitat d'avís.
El fragment que fixa l'espera, al mòdul de Correos Express:
# flexigobe_correos_express/models/delivery_carrier.py (v19.0.3.0.19)
CEX_RETRY_BACKOFF_MINUTES = [5, 15, 30, 60, 120, 240]
def _cex_retry_delay_minutes(self, attempt_no):
self.ensure_one()
idx = max(int(attempt_no or 1) - 1, 0)
if idx >= len(CEX_RETRY_BACKOFF_MINUTES):
idx = len(CEX_RETRY_BACKOFF_MINUTES) - 1
return CEX_RETRY_BACKOFF_MINUTES[idx]El correu al client: quan es dispara i què porta
Es dispara en validar, no en crear l'albarà. La plantilla estàndard («Shipping: Send by Email», a Inventari → Configuració → Confirmació de correu electrònic) diu «Nos alegra informarle de que su pedido ha sido enviado» i, si hi ha carrier_tracking_ref, afegeix la referència amb enllaç a carrier_tracking_url; l'SMS de stock_sms afegeix el número de comanda (object.origin) i la referència en text pla, sense enllaç. Com que stock_delivery crida send_to_shipper abans de super()._send_confirmation_email(), el tracking ja existeix en compondre el correu. Si l'enviament ha quedat en cua de reintent, el correu surt sense tracking.
L'enllaç el construeix cada mòdul: https://s.correosexpress.com/SeguimientoSinCP/search?n=<tracking> a Correos Express i https://www.mrw.es/seguimiento_envios/MRW_historico_nacional.asp?enviament=<número> a MRW. Tracking sense enllaç vol dir que encara no hi ha referència.
Cas: els dos mòduls propis i en què es diferencien
Comparteixen arquitectura i es mantenen per a Odoo 19, 18 i 17. Les API difereixen, i es nota en l'etiqueta, l'anul·lació i el que no fan.
| Aspecte | Correos Express (v19.0.3.0.19) | MRW (v19 · 1.0.1) |
|---|---|---|
| Protocol | REST JSON: gravació, etiqueta, seguiment, recollides, PUDO, aturar lliurament | SOAP Sagec: TransmEnvio, TransmEnvioInternacional, GetEtiquetaEnvio, CancelarEnvio |
| Etiqueta | PDF, ZPL o EPL; un adjunt per bulto | PDF o ZPL per SOAP; si no arriba el binari, es descarrega de la URL que retorna MRW |
| Multibulto | Llista de bultos amb pes i mesures, màxim 99 | Un BultoRequest per bulto i NumeroBultos |
| Tracking | Cron cada 30 minuts que escriu estat, descripció i data a l'albarà | Botó que obre el seguiment de MRW; sense sincronització periòdica |
| Anul·lació | «Parar entrega» per API; si el contracte no ho permet, queda com a manual i avisa al chatter | CancelarEnvio; si MRW diu que ja no existeix, sincronitza l'estat local en lloc de fallar |
| Recollides | Gravar, modificar, anul·lar i consultar; cerca de punts PUDO | Només la data de recollida, dins de la petició d'enviament |
| Contra reemborsament | No: reembolso s'envia buit | No: Reembolso va fix a «N» |
Cap dels dos gestiona avui el contra reemborsament, i ens ho pregunten molt. Més a Correos Express a Odoo i MRW a Odoo; si encara estàs triant, quin transportista encaixa amb un ecommerce a Odoo.
Com comprovar que funciona
No amb el sandbox: amb un albarà real validat i aquestes quatre evidències, les de les captures.
- Un adjunt
Etiqueta_CEX_…pdfoEtiqueta_MRW_…pdfamb codi de barres llegible. El de MRW mira la capçalera del binari (%PDF-,^XA,<?xml,<html) i, si no és una etiqueta imprimible, no la desa: ho diu al chatter. carrier_tracking_refemplenat i «Etiqueta OK» amb el número d'enviament.- Al chatter: «Paquete enviado al transportista…», «Etiqueta … generada correctamente» amb el PDF, i l'SMS o correu al client si estan activats.
- Camps de reintent a zero. Si no, l'enviament no ha arribat al transportista tot i que l'albarà estigui validat.
Amb un transportista sense mòdul publicat, mateix flux i un altre adaptador: dins del servei de logística a Odoo i, per a consultores, com a enginyeria per a consultories. La regla dels nostres serveis és la mateixa: l'etiqueta surt de l'albarà, el tracking torna a l'albarà i ningú copia res.
Preguntes freqüents
L'etiqueta es genera en crear la comanda o en validar l'albarà?
En validar: _action_done dispara send_to_shipper si hi ha transportista amb integració completa, no hi ha tracking i el tipus d'operació té «Imprimir etiqueta». Els mòduls afegeixen un botó per llançar-ho a mà.
Per què el correu al client ha sortit sense número de seguiment?
Perquè en compondre'l carrier_tracking_ref era buit: el transportista va fallar i l'enviament va quedar en cua, o el tipus d'operació no crida el transportista en validar. El chatter diu quina és la causa.
Es pot anul·lar un enviament des d'Odoo?
Amb matisos: MRW crida CancelarEnvio; Correos Express usa «Parar entrega» i, si el contracte no la té, registra l'anul·lació com a manual. Queda al chatter.
Enllaços útils dins de FlexigoTech
El que fem sobre això
El teu magatzem continua imprimint etiquetes des del portal del transportista?
Digue'ns quin transportista fas servir, quina versió d'Odoo tens i quants albarans surten al dia. Et diem quina part ja existeix, què cal configurar i què caldria programar. Escriu a comercial@flexigobe.com o truca al +34 616 809 504.

