nexusflex-mcp 3.70.0 → 3.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api.mjs CHANGED
@@ -47,8 +47,19 @@ if (EMAIL && PASSWORD && !/^https:\/\//i.test(API_URL)) {
47
47
  log("ADVERTENCIA: NEXUSFLEX_API_URL no es HTTPS y hay email/contraseña — viajarían sin cifrar.");
48
48
  }
49
49
 
50
- function guard(path) {
50
+ // Operaciones habilitadas dentro de rutas financieras (decisión del dueño, 29/09), con su
51
+ // MÉTODO exacto — mismas que RUTAS_MCP_OPERACION_OK en backend/src/middleware/auth.ts.
52
+ // Ninguna paga, cobra ni transfiere: excluir/reincluir un envío de una liquidación (con
53
+ // motivo) y ver/preparar los datos de facturación de un cliente (no emite comprobantes).
54
+ const OPERACIONES_OK = [
55
+ { metodo: "POST", ruta: /^\/liquidaciones\/anteriores\/\d+\/(excluir|reincluir)\/?$/i },
56
+ { metodo: "GET", ruta: /^\/afip\/estado\/?$/i },
57
+ { metodo: "POST", ruta: /^\/afip\/preparar-cliente\/?$/i },
58
+ ];
59
+
60
+ function guard(method, path) {
51
61
  const clean = path.split("?")[0];
62
+ if (OPERACIONES_OK.some((o) => o.metodo === String(method).toUpperCase() && o.ruta.test(clean))) return;
52
63
  if (RUTAS_PROHIBIDAS.some((re) => re.test(clean))) {
53
64
  throw new Error(`Ruta bloqueada por política del MCP (endpoints de dinero deshabilitados): ${clean}`);
54
65
  }
@@ -96,7 +107,7 @@ async function ensureToken() {
96
107
 
97
108
  /** Llamada autenticada a la API. Reintenta UNA vez si el token venció/se revocó. */
98
109
  export async function api(method, path, body) {
99
- guard(path);
110
+ guard(method, path);
100
111
  let token = await ensureToken();
101
112
  const doFetch = (t) =>
102
113
  fetch(`${API_URL}${path}`, {
package/docs.mjs CHANGED
@@ -158,7 +158,7 @@ const GROUPS = [
158
158
  { titulo: "WMS del nodo", tools: ["stock_nodo", "productos_nodo", "producto_crear"] },
159
159
  { titulo: "Gesti\xF3n del nodo", tools: ["clientes_del_nodo", "cliente_crear", "cliente_editar", "sucursales_cliente", "sucursal_perfil", "precios_ver", "precio_actualizar", "cuentas_vinculadas", "generar_enlace_vinculacion", "facturacion_estado", "facturacion_preparar_cliente"] },
160
160
  { titulo: "Marketing / atribuci\xF3n", tools: ["marketing_config_ver", "marketing_config_guardar"] },
161
- { titulo: "Liquidaciones (consulta)", tools: ["liquidacion_buscar", "liquidacion_detalle", "liquidaciones_sin_recibir", "liquidacion_excluir_envio", "liquidacion_reincluir_envio", "cuenta_semanal_nodos"] },
161
+ { titulo: "Liquidaciones", tools: ["liquidacion_buscar", "liquidacion_detalle", "liquidaciones_sin_recibir", "liquidacion_excluir_envio", "liquidacion_reincluir_envio", "cuenta_semanal_nodos"] },
162
162
  { titulo: "Usuarios / choferes", tools: ["chofer_listar", "chofer_crear", "chofer_editar", "usuario_editar", "operador_crear", "cliente_generar_usuario", "cliente_resetear_clave", "usuario_habilitar_reparto"] },
163
163
  { titulo: "Administraci\xF3n (red)", tools: ["nodos_listar", "nodo_crear", "usuario_habilitar_rol", "grupo_crear", "logo_subir", "sugerencias_listar", "cierre_semanal_links", "nodo_renombrar", "grupo_miembros", "grupo_sumar_nodo", "grupo_expulsar_nodo", "grupo_admin_permiso"] }
164
164
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexusflex-mcp",
3
- "version": "3.70.0",
3
+ "version": "3.71.0",
4
4
  "description": "MCP de Nexus Flex: operá tu nodo/cuenta desde un asistente de IA (altas de clientes, stock, KPIs). Login por autorización web (device-flow). NO toca dinero.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/server.mjs CHANGED
@@ -56,8 +56,9 @@ const ALLOW_PRECIOS = truthy(process.env.NEXUSFLEX_MCP_ALLOW_PRECIOS);
56
56
 
57
57
  // ATADO CON: backend/src/services/mcp-remote.ts (MCP_VERSION + NOVEDADES + mismos tools, salvo SOLO_REMOTO)
58
58
  // y mcp/package.json. Lo verifica backend/src/coherencia.test.ts. Ver CLAUDE.md → "Cosas que van juntas".
59
- const MCP_VERSION = "3.70.0"; // bumpear junto con package.json + backend/services/mcp-remote.ts
59
+ const MCP_VERSION = "3.71.0"; // bumpear junto con package.json + backend/services/mcp-remote.ts
60
60
  const NOVEDADES = [
61
+ "3.71.0 — Habilitadas por el dueño: `liquidacion_excluir_envio` / `liquidacion_reincluir_envio` (sacar o devolver UN envío del cobro de una liquidación emitida, con motivo obligatorio) y `facturacion_estado` / `facturacion_preparar_cliente` (qué falta para facturar y cargar los datos fiscales de un cliente) ya funcionan por MCP: el filtro de dinero las deja pasar con su método exacto. Siguen sin pagar, cobrar ni emitir comprobantes, y piden permiso finanzas. Además `mis_envios` ahora sí filtra por `estado`.",
61
62
  "3.70.0 — Descripciones al día: textos de las herramientas corregidos para que digan lo que hacen hoy (`envio_entregar`, `envio_asignar_mensajero`, `generar_enlace_vinculacion` vence en 48 hs, `grupo_miembros` y `provisorio_conciliar` apuntan a `grupos_tarifas`), `flujo` lista todos los flujos disponibles, `sugerencias_listar` solo para el superadmin, `envio_cargar` exige `telefono`, parámetros con formato (fechas YYYY-MM-DD, montos en ARS, nombre o id) y las instrucciones del conector más cortas (la guía sigue en `guia`). `liquidacion_excluir_envio`/`reincluir` avisan que hoy el filtro de dinero los bloquea por MCP (se hace desde la PWA).",
62
63
  "3.69.1 — AYUDA completa: `ayuda` ahora tiene la ficha (qué hace, cómo usarlo, ejemplo, qué NO hace) de los 20 tools que no la tenían (cierre semanal, zonas de grupo, tarifas de grupo, sin vendedor, corregir estado, pago al cadete, retiros…) y los 26 que no aparecían en el índice. La ayuda del paquete npm se genera desde la del conector, así que ya no se desincronizan. No mueve dinero.",
63
64
  "3.69.0 — Control por foto de la TANDA DE UN CADETE (propios + de otros nodos mezclados): en `envio_desde_etiqueta_ml` alcanza con el `mlQr` crudo — de ahí sale el número de ML y el vendedor, y el vendedor se reconoce igual que en el escáner (cuenta vinculada O cuenta aprendida en juntadas/escaneos; antes solo la vinculada). `nodoEntrega` ya no necesita `grupo`: si el cliente es del mismo nodo que entrega es un paquete propio (sin traspaso) y si es de otro nodo se usa el grupo que comparten. Si no conoce al vendedor, contesta 404 con el senderId para que preguntes de qué nodo/cliente es. Si el envío ya existía, no lo duplica: lo completa y lo avanza. No mueve dinero.",
@@ -254,7 +255,7 @@ if (isCliente) {
254
255
  tool("mis_envios", {
255
256
  title: "Mis envíos",
256
257
  description: "Tus envíos/paquetes (solo los tuyos), los 300 más recientes, cada uno con su `estado`. No incluye datos de otros clientes ni del nodo.",
257
- inputSchema: { estado: z.string().optional().describe("Estado: 'A retirar', 'Colectado', 'En centro de distribución', 'En camino', 'Entregado' (o una novedad, ej. 'Comprador ausente'). Ojo: hoy el backend no aplica este filtro y devuelve todos; filtrá vos por el campo `estado` de cada envío.") },
258
+ inputSchema: { estado: z.string().optional().describe("Estado: 'A retirar', 'Colectado', 'En centro de distribución', 'En camino', 'Entregado' (o una novedad, ej. 'Comprador ausente'). Filtra por los que EMPIEZAN con ese texto ('Entregado' incluye 'Entregado (Flex)'); los 300 más recientes de ese estado.") },
258
259
  }, async ({ estado }) => run(() => api("GET", `/portal/envios${q({ estado })}`)));
259
260
 
260
261
  tool("mis_kpis", {
@@ -1192,7 +1193,7 @@ if (ALLOW_WRITE) {
1192
1193
  tool("liquidacion_excluir_envio", {
1193
1194
  title: "No cobrar un envío de una liquidación",
1194
1195
  description:
1195
- "Saca UN envío (por tracking) del cobro de una liquidación YA emitida y re-suma el total, ajustando el cargo en la cuenta corriente del cliente. El `motivo` es OBLIGATORIO: queda en el historial del envío y el vendedor lo ve en su portal. Si esa liquidación ya está en una factura de ARCA emitida, lo rechaza (haría falta una nota de crédito, que el sistema no emite). Scopeada a tu nodo. Hoy el filtro de dinero del backend bloquea esta ruta vía MCP (403): se hace desde la PWA.",
1196
+ "Saca UN envío (por tracking) del cobro de una liquidación YA emitida y re-suma el total, ajustando el cargo en la cuenta corriente del cliente. El `motivo` es OBLIGATORIO: queda en el historial del envío y el vendedor lo ve en su portal. Si esa liquidación ya está en una factura de ARCA emitida, lo rechaza (haría falta una nota de crédito, que el sistema no emite). Scopeada a tu nodo.",
1196
1197
  inputSchema: {
1197
1198
  id: z.number().int().positive().describe("id de la liquidación"),
1198
1199
  tracking: z.string().min(1),
@@ -1202,7 +1203,7 @@ if (ALLOW_WRITE) {
1202
1203
  tool("liquidacion_reincluir_envio", {
1203
1204
  title: "Volver a cobrar un envío de una liquidación",
1204
1205
  description:
1205
- "Lo inverso de `liquidacion_excluir_envio`: devuelve al cobro un envío que se había excluido, re-suma y ajusta la cuenta corriente. El `motivo` es OBLIGATORIO. Mismo guard de factura emitida. Hoy el filtro de dinero del backend bloquea esta ruta vía MCP (403): se hace desde la PWA.",
1206
+ "Lo inverso de `liquidacion_excluir_envio`: devuelve al cobro un envío que se había excluido, re-suma y ajusta la cuenta corriente. El `motivo` es OBLIGATORIO. Mismo guard de factura emitida.",
1206
1207
  inputSchema: {
1207
1208
  id: z.number().int().positive().describe("id de la liquidación"),
1208
1209
  tracking: z.string().min(1),