Sincronización automática e integracion de facturación externa hacia Goujana
Documentación técnica · Workflow de automatización- Resumen general
- Arquitectura del flujo
- Disparador: Webhook del pedido
- Resolución de identificación del cliente
- Búsqueda del usuario en Goujana
- Decisión: usuario existente vs. nuevo
- Creación de usuario (con fallback de email)
- Nodo de mapeo de datos
- Construcción del payload de la factura
- Envío de la factura a Goujana
- Variables y configuración
- Manejo de errores y casos límite
- Consideraciones de seguridad
1 Resumen general
Este workflow automatiza la creación de facturas de venta en Goujana a partir de los pedidos pagados generados en una plataforma externa de comercio electrónico. Cuando la plataforma confirma el pago de una orden, envía un webhook hacia el motor de automatización; el flujo identifica (o crea) al cliente en Goujana, mapea y normaliza los datos del pedido, arma el payload de la factura con sus líneas de producto y costos de envío, y finalmente registra la factura de venta vía la API REST de Goujana.
2 Arquitectura del flujo
El flujo se compone de los siguientes nodos principales, ejecutados en orden:
| # | Nodo | Tipo | Responsabilidad |
|---|---|---|---|
| 1 | Webhook order |
Webhook | Recibe el evento de pedido pagado desde la plataforma externa. |
| 2 | get identification |
Mapeo (Python) | Determina la identificación del cliente (NIT/Cédula o fallback). |
| 3 | Get User in Goujana |
HTTP GET | Consulta si el usuario ya existe en Goujana. |
| 4 | User Default |
Mapeo (JS) | Resuelve el user_id o construye el payload de creación. |
| 5 | if_user_exist |
Switch | Bifurca según exista o no el usuario. |
| 6 | Post_user_created |
HTTP POST | Crea al usuario en Goujana cuando no existe. |
| 7 | if_user_created |
Switch | Verifica si la creación fue exitosa o falló por email duplicado. |
| 8 | Post_user_created_secundary_emails |
HTTP POST | Reintenta la creación moviendo el email a secundary_emails. |
| 9 | Payload Creator |
Mapeo (JS) | Construye el payload final de la factura de venta. |
| 10 | Post invoice |
HTTP POST | Crea la factura de venta en Goujana. |
Plataforma externa (pedido pagado)
│
▼
[Webhook order] ──► [get identification] ──► [Get User in Goujana]
│
▼
[User Default]
│
▼
[if_user_exist]
┌───────┴───────┐
(no existe) (existe)
│ │
▼ │
[Post_user_created] │
│ │
▼ │
[if_user_created] │
┌────────┴────────┐ │
(email duplicado) (creado) │
│ │ │
▼ │ │
[Post_user_created_secundary_emails]│ │
│ │ │
└────────┬───────┘ │
▼ │
[Payload Creator] ◄──────┘
│
▼
[Post invoice]
│
▼
Goujana API
3 Disparador: Webhook del pedido
El nodo Webhook order expone un endpoint POST al que la plataforma externa envía el evento de pedido pagado. La URL pública apunta a:
POST https://<motor-de-automatizacion>/webhook/<uuid>
El cuerpo (body) recibido contiene la información completa del pedido: identificadores, totales, datos del cliente, dirección de facturación y envío, líneas de producto, descuentos, impuestos y costos de envío. Este objeto es el insumo principal de todos los nodos posteriores.
Cabeceras típicas relevantes para validación de origen:
- Cabecera de tópico/evento (ej.
order/paid). - Cabecera con el dominio o ID de la tienda emisora.
- Cabecera con el ID único del pedido y del webhook.
- Cabecera de firma HMAC para validar autenticidad del origen.
4 Resolución de identificación del cliente
El nodo de mapeo get identification (Python) extrae el documento de identidad del cliente usando la siguiente lógica:
- Lee
body.billing_address.company. Por convención, este campo se usa en el checkout de la plataforma para almacenar la cédula o NIT del comprador. - Si
companyestá vacío, se genera una identificación de respaldo con el formatoSHOP-<customer.id>, garantizando que siempre exista un identificador único para crear o consultar al usuario en Goujana.
identification = address.get("company") or f"SHOP-{customer.get('id')}"
5 Búsqueda del usuario en Goujana
El nodo Get User in Goujana consulta la API:
GET https://goujana.co/api/v1/base_model_s/user/?identification={identification}
Header: X-API-TOKEN: ********
Se espera una respuesta paginada con un array results. Si contiene al menos un elemento, se considera que el usuario ya existe y su id se reutiliza para la factura.
6 Decisión: usuario existente vs. nuevo
El nodo de mapeo User Default centraliza esta decisión:
- Si
Get User in Goujanaretornó resultados, devuelve{ user_id }. - Si no existe, construye un objeto
create_user_payloadcon los datos del cliente provenientes del webhook (nombre, email, teléfono, dirección, ciudad, estado).
A continuación, el nodo Switch if_user_exist evalúa la propiedad user_id:
- Salida 1 - "Crear usuario":
user_idno existe → flujo de creación. - Salida 2 - "Se encontró usuario":
user_idexiste → directo aPayload Creator.
7 Creación de usuario (con fallback de email)
7.1 Creación primaria
El nodo Post_user_created envía:
POST https://goujana.co/api/v1/base_model_s/user/
{
"type_document": "1",
"identification": "...",
"first_name": "...",
"last_name": "...",
"email": "...",
"phone": "...",
"address": "...",
"city": "...",
"state": "..."
}
Este nodo está configurado con onError: "continueRegularOutput", por lo que aunque Goujana devuelva error (ej. email duplicado), el flujo continúa y se evalúa la respuesta.
7.2 Validación de la respuesta
El nodo if_user_created evalúa dos casos:
- Error al crear: si
error.messagecontiene"Los campos email", indica que ese email ya existe asociado a otro usuario en Goujana. En ese caso se intenta una segunda creación moviendo el email al camposecundary_emails. - Usuario creado: si la respuesta tiene
id, ese valor se usa comouser_idde la factura.
7.3 Reintento con email secundario
El nodo Post_user_created_secundary_emails repite el POST pero deja email vacío y coloca el correo dentro de un arreglo en secundary_emails:
{
"email": "",
"secundary_emails": "[correo@dominio.com]",
...
}
8 Nodo de mapeo de datos
El flujo cuenta con varios nodos de mapeo que actúan como transformadores entre el modelo de datos de la plataforma externa y el modelo de datos esperado por Goujana. Estos nodos son el corazón de la integración: aíslan la lógica de negocio y permiten ajustar la transformación sin tocar las llamadas HTTP.
| Nodo de mapeo | Lenguaje | Entrada | Salida | Propósito |
|---|---|---|---|---|
get identification |
Python | Body del webhook | { identification } |
Extrae o genera el documento de identidad del cliente. |
User Default |
JavaScript | Resultado del GET | { user_id } o { create_user_payload } |
Decide entre reutilizar usuario o preparar uno nuevo. |
Payload Creator |
JavaScript | Webhook + datos del usuario resuelto | Payload completo de factura | Mapeo principal: convierte el pedido al formato de Goujana. |
Reglas de mapeo principales
El nodo Payload Creator aplica las siguientes reglas de transformación:
| Campo origen (plataforma) | Campo destino (Goujana) | Transformación |
|---|---|---|
order.created_at |
date |
Se recorta solo la parte YYYY-MM-DD. |
order.order_number |
reference y custom_integer_1 |
Se convierte a string. |
order.line_items[].sku |
details[].element |
Se parsea como entero (ID de producto en Goujana). |
order.line_items[].title |
details[].description |
Se prefija con alerta si el SKU es inválido. |
order.line_items[].price |
details[].unit_value |
Se convierte a float. |
order.line_items[].quantity |
details[].quantity |
Sin transformación. |
order.shipping_lines[] |
details[] |
Se mapea como línea adicional con producto fijo de envío. |
order.total_price |
payments[0].value |
Se convierte a float. |
order.email |
create_user_payload.email |
Solo si el usuario no existe. |
order.billing_address |
create_user_payload.address/city/state/phone |
Concatenación de campos de dirección. |
9 Construcción del payload de la factura
El nodo Payload Creator arma el cuerpo final de la factura. Primero valida que la orden esté pagada y confirmada:
if (order.financial_status !== "paid" || !order.confirmed) {
return [{ json: { stop: true, reason: "Orden no confirmada o no pagada" } }];
}
9.1 Resolución del user_id
Se intenta en este orden:
if_user_exist(usuario existente).Post_user_created(usuario recién creado).Post_user_created_secundary_emails(creado con email secundario).
9.2 Detalle de líneas (productos)
Cada línea de producto del pedido se mapea a un detalle de la factura. La clave está en el SKU: en Goujana, este campo se interpreta como el id del producto.
- Si el SKU es numérico válido → se usa como
element. - Si el SKU está vacío o no es numérico → se usa el producto por defecto (
DEFAULT_PRODUCT_ID = 84066) y se prefija la descripción con "¡ERROR DE SINCRONIZACIÓN, EL SKU NO EXISTE!" para alertar visualmente.
9.3 Costos de envío
Cada línea de envío del pedido se agrega como un detalle adicional, usando el producto fijo SHIPPING_PRODUCT_ID = 84087 con cantidad 1 y el valor del envío.
9.4 Pagos
Se registra un único pago con el total de la orden, usando el método de pago PAYMENT_METHOD_ID = 2378 y la fecha de creación de la orden.
9.5 Estructura final del payload
{
"user_db_id": 9627,
"company": 67224,
"branch": 1180,
"user": <user_id resuelto>,
"date": "YYYY-MM-DD",
"observation": "Compra desde plataforma externa: Orden #2178",
"custom_integer_1": "2178",
"reference": "2178",
"retentions": [],
"details": [
{
"element": 81625,
"description": "Nombre del producto",
"unit_value": 40000,
"quantity": 1,
"chart_account": "415535",
"taxes": [],
"retentions": []
},
{
"element": 84087,
"description": "Costo de Envío",
"unit_value": 16500,
"quantity": 1,
"chart_account": "415535",
"taxes": [],
"retentions": []
}
],
"payments": [
{
"value": 52500,
"reference": 2178,
"date": "2025-11-30",
"payment_method": 2378
}
],
"send_to_dian_now": false
}
10 Envío de la factura a Goujana
El nodo final Post invoice realiza:
POST https://goujana.co/api/v1/billing_s/invoicesell/
Headers:
X-API-TOKEN: ********
Content-Type: application/json
Body: <payload generado por Payload Creator>
send_to_dian_now está fijado en false. Esto significa que la factura se crea en Goujana pero no se envía automáticamente a la DIAN en este momento. Cambiar a true si se desea emisión inmediata.11 Variables y configuración
El nodo Payload Creator declara una serie de constantes que son específicas de cada instalación de Goujana. Los valores que aparecen a continuación son de ejemplo y deben reemplazarse por los valores reales del ERP donde se vaya a desplegar la integración.
id único asignado por el ERP.| Variable | Valor de ejemplo | Descripción | Dónde obtenerlo en el ERP |
|---|---|---|---|
USER_DB_ID |
9627 | Usuario que ejecuta la operación en Goujana. | Módulo de Usuarios del ERP. |
COMPANY_ID |
67224 | Empresa emisora de la factura. | Módulo de Empresas / configuración general. |
BRANCH_ID |
1180 | Sucursal o punto de venta donde se registra la factura. | Módulo de Sucursales de la empresa. |
PAYMENT_METHOD_ID |
2378 | Método de pago configurado para la pasarela de la plataforma. | Módulo de Métodos de pago en facturación. |
SHIPPING_PRODUCT_ID |
84087 | Producto genérico utilizado para facturar el costo de envío. | Módulo de Productos / Inventario. |
DEFAULT_PRODUCT_ID |
84066 | Producto fallback cuando el SKU del pedido no es válido. | Módulo de Productos / Inventario. |
CHART_ACCOUNT |
"415535" | Cuenta contable PUC asociada (típicamente Ingresos por ventas). | Módulo de Plan Único de Cuentas (PUC). |
Pasos para parametrizar la integración
- Ingresar al ERP Goujana con un usuario administrador.
- Identificar y anotar los
idreales de cada elemento listado en la tabla (empresa, sucursal, método de pago, productos de envío y fallback, cuenta contable). - Reemplazar los valores de ejemplo dentro del nodo
Payload Creatorpor los valores reales obtenidos. - Ejecutar una prueba con un pedido de prueba antes de habilitar el flujo en producción.
X-API-TOKEN de Goujana aparecen en el JSON exportado del workflow. Antes de versionar o compartir el flujo, estos tokens deben moverse a las Credentials del motor de automatización y nunca commitearse en texto plano. Lo mismo aplica para cualquier secreto de validación HMAC del webhook.12 Manejo de errores y casos límite
Payload Creator retorna { stop: true, reason: ... } y la factura no se genera.84066 y se marca la descripción con alerta visible para corrección manual.SHOP-<customer.id> que evita fallas en la creación del usuario.secundary_emails.13 Consideraciones de seguridad y mejoras
- Validar HMAC del webhook para evitar peticiones falsificadas desde fuera de la plataforma origen.
- Mover los tokens de API de Goujana a las Credentials del motor de automatización.
- Idempotencia: usar el ID único del webhook o el
order_numbercomo llave para evitar facturar dos veces si la plataforma reenvía el evento (la mayoría de plataformas reintentan ante fallos de respuesta). - Logging y notificaciones: añadir un nodo de notificación (email/Slack) ante fallos en la creación de usuario o factura.
- Respuesta al webhook: devolver explícitamente
200 OKal final del flujo para que la plataforma marque el webhook como procesado. - Manejo de impuestos: el array
taxesestá vacío. Si los precios incluyen IVA y Goujana debe discriminarlo, evaluar el mapeo de las líneas de impuestos del pedido.