Integraciones

Cómo diseñar una integración entre ecommerce y ERP sin duplicar pedidos

Un pedido duplicado en el ERP descuadra stock y facturación. Seis decisiones de diseño para que tu integración aguante reintentos y errores sin duplicar nada.

Un pedido duplicado en el ERP no es un error inofensivo: genera un albarán de más, descuadra el stock y acaba en una llamada incómoda con el cliente. Casi siempre se debe a lo mismo: la integración da por hecho que cada mensaje llega una sola vez. Así se diseña una integración entre tienda online y ERP que aguante reintentos, caídas y errores sin duplicar nada.

Por qué se duplican los pedidos

  • Reintentos automáticos: la tienda o el webhook reenvía el pedido porque el ERP tardó en responder, aunque sí lo había registrado.
  • Varios disparadores: el pedido se envía al crearse y otra vez al pagarse, o desde un cron y desde un evento a la vez.
  • Procesos en paralelo: dos workers cogen el mismo pedido al mismo tiempo.
  • Reenvíos manuales: alguien pulsa "volver a enviar" sin saber si el primer envío llegó.

1. Define qué sistema manda en cada dato

Antes de escribir código, decide quién es la fuente de verdad: normalmente la tienda manda en pedidos y clientes web, y el ERP en stock, precios y estados de envío. Cada dato viaja en una sola dirección. Las integraciones bidireccionales "de todo" son las que más duplicados y conflictos generan.

2. Usa una clave de idempotencia

Cada pedido debe llevar un identificador único y estable, por ejemplo el número de pedido de la tienda. El receptor guarda ese identificador y, si vuelve a llegar, devuelve el resultado anterior en lugar de crear otro pedido. Con una restricción UNIQUE en base de datos, ni dos procesos simultáneos pueden saltársela:

// Tabla de control: integration_orders (external_id UNIQUE, erp_id, status)
$registro = IntegrationOrder::firstOrCreate(
    ['external_id' => $pedido->numero],
    ['status' => 'pending']
);

if ($registro->erp_id) {
    return $registro->erp_id; // ya enviado: no se duplica
}

$erpId = $erp->crearPedido($pedido);
$registro->update(['erp_id' => $erpId, 'status' => 'sent']);

3. Encola los envíos y reintenta con cabeza

El envío al ERP no debe ocurrir dentro de la petición del cliente. Ponlo en una cola, con reintentos limitados y espera creciente entre intentos. Y separa los errores: un 400 (datos incorrectos) no se arregla reintentando; un 503 o un timeout, sí.

4. Valida el formato antes de enviar

Muchos rechazos vienen de diferencias de formato: una dirección que se envía como objeto cuando el ERP espera campos simples, decimales con coma, códigos de país distintos. Documenta el contrato de datos y valida el pedido antes de mandarlo. Es exactamente lo que resolvimos en el caso de integración de pedidos Magento 2 con una API externa.

5. Registra todo con contexto

Cada envío debe dejar rastro: pedido, payload, respuesta, código de estado y número de intento. Cuando algo falla, la alerta tiene que decir qué pedido y por qué, no solo "error en la integración".

6. Ten un proceso de conciliación

Aunque todo esté bien diseñado, conviene una comprobación diaria: pedidos de la tienda sin ID del ERP, pedidos del ERP sin origen en la tienda y estados que no coinciden. Detectarlo el mismo día es mucho más barato que descubrirlo en el cierre de mes.

Lista de comprobación rápida

  • Cada dato tiene un único sistema propietario.
  • Cada pedido viaja con una clave de idempotencia y hay restricción única en destino.
  • Los envíos van por cola, con reintentos solo para errores temporales.
  • El formato se valida antes de enviar.
  • Hay logs con contexto y alertas útiles.
  • Existe una conciliación periódica.

Si tu tienda y tu ERP no terminan de entenderse, puedo revisar la integración y proponerte un plan por fases. Mira mis servicios de desarrollo e integraciones o cuéntame tu caso.

¿Quieres aplicar estas ideas a tu proyecto?

Revisamos el contexto y definimos el siguiente paso.