2026-10-13 08:09:07 -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`](../../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/`):
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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`](../../CLAUDE.md#api-prefijo-api).
|
|
|
|
|
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).
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npm run publicar # desde la raíz: arma release/devolucion-proveedores/
|
|
|
|
|
```
|
|
|
|
|
|
2026-10-13 08:55:29 -05:00
|
|
|
Instalación en Windows (servicio con NSSM, HTTPS, firewall, actualizaciones): [`../../deploy/windows/DEPLOY.md`](../../deploy/windows/DEPLOY.md).
|
2026-10-13 08:09:07 -05:00
|
|
|
|
2026-10-13 08:55:29 -05:00
|
|
|
**Logs:** la API no escribe archivos; usa el `Logger` de Nest por consola. Como servicio, NSSM captura
|
2026-10-13 08:09:07 -05:00
|
|
|
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 están escritas pero no se han ejecutado todavía.
|
|
|
|
|
|
|
|
|
|
## 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`. |
|