Flujos ERP → WMS
Sincronización de datos desde Tango (SQL Server) hacia el WMS (API HTTP).
Diagrama General
flowchart LR
subgraph Tango["Tango (SQL Server)"]
GVA18[GVA18<br/>Provincias]
GVA05[GVA05<br/>Zonas]
WEBCLI[WEBCLIENTE<br/>Clientes]
WEBVIEW[WEBVIEW<br/>Artículos]
WMS_PED[WMS_Pedidos<br/>Pedidos]
WMS_OC[WMS_OC_pendientes<br/>OC]
end
subgraph Middleware["Sync Engine"]
POLL[Poller]
TRANS[Transforms]
QUEUE[Queue]
end
subgraph WMS["WMS API"]
PROV[/provincias/]
ZON[/zonas/]
CLI[/clientes/]
ART[/articulos/]
PED[/pedidos/]
OC[/ordenesDeCompra/]
end
GVA18 --> POLL
GVA05 --> POLL
WEBCLI --> POLL
WEBVIEW --> POLL
WMS_PED --> POLL
WMS_OC --> POLL
POLL --> TRANS
TRANS --> QUEUE
QUEUE --> PROV
QUEUE --> ZON
QUEUE --> CLI
QUEUE --> ART
QUEUE --> PED
QUEUE --> OC
Flujo de Datos
1. Tablas Maestras
Datos que cambian muy poco. Se sincronizan cada hora.
flowchart LR
A[(GVA18)] -->|SELECT *| B[Poller]
B -->|POST/PATCH| C[/provincias/]
style A fill:#f9f,stroke:#333
style C fill:#9f9,stroke:#333
| Entity | Tabla Tango | Endpoint WMS | Intervalo |
|---|---|---|---|
| provincias | GVA18 | /provincias | 1h |
| zonas | GVA05 | /zonas | 1h |
| transportes | GVA24 | /transportes | 1h |
| depositos | STA22 | /depositos | 1h |
| categorias | (estático) | /categorias | 24h |
2. Clientes y Proveedores
Cambios moderados. Se sincronizan cada 5 minutos.
// Flow clientes
{
name: 'clientes',
source: { adapter: 'tango' },
destinations: ['wms', 'mysql-web', 'mysql-development'], // Múltiples destinos
pollInterval: 5 * 60 * 1000,
priority: 'normal',
alerts: {
onJobFailed: [
// Alerta solo cuando falla el sync al WMS
{ type: 'email', to: ['ops@empresa.com'], destinations: ['wms'] },
],
},
}
Mapeo de campos (destino WMS):
| Campo WMS | Campo Tango | Descripción |
|---|---|---|
| codigo | Cod Cliente | Código único |
| nombre | Nombre | Razón social |
| cuit | CUIT | CUIT/CUIL |
| direccion | Direccion | Domicilio |
| codigoProvincia | Cod Provincia | FK a provincias |
| codigoZona | Cod Zona | FK a zonas |
Destino MySQL Web — multi-tabla: la misma fila de WEBCLIENTE se materializa como 3 escrituras transaccionales:
flowchart LR
A[(WEBCLIENTE<br/>Tango)] -->|clientesMysql| B[Row con _vend_*]
B -->|TX| C1[REG_CUENTA<br/>subsistema=02<br/>cliente]
B -->|TX| C2[REG_CUENTA<br/>subsistema=22<br/>vendedor]
C1 -->|SELECT id_regcuenta| D[REG_CUENTA_RELACIONES]
C2 -->|SELECT id_regcuenta| D
El transform clientesMysql valida que el cliente tenga vendedor asignado; si no, el job falla y dispara la alerta. Ver Operaciones Múltiples para la configuración completa.
3. Artículos
Cambios frecuentes. Se sincronizan cada minuto.
flowchart TD
A[(WEBVIEW<br/>35,000 rows)] -->|SELECT *| B[Poller]
B -->|Hash compare| C{¿Cambió?}
C -->|No| D[Skip]
C -->|Sí| E[Job Queue]
E --> F[WMS /articulos]
E --> G[MySQL productos]
Mapeo de campos (artículos):
| Campo WMS | Campo Tango |
|---|---|
| codigo | CODIGO |
| nombre | DESCRIPCION |
| codigoCategoria | COD_CATEGORIA |
| codigoProveedor | COD_PROVEE |
| stockActual | STOCK |
| precioLista | PRECIO_LISTA_1 |
4. Pedidos
Datos críticos. Se sincronizan cada 30 segundos con agrupación.
flowchart TD
A[(WMS_Pedidos<br/>Líneas)] -->|SELECT *| B[Poller]
B -->|agruparPedidos| C[Transform]
C -->|Por Nro. Pedido| D[Pedidos agrupados]
D --> E{¿Cambió hash?}
E -->|Sí| F[Job Queue]
F -->|POST/PATCH| G[WMS /pedidos]
Transform agruparPedidos:
// Input: líneas planas
[
{ "Nro. Pedido": "001", "Cod Articulo": "A1", Cantidad: 10 },
{ "Nro. Pedido": "001", "Cod Articulo": "A2", Cantidad: 5 },
]
// Output: pedidos con detalles
[
{
"_pk": "001",
"idERP": "001",
"numero": "0000000001",
"codigoCliente": "CLI001",
"fecha": "2025-01-08 10:30:00",
"detalles": [
{ "codigoArticulo": "A1", "cantidadSolicitada": 10 },
{ "codigoArticulo": "A2", "cantidadSolicitada": 5 },
]
}
]
5. Órdenes de Compra
Similar a pedidos, con agrupación.
{
name: 'ordenesDeCompra',
source: { adapter: 'tango' },
destinations: ['wms'],
pollInterval: 60 * 1000,
priority: 'high',
transform: 'agruparOrdenesCompra',
}
HTTP Adapter - Lógica de Upsert
El adapter WMS intenta POST, si da 409 hace PATCH:
sequenceDiagram
participant Queue
participant Adapter
participant WMS
Queue->>Adapter: Job (articulo ART001)
Adapter->>WMS: POST /articulos
alt Artículo nuevo
WMS-->>Adapter: 201 Created
Adapter-->>Queue: Success
else Ya existe
WMS-->>Adapter: 409 Conflict
Adapter->>WMS: PATCH /articulos/ART001
WMS-->>Adapter: 200 OK
Adapter-->>Queue: Success
end
Configuración del Source
// src/config/sources/tango.ts
export const tangoSource: MssqlSourceConfig = {
name: 'tango',
type: 'mssql-source',
config: {
server: process.env.MSSQL_SERVER,
database: process.env.MSSQL_DATABASE,
// ...
},
entities: {
articulos: {
table: 'WEBVIEW',
primaryKey: ['CODIGO'],
},
clientes: {
table: 'WEBCLIENTE',
primaryKey: ['Cod Cliente'],
},
pedidos: {
table: 'WMS_Pedidos',
primaryKey: ['Nro. Pedido'],
},
proveedores: {
table: 'CPA01',
condition: 'HABILITADO = 1', // Solo activos
primaryKey: ['COD_PROVEE'],
},
},
};
Configuración del Destination
// src/config/destinations/wms.ts
export const wmsAdapter: HttpAdapterConfig = {
name: 'wms',
type: 'http',
config: {
baseUrl: process.env.WMS_API_URL,
headers: {
'X-API-KEY': process.env.WMS_API_KEY,
},
},
entities: {
articulos: {
endpoint: 'articulos',
keyField: 'codigo',
fields: {
codigo: 'CODIGO',
nombre: 'DESCRIPCION',
// ...
},
},
pedidos: {
endpoint: 'pedidos',
keyField: 'idERP',
fields: {
idERP: 'idERP',
numero: 'numero',
// ... (viene del transform)
},
},
},
};
Manejo de Errores
Error de Conexión
flowchart TD
A[Job falla] --> B{¿Error de red?}
B -->|Sí| C[Retry con backoff]
C --> D{¿Intentos < 5?}
D -->|Sí| E[Esperar 5s, 10s, 20s...]
E --> F[Reintentar]
D -->|No| G[Fallo permanente]
B -->|No| H{¿Error 4xx?}
H -->|400 Bad Request| I[Loggear y fallar]
H -->|409 Conflict| J[Intentar PATCH]
Logs de Error
{
"level": "error",
"entity": "articulos",
"adapter": "wms",
"pk": "ART001",
"status": 400,
"responseBody": { "error": "Campo requerido faltante" },
"requestBody": { "codigo": "ART001" },
"msg": "HTTP request failed"
}
Monitoreo
Ver en el dashboard:
- Flows activos: Estado de cada flow
- Jobs en cola: Pendientes, activos, fallidos
- Métricas: Duración promedio, P95, errores
- Bull Board: Detalle de jobs individuales