Files
georgeandClaude Sonnet 5.5 67a80e18db DP_Stock v3: sin COALESCE ni subconsultas (el analizador del Service Layer no los admite)
Suma OpenInvQty con JOIN + GROUP BY. Sin consignación no hay fila, y la nueva consulta
DP_Articulo distingue artículo existente (0) de inexistente.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 15:50:58 -05:00
..

API — Devolución a Proveedores

Backend en NestJS 12 (ESM) de la aplicación Devolución a Proveedores para SAP Business One. No tiene base de datos propia: habla con el Service Layer de SAP B1 en nombre del usuario que inició sesión, y guarda cada ejecución en el UDO LIB_ODEV.

La documentación general del proyecto (decisiones, flujo, estado) está en ../../CLAUDE.md. Este archivo cubre solo cómo ejecutar y mantener la API.

Requisitos

  • Node 22 LTS o superior.
  • Acceso de red al Service Layer de SAP B1 (por defecto https://servidor:50000/b1s/v1).
  • Red con Fortinet (inspección SSL): exportar NODE_OPTIONS=--use-system-ca (o NODE_EXTRA_CA_CERTS) antes de usar npm.

Puesta en marcha

Desde la raíz del monorepo (devolucion-proveedores-web/):

npm install
cp apps/api/.env.example apps/api/.env   # y completar los valores
npm run dev:api                          # compila @dp/shared y levanta la API en :3000

Variables de .env

Variable Descripción
PORT Puerto de la API (3000).
WEB_ORIGIN Origen del frontend para CORS. En desarrollo ng serve usa proxy y no hace falta.
SL_URL URL del Service Layer, con /b1s/v1 al final.
SL_COMPANY_DB Base de la sociedad (CompanyDB del Login).
SL_REJECT_UNAUTHORIZED false si el Service Layer usa un certificado autofirmado.
DB_TYPE HANA (producción) o MSSQL (pruebas). Elige la variante de cada consulta SQL.
COOKIE_SECURE true solo cuando la API se publica por HTTPS.
HTTPS_PFX_PATH / HTTPS_PFX_PASSPHRASE Solo producción: certificado .pfx y su clave. La API escucha por HTTPS.
HTTPS_KEY_PATH / HTTPS_CERT_PATH Alternativa al .pfx: clave privada y certificado en PEM (no mezclar con el .pfx).
HTTP_REDIRECT_PORT Con HTTPS: puerto HTTP que redirige (301) al HTTPS, normalmente 80.
WEB_DIST_DIR Carpeta con la web compilada. Por defecto apps/web/dist/web/browser si existe.

El usuario y la contraseña de SAP no se configuran aquí: se escriben en la pantalla de login y se usan para el Login del Service Layer. La API reinicia sin conservar sesiones.

Scripts

Se ejecutan con npm run <script> -w api desde la raíz, o directamente desde apps/api.

Script Qué hace
start:dev Modo watch (recompila y reinicia; se pierden las sesiones en cada reinicio).
build / start:prod Compila a dist/ y ejecuta node dist/main.
test Tests unitarios (Vitest).
test:e2e Tests e2e (test/).
test:cov Cobertura.
lint oxlint --type-aware src/ test/.

Endpoints (prefijo /api)

Todos exigen sesión (cookie dp_sid) salvo /health, /auth/info, /auth/login y /auth/logout.

Área Rutas
Salud y sesión GET /health · GET /auth/info · POST /auth/login · POST /auth/logout · GET /auth/me
Metadatos GET /metadata/status · POST /metadata/rebuild
Catálogos GET /catalogos · GET /catalogos/almacenes
Planificaciones GET /planificaciones (paginado, con filtros) · GET /planificaciones/abierta · GET /planificaciones/:id
POST /planificaciones/pegar · POST /planificaciones · PATCH /planificaciones/:id/cabecera · PATCH /planificaciones/:id/lineas/:lineId
POST /planificaciones/:id/devoluciones · POST /planificaciones/:id/reprocesar · POST /planificaciones/:id/cerrar
PDF POST /planificaciones/:id/pdf

El detalle de cada ruta (parámetros y reglas) está en la tabla de CLAUDE.md. Ejemplo del listado: GET /api/planificaciones?status=C&whsCode=01&desde=2026-10-01&pagina=2&tamano=20.

Producción

En producción la API sirve también la web compilada (si existe apps/web/dist/web/browser): todo queda en el mismo origen y en un solo puerto. Las rutas de Angular (sin extensión y fuera de /api) devuelven index.html; los archivos con hash se cachean un año; se agregan cabeceras de seguridad (y HSTS con HTTPS).

npm run publicar          # desde la raíz: arma release/devolucion-proveedores/

Instalación en Windows (servicio con NSSM, HTTPS, firewall, actualizaciones): ../../deploy/windows/DEPLOY.md.

Logs: la API no escribe archivos; usa el Logger de Nest por consola. Como servicio, NSSM captura esa salida y la rota. Con NO_COLOR=1 el log sale sin códigos de color.

Estructura

src/
├── config/            lectura y validación del .env
├── service-layer/     ServiceLayerClient (axios) y SessionStore (en memoria)
├── auth/              login/logout/me, SessionGuard global y @Public()
├── sql-queries/       consultas guardadas (SQLQueries) con variantes HANA y MSSQL
├── catalogos/         almacenes, series y valores válidos de los UDF
├── planificaciones/   FIFO, UDO LIB_ODEV, Devoluciones, reprocesar y listado
├── pdf/               SOAP de BES (Consulta_TXTDTE) y unión de PDF
├── metadata/          definiciones JSON de tablas/campos/UDO y su reconstrucción
├── health/
├── http-exception.logger.ts   registra en el log todo error 4xx/5xx
├── web-estatico.ts            sirve la web compilada, fallback a index.html y cabeceras de seguridad
└── https.ts                   lee el certificado y redirige HTTP → HTTPS

La lógica de dominio pura (FIFO, consolidación por proveedor, parseo del texto de Excel) vive en libs/shared (@dp/shared), que se consume compilada (dist/): tras cambiarla, npm run build:shared.

Cosas que conviene saber

  • Una sesión del Service Layer no admite peticiones simultáneas: las procesa en serie y cada una espera unos 7 s. ServiceLayerClient.request las encola por sesión; no uses otro cliente HTTP para hablar con SAP. Una petición que tarde más de 2 s queda avisada en el log.
  • Consultas SQL: se guardan en SAP como SQLQueries (DP_Stock, DP_EntradasAbiertas) y la API las crea o actualiza sola. SAP reescribe el SQL al guardarlo, por lo que al modificar una consulta hay que subir su version en sql-queries/sql-queries.definitions.ts. El analizador SQL no admite funciones como FORMAT; los parámetros van entre comillas simples.
  • Credenciales del web service DTE (@DTE_CONFC): se leen en cada descarga de PDF, no se registran en el log y no se devuelven al navegador.
  • Metadatos: la fuente de verdad son los JSON de src/metadata/definitions/. Reconstruir crea lo que falta; borrar y recrear un campo solo ocurre con autorización explícita.
  • Los tipos que aparecen en firmas con decoradores se importan con import type (por isolatedModules + emitDecoratorMetadata); los DTO, que son clases, se importan como valor.
  • HANA: las variantes HANA de las consultas ya se probaron contra el Service Layer de HANA y funcionan. Falta confirmar el paginado del listado y los tipos de los metadatos.

Diagnóstico rápido

Síntoma Causa probable
No se pudo conectar con el Service Layer (EHOSTUNREACH) Proceso de la API con un estado de red viejo (cambio de red o VPN). Reiniciarla.
401 Debe iniciar sesión tras tocar el código La API se reinició y perdió las sesiones. Volver a iniciar sesión.
Respuestas de 20-40 s Peticiones en paralelo sobre una misma sesión (ver arriba). Mirar los avisos Petición lenta del log.
Invalid SQL syntax ... Cannot support this function El analizador SQL del Service Layer rechazó una función en una consulta guardada.
SELF_SIGNED_CERT_IN_CHAIN al instalar Falta NODE_OPTIONS=--use-system-ca o NODE_EXTRA_CA_CERTS.