Skip to content

Modulo MBA (ms-mba)

ms-mba — Contrato de integracion del microservicio de MBA3 / 4D

Section titled “ms-mba — Contrato de integracion del microservicio de MBA3 / 4D”

ms-mba es un microservicio NestJS 11 que actua como unica puerta de entrada entre NoviSuite y el ERP MBA3 (motor 4D v20) del cliente. Expone una capa HTTP estable, independientemente de como MBA3 responda por debajo (HTTP REST o TCP nativo).

Opera con dos backends complementarios hacia 4D:

BackendTransporteUso
Consulta Externa (preferido)HTTP REST multipart -> http://<mba>:8081/ws_Consulta_externa_MBA3/Todas las lecturas de catalogo, facturas, cobros, transferencias, clientes
MBA3 Web APIHTTP REST JSON -> http://<mba>:8081/mba3api/*Escrituras (alta/edicion de proveedores)
p4d proxy (legacy)Proxy Python 4D nativo por TCP 19812Health check profundo + controladores de retro-compatibilidad (legacy-compat, local-compat)
  • Traducir operaciones HTTP de NoviSuite en queries SQL-like de Consulta Externa o POST al MBA3 Web API.
  • Sincronizar nightly (22:00 - 22:50 hora Ecuador) los datos maestros hacia PostgreSQL local para lecturas rapidas offline.
  • Exponer endpoints de consulta paginados, con busqueda y filtros por fechas.
  • Cachear la sesion JWT de MBA3 con single-flight para evitar logins concurrentes.
  • Proveer health check y diagnostico profundo para depurar VPN / red / motor 4D.

Flujo objetivo: NoviSuite -> HTTP JSON -> ms-mba -> Consulta Externa multipart -> 4D -> JSON -> ms-mba -> NoviSuite, con fallback a p4d solo en controladores legacy.

  1. Dashboard hace GET /api/v1/mba/<recurso>?... con Bearer JWT.
  2. ms-mba consulta Postgres local (datos sincronizados la noche anterior).
  3. Si el endpoint termina en 4d/... o from-4d, consulta Consulta Externa en vivo.
  4. Respuesta paginada con { data, meta }.
  1. A las 22:00 hora Ecuador empieza la ventana de sync.
  2. SyncSchedulerService dispara 7 jobs cron separados cada 5 - 10 min.
  3. Cada *-sync.service.ts hace syncRecent(1) -> trae los registros del dia via Consulta Externa.
  4. Upsert en chunks de 200 filas a Postgres local (TypeORM orUpdate).
  1. Dashboard llama POST /api/v1/mba/providers con Bearer JWT.
  2. ProvidersService obtiene JWT de MBA3 (single-flight) y hace POST /mba3api/proveedores.
  3. Verifica la creacion via Consulta Externa (hasta 3 intentos con backoff).
  4. Responde con { status: 'verified' | 'not_found' | 'unavailable' }.
  • GET /api/v1/mba/invoices/4d/:code/claro-flow — consulta factura + lineas en vivo desde 4D.
  • GET /api/v1/mba/products/:id/with-stock — producto + stock actual en todas las bodegas.
