← Volver al catálogo

🚨 Vigilante de Envíos 17h

Archivo: /Users/user/rifai-agents/agentes/sec/vigilante-envios.ts · Plist: com.rifai.vigilante-envios · Horario: cada día a las 17:00 Madrid (StartCalendarInterval Hour 17, Minute 0). El script vuelve a comprobar que la hora de Madrid sea 17 salvo FORCE=1.

Qué hace

Cada día a las 17:00 lee en Shopify los pedidos creados desde la fecha de arranque (pizarra limpia desde 2026-06-04) y los clasifica por estado de envío: incidencias, sin enviar (+5d / 3-5d / 1-2d / hoy), en tránsito (estancados +7d / normales) y entregados hoy. Con eso compone un informe HTML y lo manda por Telegram. Pese a ser un agente del depto Secretario, el informe se envía al bot de Oscar (ops) porque los envíos son logística, no al bot de Sec.

Cómo funciona

1. Parsea .env y calcula la hora de Madrid. Gate: si no es FORCE=1 y la hora no es 17, sale.

2. Pide a Shopify orders.json?status=any&created_at_min=<CONTAR_DESDE>&limit=250 con los campos de fulfillment/tracking/cliente.

3. Para cada pedido (descartando cancelados, refunded y voided) calcula la antigüedad en días y extrae el tracking del primer fulfillment.

4. Clasifica con la lógica del nodo original:

  • deliveredToday → entregadosHoy; delivered (no hoy) → se ignora.
  • attempted_delivery/failure → incidencias.
  • unfulfilled/partial/sin estado → sinEnviar según edad (≥5 / ≥3 / ≥1 / hoy).
  • fulfilled con tracking → enTránsito; estancado si los días desde la última actualización del tracking ≥7, si no normal.

5. Ordena cada cubo por antigüedad/días en tránsito descendente.

6. Construye el mensaje HTML con secciones (solo las no vacías), formateando cada pedido (nombre, total, cliente, ciudad, edad y, donde aplica, número/empresa/estado de tracking) y añade el resumen "Total activos / entregados hoy". Si no hay nada: "Todo al día".

7. sendTelegram trocea el mensaje en partes ≤3900 caracteres (cortando por salto de línea) y las envía con parse_mode: HTML al bot de ops.

Datos/APIs

  • Shopify Admin API (2024-10): orders.json con status=any y created_at_min. Vars: SHOPIFY_STORE, SHOPIFY_ACCESS_TOKEN.
  • Telegram Bot API (bot de Oscar / ops): sendMessage con parse_mode: HTML, multi-parte. Vars: TELEGRAM_OPS_TOKEN, TELEGRAM_CHAT_ID.
  • Nota: envía con fetch directo a Telegram (no usa notify-router.ts).

Cómo probarlo

cd /Users/user/rifai-agents && FORCE=1 npx tsx agentes/sec/vigilante-envios.ts

FORCE=1 salta el gate de las 17:00. Esperado: log con la hora de Madrid, y "Informe enviado a Oscar. Activos: N, entregados hoy: M", más el informe en el bot de ops. Si no hay pedidos activos, el mensaje será "Todo al día." Para revisar el texto sin enviar a producción, ejecutar fuera de la franja sin FORCE saldrá antes ("Fuera de ventana 17:00").

Si se rompe / recuperar

Recargar el plist:

launchctl unload ~/Library/LaunchAgents/com.rifai.vigilante-envios.plist
launchctl load   ~/Library/LaunchAgents/com.rifai.vigilante-envios.plist

Logs: /Users/user/rifai-agents/logs/vigilante-envios.log. Causas típicas: SHOPIFY_ACCESS_TOKEN caducado o sin scope de orders, TELEGRAM_OPS_TOKEN incorrecto, o cambio en la estructura de fulfillments/shipment_status de Shopify.

Cómo replicarlo

  • .env con SHOPIFY_STORE, SHOPIFY_ACCESS_TOKEN, TELEGRAM_OPS_TOKEN, TELEGRAM_CHAT_ID.
  • App Shopify con permiso de lectura de pedidos.
  • Gate horario (17:00 Madrid, override FORCE=1).
  • Consulta orders.json con created_at_min y la lógica de clasificación por fulfillment_status + shipment_status + antigüedad/días en tránsito.
  • Formateo HTML por secciones + envío multi-parte (≤3900) al bot de ops.
  • Plist launchd con StartCalendarInterval a las 17:00 que ejecute npx tsx del script.