Saltar al contenido principal
Logística en Odoo · Etiquetas y seguimiento

Etiquetas y seguimiento automáticos en Odoo: del picking validado al correo del cliente

Qué se automatiza al validar un albarán, en qué modelo de Odoo vive cada paso y qué pasa cuando el transportista no responde. Con el código real de nuestros conectores de Correos Express y MRW.

Albarán de Odoo con el bloque MRW: número de solicitud, número de envío, estado «Etiqueta OK» y el PDF de la etiqueta adjunto

Al validar un albarán con transportista, Odoo automatiza cuatro cosas: la llamada a la API, la etiqueta PDF adjunta al albarán, el número de seguimiento en carrier_tracking_ref y el correo o SMS al cliente con ese número. No automatiza la recogida física ni la verdad del peso y los bultos. Aquí va el flujo con el modelo de Odoo de cada paso y el código de nuestros conectores de Correos Express y MRW, que usamos en nuestro propio almacén. Sin Odoo detrás, lo mismo está en integrar la API de un transportista en una web propia.

Idea clave: el fallo caro no es la etiqueta que no sale, sino la que no sale y nadie se entera. Un conector serio distingue el error de datos (lo enseña y no reintenta) del error del transportista (lo encola, reintenta con espera creciente y lo escribe en el chatter).

Qué hace falta antes

  • Contrato y credenciales del entorno correcto. Correos Express separa test (www.test.cexpr.es) y producción (www.cexpr.es); MRW usa el servicio web Sagec con franquicia, abonado, departamento, usuario y contraseña. Los dos traen un botón de prueba de conexión (action_cex_test_connection y action_mrw_test_connection) para verificarlo antes del primer envío real.
  • Dirección normalizada. Nombre, calle, población, CP de cinco dígitos en España y teléfono de al menos nueve dígitos, en remitente y destinatario: la lista literal de _cex_validate_shipment_inputs.
  • Peso y bultos en el albarán. Los módulos leen los paquetes (package_level_ids / package_ids) o, si no hay, un bulto con shipping_weight o weight. Peso cero no sale.
  • Tipo de operación con «Imprimir etiqueta». En Odoo 19 la llamada automática al validar solo ocurre con print_label activado. Es la causa más común de «he validado y no ha pasado nada».

El flujo paso a paso, con el modelo de Odoo en cada paso

  1. Validar (stock.picking._action_done). Odoo 19 llama a _send_confirmation_email, que stock_delivery sobrescribe: con transportista rate_and_ship, sin tracking aún y tipo de operación que imprime etiqueta, ejecuta send_to_shipper() antes de componer el correo.
  2. Llamar a la API (delivery.carrier.send_shipping). Odoo despacha a cex_send_shipping o mrw_send_shipping: JSON contra apiRestGrabacionEnviok8s/json en Correos Express, SOAP TransmEnvio contra sagec.mrw.es en MRW. Si ya había número de envío, se devuelve el existente.
  3. Guardar la etiqueta (ir.attachment). El PDF se adjunta al albarán como Etiqueta_CEX_<número>.pdf o Etiqueta_MRW_<número>.pdf y se publica en el chatter. Con varios bultos, Correos Express devuelve varias con sufijo _01, _02
  4. Escribir el tracking (carrier_tracking_ref). send_to_shipper toma tracking_number de la respuesta, lo escribe en el campo estándar y publica «Paquete enviado al transportista … con número de rastreo …». Los módulos guardan además su número propio.
  5. Avisar al cliente (mail.template / sms.template). stock envía «Shipping: Send by Email» si la compañía tiene activada la confirmación por correo, y stock_sms el SMS. Ambas incluyen el tracking solo si carrier_tracking_ref ya está relleno.
Albarán de Odoo 19 en producción con el bloque de Correos Express: estado «Etiqueta OK», número de envío, códigos de bulto, campos de reintento y el chatter con el SMS al cliente, el mensaje de envío al transportista y la etiqueta PDF
Nuestro Odoo 19 en producción, albarán validado con Correos Express: número de envío, códigos de bulto y campos de reintento; en el chatter, SMS al cliente con el tracking, «Paquete enviado al transportista» y etiqueta PDF.