RecursoValor
Puerto HTTP3001
Base de datosmba_service_development / mba_service_production (PostgreSQL)
RedisCache JWT auth interno (TTL 60 s)
Consulta Externa${MBA_WEB_API_BASE_URL}/ws_Consulta_externa_MBA3/
MBA3 Web API${MBA_WEB_API_BASE_URL}/mba3api/*
p4d proxyTCP 127.0.0.1:5000 -> MBA_API_SERVER:19812 (dentro del contenedor)
Rednetwork_mode: service:vpn-gateway — todo el trafico sale por el tunel OpenVPN del vpn-gateway
Zona horariaTZ=America/Guayaquil (critico para crons nightly)
Health checkGET /up (rapido) · GET /api/v1/mba/health/4d (profundo)
src/
├── app.controller.ts # /up, /api/v1/mba/health, /api/v1/mba/health/4d, /api/v1/mba/auth/*
├── app.module.ts
├── main.ts
├── consulta-externa/ # ← BACKEND PREFERIDO
│ ├── consulta-externa.service.ts # HTTP client + JWT single-flight
│ └── consulta-externa.module.ts
├── mba3-auth/ # Login JWT compartido para /mba3api/*
│ ├── mba3-auth.service.ts
│ └── mba3-auth.module.ts
├── mba-database/ # ← BACKEND LEGACY p4d
│ ├── mba-database.service.ts # Spawn Python + TCP 4D nativo
│ ├── proxy.py # Servidor local TCP 5000
│ └── p4d_legacy_bridge/
├── auth-client/ # Valida Bearer JWT contra ms-auth
│ ├── auth-client.service.ts
│ └── auth-client.module.ts
├── sync-scheduler/ # 7 crons nightly (22:00–22:50)
│ ├── sync-scheduler.service.ts
│ └── sync-scheduler.module.ts
├── warehouses/ # ✓ Consulta Externa
├── products/ # ✓ Consulta Externa
├── sellers/ # ✓ Consulta Externa
├── clients/ # ✓ Consulta Externa
├── invoices/ # ✓ Consulta Externa
├── payments/ # ✓ Consulta Externa
├── inventory-transfers/ # ✓ Consulta Externa
├── providers/ # ✓ Consulta Externa (read) + /mba3api (write)
├── legacy-compat/ # ! Endpoints viejos (sobre MbaDatabaseService)
├── local-compat/ # ! Endpoints locales (sobre MbaDatabaseService)
├── legacy-mba/ # ! Endpoints muy viejos
├── entities/ # TypeORM para Postgres local
│ ├── warehouse.entity.ts
│ ├── product.entity.ts
│ ├── seller.entity.ts
│ ├── client.entity.ts
│ ├── invoice.entity.ts
│ ├── payment.entity.ts
│ └── inventory-transfer.entity.ts
├── redis/
├── config/
├── database/migrations/
└── common/
├── guards/
├── filters/
└── decorators/
EsquemaHeaderUso
Bearer JWTAuthorization: Bearer <token>Dashboard (validado via ms-auth)
ServiceKeyx-service-key: <key>Sistemas internos / debug / cron triggers manuales
Legacy tokenAuthorization: <AUTH_TOKEN> o ?api_key=<AUTH_TOKEN>Controladores legacy-compat, local-compat, legacy-mba

Extrae el token, lo valida llamando a POST /api/internal/users/validate_token en ms-auth (con cache Redis de 60 s), y adjunta request.user = { id, email, roles, permissions }.

Para endpoints de compat: acepta cualquiera de los dos esquemas. Si el header es Bearer *, delega al AuthGuard; si es el token plano, lo compara contra AUTH_TOKEN del .env.

Aplicado manualmente en endpoints internos. Compara x-service-key contra SERVICE_KEY con comparacion timing-safe.

MetodoRutaAuthDescripcion
GET/upHealth rapido
GET/api/v1/mba/healthPing al p4d proxy
GET/api/v1/mba/health/4dDiagnostico profundo: TCP + proxy + query real
GET/api/v1/mba/auth/statusEstado del JWT cacheado de MBA3
POST/api/v1/mba/auth/refreshBearer JWT (admin)Fuerza re-login contra MBA3
MetodoRutaDescripcion
GET/api/v1/mba/warehousesListado desde Postgres local
GET/api/v1/mba/warehouses/:idDetalle
POST/api/v1/mba/warehousesCrear en MBA3 (/mba3api/bodegas)
PUT/api/v1/mba/warehouses/:idActualizar en MBA3
DELETE/api/v1/mba/warehouses/:idAnular en MBA3
POST/api/v1/mba/warehouses/sync?days=1Forzar sync inmediato
MetodoRutaDescripcion
GET/api/v1/mba/sellers?page=&limit=&search=Listado paginado
GET/api/v1/mba/sellers/:codeDetalle
POST/api/v1/mba/sellers/sync?days=1Sync manual
MetodoRutaDescripcion
GET/api/v1/mba/clients?page=&limit=&search=Listado paginado
GET/api/v1/mba/clients/search?q=...Busqueda por nombre/cedula/RUC
GET/api/v1/mba/clients/:codeDetalle
POST/api/v1/mba/clients/sync?days=1Sync manual
MetodoRutaDescripcion
GET/api/v1/mba/products?page=&limit=&search=Listado
GET/api/v1/mba/products/with-stockProductos + stock combinado
GET/api/v1/mba/products/stockSaldos
GET/api/v1/mba/products/movementsMovimientos de inventario
GET/api/v1/mba/products/:productIdDetalle
GET/api/v1/mba/products/:productId/with-stockDetalle + stock en vivo
POST/api/v1/mba/products/sync?days=1Sync manual
MetodoRutaDescripcion
GET/api/v1/mba/invoices?page=&limit=Listado desde Postgres local
GET/api/v1/mba/invoices/activeSolo no anuladas
GET/api/v1/mba/invoices/seller/:sellerIdPor vendedor
GET/api/v1/mba/invoices/status/active/:sellerIdActivas por vendedor
GET/api/v1/mba/invoices/date-range?start_date=&end_date=Por rango
GET/api/v1/mba/invoices/number/:numberPor numero de factura
GET/api/v1/mba/invoices/:codeDetalle
GET/api/v1/mba/invoices/:code/findBusqueda flexible
GET/api/v1/mba/invoices/:code/extendedCon lineas, cobros, cliente
GET/api/v1/mba/invoices/4d/:codeDetalle en vivo desde 4D
GET/api/v1/mba/invoices/4d/:code/claro-flowPayload listo para ms-recargas
POST/api/v1/mba/invoices/sync?days=1Sync manual
MetodoRutaDescripcion
GET/api/v1/mba/payments?page=&limit=&search=Listado
GET/api/v1/mba/payments/date-range?start_date=&end_date=Por rango
GET/api/v1/mba/payments/:paymentDetalle con cliente + metodos + detalle
POST/api/v1/mba/payments/sync?days=1Sync manual
MetodoRutaDescripcion
GET/api/v1/mba/inventories/transfers?page=&limit=&search=Listado
GET/api/v1/mba/inventories/transfers/confirmedSolo confirmadas
GET/api/v1/mba/inventories/transfers/date-rangePor rango
GET/api/v1/mba/inventories/transfers/:transferDetalle + productos movidos
POST/api/v1/mba/inventories/transfers/sync?days=1Sync manual
MetodoRutaDescripcion
POST/api/v1/mba/providersCrear proveedor (operacion=0) + verificar
PUT/api/v1/mba/providersActualizar (operacion=1) + verificar
POST/api/v1/mba/providers/verifySolo verificar

Respuesta tipica:

{
"success": true,
"operation": "create",
"payload": { "codigo_empresa": "NVC01", "nombre_proveedor": "...", "rfc_ruc_ci_proveedor": "1700000000" },
"upstream": { "respuesta": "OK" },
"verification": {
"status": "verified",
"codigo_proveedor": "PROV-001",
"matched_by": "tax_id",
"message": null
}
}

Los controladores legacy-compat (/mba/*), local-compat (/local-mba/*) y legacy-mba (/legacy/mba/*) exponen los mismos datos que los endpoints v1 pero con el shape antiguo. Se mantienen para integraciones legadas; internamente usan MbaDatabaseService (p4d) y no estan cubiertos por el sync nightly.

POST /login_Servicio HTTP/1.1
Content-Type: application/json
{ "codigo": "<MBA_WEB_API_CODIGO>", "pwd": "<MBA_WEB_API_PWD>" }

Respuesta: { "jwt": "eyJ...", ... } + Set-Cookie: session=....

POST /ws_Consulta_externa_MBA3/ HTTP/1.1
Content-Type: multipart/form-data; boundary=...
Authorization: eyJ...
Cookie: session=...
--boundary
Content-Disposition: form-data; name="select"
PRODUCT_ID,PRODUCT_NAME,DESCRIPTION,CORP,PRODUCT_TYPE
--boundary
Content-Disposition: form-data; name="from"
INVT_Ficha_Principal
--boundary
Content-Disposition: form-data; name="where"
CORP = 'NVC01' AND PRODUCT_ID LIKE 'REC%'
--boundary
Content-Disposition: form-data; name="orderBy"
PRODUCT_ID ASC
--boundary--

Respuesta: 200 OK con body JSON [{...}, {...}].

  • No soporta AS. Los renombrados se hacen en codigo con mapXxxRow().
  • No soporta parametros preparados (:param). Se usa toSqlString() que escapa comillas simples.
  • No soporta LIMIT/OFFSET SQL. El campo limit del multipart solo acota filas; para paginacion grande se trae todo y se corta en memoria.
  • Booleanos van como true/false literales: WHERE TRANSFERS = true.
  • Fechas van como strings ISO: WHERE FECHA_FACTURA = '2026-04-21'.

El JWT se cachea hasta 30 s antes de su exp. Si varias requests encuentran el token expirado, una sola dispara performLogin() y las demas comparten la promesa via pendingSession. Si MBA3 devuelve 401, solo se invalida el cache si el JWT que recibio el 401 sigue siendo el cacheado.

Hora (ECT)CronJobBackend
22:000 22 * * *warehouseSync.syncAll()Consulta Externa
22:055 22 * * *sellerSync.syncAll()Consulta Externa
22:1010 22 * * *clientSync.syncAll()Consulta Externa
22:2020 22 * * *productSync.syncAll()Consulta Externa
22:3030 22 * * *invoiceSync.syncRecent(1)Consulta Externa
22:4040 22 * * *paymentSync.syncRecent(1)Consulta Externa
22:5050 22 * * *transferSync.syncRecent(1)Consulta Externa

Cada job respeta un flag syncing (no overlap), trae filas del dia/rango, hace upsert en chunks de 200 con orUpdate y registra synced_from_4d=true + last_synced_at=now.

No hay reintentos automaticos por job fallido; se reintenta al dia siguiente. Para forzar manualmente: POST /api/v1/mba/<recurso>/sync?days=N.

VariableObligatoriaDefaultDescripcion
NODE_ENVsidevelopmentEn production desactiva synchronize + logging SQL
PORT3001Puerto HTTP
TZsiAmerica/GuayaquilCritico para crons nightly
DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAMEsiPostgres local
AUTO_DB_SYNCfalseAuto-sync schema TypeORM (solo dev)
AUTO_RUN_MIGRATIONStrueMigrations al boot
AUTH_SERVICE_URLsiURL de ms-auth
SERVICE_KEYsiLlave compartida ServiceKey
AUTH_TOKENsiToken legacy (compat controllers)
REDIS_URLsiredis://redis:6379Cache JWT interno
ALLOWED_ORIGINSsiCSV de origenes CORS
THROTTLE_TTL / THROTTLE_LIMIT60000 / 120Rate limit
MBA_WEB_API_BASE_URLsihttp://192.168.80.190:8081Base de MBA3
MBA_WEB_API_LOGIN_PATH/login_ServicioPath de login
MBA_CONSULTA_EXTERNA_PATH/ws_Consulta_externa_MBA3/Path de queries
MBA_WEB_API_CODIGOsiUsuario MBA3
MBA_WEB_API_PWDsiPassword MBA3
MBA_WEB_API_TIMEOUT30 (seg)Timeout HTTP Consulta Externa
MBA_API_SERVER / MBA_API_SERVER_PORT4D nativo (p4d proxy legacy)
MBA_API_USER / MBA_API_PASSWORDAPI/APICredenciales p4d
MBA_QUERY_TIMEOUT_MS5000Timeout p4d por query
MBA_QUERY_MAX_ATTEMPTS1Reintentos p4d
MBA_MAX_IN_FLIGHT_QUERIES2Concurrencia p4d
MBA_CIRCUIT_BREAK_MS10000Circuit-breaker p4d
MBA_PROXY_*Tunning proxy Python
MBA_PROVIDERS_API_PATH/mba3api/proveedoresPath escritura proveedores
MBA_PROVIDER_OPERATION_CREATE0Codigo operacion crear
MBA_PROVIDER_OPERATION_UPDATE1Codigo operacion actualizar
  • ms-mba corre con network_mode: service:vpn-gateway -> todo el trafico sale por el tunel OpenVPN.
  • El vpn-gateway hace DNAT del puerto 3001 para que el resto de MS llegue por http://vpn-gateway:3001.
  • La IP publica del tunel debe estar en la whitelist de MBA3. Si recibes 003 - IP No Autorizada, el guard de 4D rechazo.
  • JWT de MBA3 de 8 h; cache expira 30 s antes del exp.
EntidadTablaPKContiene
WarehousewarehousescodeBodegas
SellersellerscodeVendedores (VE*)
Clientclientscodigo_clienteFichas de cliente
Productproductsproduct_id + corpCatalogo
Invoiceinvoicescodigo_facturaCabecera de facturas
Paymentpaymentscodigo_cobroCabecera de cobros
InventoryTransferinventory_transfersdoc_idTransferencias entre bodegas

Comunes: synced_from_4d boolean, last_synced_at timestamp, created_at, updated_at.

Lineas de factura / metodos de cobro / productos de transferencia no se sincronizan; se cargan en vivo desde Consulta Externa en el detalle.

GET /api/v1/mba/health/4d:

{
"status": "ok | degraded | down",
"checks": {
"tcp": { "ok": true, "latency_ms": 4 },
"proxy": { "ok": true, "pid": 42 },
"query": { "ok": true, "rows": 1, "latency_ms": 18 }
},
"diagnostic": "Todo OK | Proxy no respondio | VPN caida"
}

Distingue:

  • VPN caida: tcp falla -> revisar vpn-gateway.
  • 4D detenido: tcp OK pero proxy falla.
  • Query lenta: todo OK pero query.latency_ms > 2000 -> saturacion.
CodigoSignificadoCausa tipica
401JWT invalido/expiradoToken del dashboard caduco
403Permisos insuficientes o 003 de MBA3IP no whitelisteada
404Registro no existe
502BadGatewayExceptionMBA3 devolvio error HTTP o cuerpo invalido
504GatewayTimeoutExceptionConsulta Externa no respondio en MBA_WEB_API_TIMEOUTs
ModuloBackendEstado
warehousesConsulta ExternaOK
productsConsulta ExternaOK
sellersConsulta ExternaOK
clientsConsulta ExternaOK
invoicesConsulta ExternaOK
paymentsConsulta ExternaOK
inventory-transfersConsulta ExternaOK
providers (read)Consulta ExternaOK
providers (write)MBA3 /mba3api/proveedoresOK (no aplica Consulta Externa)
app.controller healthp4d (MbaDatabaseService)legacy
legacy-compat / local-compat / legacy-mbap4dretro-compatibilidad

El p4d proxy (mba-database/) sigue activo solo para diagnostico profundo y controladores de compat.

  • HTTP client: services/ms-mba/src/consulta-externa/consulta-externa.service.ts
  • Orquestador nightly: services/ms-mba/src/sync-scheduler/sync-scheduler.service.ts
  • Escritura proveedores: services/ms-mba/src/providers/providers.service.ts
  • Compose produccion: docker-compose.yml — bloques ms-mba + vpn-gateway
  • Diagrama tablas 4D: schema_4d_invoices_tables.md