Deja de sufrir y comienza a Fluir

Integración de Facturación Electrónica

Image description

Sincronización automática e integracion de facturación externa hacia Goujana

Documentación técnica · Workflow de automatización

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.

Objetivo: mantener la contabilidad y facturación electrónica sincronizadas en tiempo real con la tienda online, sin intervención manual.

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.
Diagrama lógico (alto nivel)
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.
Recomendación: validar la firma HMAC contra el secreto del webhook para confirmar que el evento proviene realmente de la plataforma. Actualmente esta validación no está presente en el flujo.

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:

  1. 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.
  2. Si company está vacío, se genera una identificación de respaldo con el formato SHOP-<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 Goujana retornó resultados, devuelve { user_id }.
  • Si no existe, construye un objeto create_user_payload con 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_id no existe → flujo de creación.
  • Salida 2 - "Se encontró usuario": user_id existe → directo a Payload 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.message contiene "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 campo secundary_emails.
  • Usuario creado: si la respuesta tiene id, ese valor se usa como user_id de 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]",
  ...
}
Esta estrategia evita el conflicto de unicidad de emails en Goujana cuando un mismo correo ya estaba registrado bajo otra identificación.

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.
Buena práctica: toda lógica condicional, validación y conversión de tipos debe vivir en estos nodos de mapeo. Los nodos HTTP deben permanecer "tontos", limitándose a consumir el payload que el mapeo produce.

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:

  1. if_user_exist (usuario existente).
  2. Post_user_created (usuario recién creado).
  3. 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>
Nota: el campo 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.

Cómo obtener los valores reales: todas estas variables se pueden consultar directamente dentro del ERP Goujana, en los módulos correspondientes (usuarios, empresas, sucursales, métodos de pago, productos y plan de cuentas). No se deben copiar los valores de ejemplo: cada empresa, sucursal y producto tiene un 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
  1. Ingresar al ERP Goujana con un usuario administrador.
  2. Identificar y anotar los id reales de cada elemento listado en la tabla (empresa, sucursal, método de pago, productos de envío y fallback, cuenta contable).
  3. Reemplazar los valores de ejemplo dentro del nodo Payload Creator por los valores reales obtenidos.
  4. Ejecutar una prueba con un pedido de prueba antes de habilitar el flujo en producción.
Seguridad de credenciales: los tokens 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

Orden no pagada o no confirmada
Payload Creator retorna { stop: true, reason: ... } y la factura no se genera.
SKU inexistente o no numérico
Se factura el producto por defecto 84066 y se marca la descripción con alerta visible para corrección manual.
Sin documento de identidad
Se genera un identificador SHOP-<customer.id> que evita fallas en la creación del usuario.
Email duplicado en Goujana
Reintento automático colocando el email en 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_number como 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 OK al final del flujo para que la plataforma marque el webhook como procesado.
  • Manejo de impuestos: el array taxes está vacío. Si los precios incluyen IVA y Goujana debe discriminarlo, evaluar el mapeo de las líneas de impuestos del pedido.
Documentación técnica del flujo de integración de facturación electrónica con Goujana.



Descargar flujo N8N ejemplo

Whatsapp