Validar antes de llamar: qué se comprueba y qué devuelve el transportista si no

El transportista valida, pero tarde y con mensajes para su equipo. Los módulos comprueban primero en Odoo y solo llaman si no hay errores; si los hay, un único UserError con todos. Si aun así rechaza, la respuesta se clasifica por palabras clave y se traduce a una frase para el operario; el administrador ve el detalle técnico.

Comprobación en OdooSi el transportista lo rechaza igualmenteLo que ve el operario
Dirección, población, CP de 5 dígitos (ES), teléfono ≥ 9 dígitosRespuesta con «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»
Peso mayor que cero, al menos un bulto, máximo 99 (CEX)Respuesta con «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»
Servicio coherente con destino: internacional (90/91) no para España, PAQ Empresa (92) solo a empresasCódigo de servicio no contratado o no válidoMRW reintenta con los códigos alternativos del preset y del catálogo; si ninguno entra, el administrador ve «Servicios probados» en el error
Códigos de cliente y solicitante presentes«unauthorized», «forbidden», «credenciales»«CEX rechazó las credenciales del transportista». No se reintenta: no es transitorio

Reintentos: un fallo silencioso es peor que uno visible

Un 503 en plena preparación de pedidos no es raro. Dejar el albarán a medias es la peor respuesta; tragarse el error, la segunda. Los módulos hacen una tercera: decidir si el fallo es transitorio y reintentar con espera creciente.

  • Transitorio en Correos Express es HTTP 408, 409, 423, 425, 429, 500, 502, 503 o 504, o un mensaje con «timeout», «vuelva a intentarlo», «service unavailable» o «error interno»; MRW usa una lista más corta: 408, 429, 500, 502, 503 y 504. El resto es error de datos: se marca y se muestra.
  • En el albarán quedan cex_retry_pending, cex_retry_count, cex_retry_next_attempt, cex_last_error_message y cex_last_attempt_at (en MRW, prefijo mrw_), y en el chatter «CEX temporalmente no disponible. Reintento automático #1 programado para …».
  • Un cron cada 5 minutos recoge los pendientes sin número de envío con la hora cumplida, de 50 en 50, y los pasa por el mismo código del primer intento.
  • Espera: 5, 15, 30, 60, 120 y 240 minutos en Correos Express; 5, 15, 30, 60, 180 y 360 en MRW. Seis intentos por defecto, configurable. Al agotarlos, «Se alcanzó el máximo de reintentos automáticos»: ahí hace falta una persona.
  • Quién se entera: el operario, en el error y en el chatter. Odoo 19 añade su red: si en un lote ya se procesó un albarán en el transportista, el siguiente error no revierte el lote; se convierte en una actividad de aviso.

El fragmento que fija la espera, en el módulo 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 correo al cliente: cuándo se dispara y qué lleva

Se dispara al validar, no al crear el albarán. La plantilla estándar («Shipping: Send by Email», en Inventario → Ajustes → Confirmación de correo electrónico) dice «Nos alegra informarle de que su pedido ha sido enviado» y, si hay carrier_tracking_ref, añade la referencia con enlace a carrier_tracking_url; el SMS de stock_sms añade el número de pedido (object.origin) y la referencia en texto plano, sin enlace. Como stock_delivery llama a send_to_shipper antes de super()._send_confirmation_email(), el tracking ya existe al componer el correo. Si el envío quedó en cola de reintento, el correo sale sin tracking.

El enlace lo construye cada módulo: https://s.correosexpress.com/SeguimientoSinCP/search?n=<tracking> en Correos Express y https://www.mrw.es/seguimiento_envios/MRW_historico_nacional.asp?enviament=<número> en MRW. Tracking sin enlace significa que aún no hay referencia.

Caso: los dos módulos propios y en qué se diferencian

Comparten arquitectura y se mantienen para Odoo 19, 18 y 17. Las API difieren, y se nota en la etiqueta, la anulación y lo que no hacen.

AspectoCorreos Express (v19.0.3.0.19)MRW (v19 · 1.0.1)
ProtocoloREST JSON: grabación, etiqueta, seguimiento, recogidas, PUDO, parar entregaSOAP Sagec: TransmEnvio, TransmEnvioInternacional, GetEtiquetaEnvio, CancelarEnvio
EtiquetaPDF, ZPL o EPL; un adjunto por bultoPDF o ZPL por SOAP; si no llega el binario, se descarga de la URL que devuelve MRW
MultibultoLista de bultos con peso y medidas, máximo 99Un BultoRequest por bulto y NumeroBultos
TrackingCron cada 30 minutos que escribe estado, descripción y fecha en el albaránBotón que abre el seguimiento de MRW; sin sincronización periódica
Anulación«Parar entrega» por API; si el contrato no lo permite, queda como manual y avisa en el chatterCancelarEnvio; si MRW dice que ya no existe, sincroniza el estado local en vez de fallar
RecogidasGrabar, modificar, anular y consultar; búsqueda de puntos PUDOSolo la fecha de recogida, dentro de la petición de envío
Contra reembolsoNo: reembolso se envía vacíoNo: Reembolso va fijo a «N»

Ninguno gestiona hoy el contra reembolso, y nos lo preguntan mucho. Más en Correos Express en Odoo y MRW en Odoo; si aún eliges, qué transportista encaja con un ecommerce en Odoo.

Cómo comprobar que funciona

No con el sandbox: con un albarán real validado y estas cuatro evidencias, las de las capturas.

  1. Un adjunto Etiqueta_CEX_…pdf o Etiqueta_MRW_…pdf con código de barras legible. El de MRW mira la cabecera del binario (%PDF-, ^XA, <?xml, <html) y, si no es etiqueta imprimible, no la guarda: lo dice en el chatter.
  2. carrier_tracking_ref relleno y «Etiqueta OK» con el número de envío.
  3. En el chatter: «Paquete enviado al transportista…», «Etiqueta … generada correctamente» con el PDF, y el SMS o correo al cliente si están activados.
  4. Campos de reintento a cero. Si no, el envío no ha llegado al transportista aunque el albarán esté validado.

Con un transportista sin módulo publicado, mismo flujo y otro adaptador: dentro del servicio de logística en Odoo y, para consultoras, como ingeniería para consultorías. La regla de nuestros servicios es la misma: la etiqueta sale del albarán, el tracking vuelve al albarán y nadie copia nada.

Preguntas frecuentes

¿La etiqueta se genera al crear el pedido o al validar el albarán?

Al validar: _action_done dispara send_to_shipper si hay transportista con integración completa, no hay tracking y el tipo de operación tiene «Imprimir etiqueta». Los módulos añaden un botón para lanzarlo a mano.

¿Por qué el correo al cliente ha salido sin número de seguimiento?

Porque al componerlo carrier_tracking_ref estaba vacío: el transportista falló y el envío quedó en cola, o el tipo de operación no llama al transportista al validar. El chatter dice cuál.

¿Se puede anular un envío desde Odoo?

Con matices: MRW llama a CancelarEnvio; Correos Express usa «Parar entrega» y, si el contrato no lo tiene, registra la anulación como manual. Queda en el chatter.

Enlaces útiles dentro de FlexigoTech

Correos Express en OdooServicios, validación previa, PUDO y recogidasMRW en OdooSOAP Sagec, etiqueta con fallback a URL, cancelaciónQué transportista encaja con un ecommerce en OdooCriterios para elegir antes de integrarLogística en Odoo: el servicioTransportistas, etiquetas y seguimiento dentro del albarán

Lo que hacemos sobre esto

Automatización con OperariaQué hace, capturas, versiones y precio.

¿Tu almacén sigue imprimiendo etiquetas desde el portal del transportista?

Dinos qué transportista usas, qué versión de Odoo tienes y cuántos albaranes salen al día. Te decimos qué parte ya existe, qué hay que configurar y qué habría que programar. Escribe a comercial@flexigobe.com o llama al +34 616 809 504.

Hablar con un ingeniero