DP_Stock (v2) suma PDN1.OpenInvQty de las Entradas de Consignación abiertas del almacén, lo mismo que usa el FIFO. La columna se muestra como Consignación. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Web — Devolución a Proveedores
Frontend en Angular 22 (componentes standalone, signals, sin zone.js, CSS) de la aplicación
Devolución a Proveedores para SAP Business One. Consume la API NestJS de ../api.
La documentación general del proyecto (decisiones, flujo, estado) está en
../../CLAUDE.md. Este archivo cubre solo cómo ejecutar y mantener la web.
Puesta en marcha
Desde la raíz del monorepo (devolucion-proveedores-web/), con la API ya levantada:
npm install
npm run dev:web # compila @dp/shared y levanta Angular en http://localhost:4200
ng serve redirige /api a http://localhost:3000 (ver src/proxy.conf.json), así que no hace falta
configurar CORS en desarrollo. Con Fortinet, exportar antes NODE_OPTIONS=--use-system-ca y
NG_CLI_ANALYTICS=false.
Importante:
@dp/sharedse consume compilado. Si lo cambia, ejecutenpm run build:sharedy reinicieng serve: Vite sirve una copia vieja y la página falla con "does not provide an export named …". Los tests no lo detectan.
Scripts
| Comando | Qué hace |
|---|---|
ng serve / npm start |
Servidor de desarrollo con recarga. |
ng build |
Compila a dist/web. |
ng test |
Tests (Vitest + jsdom). Para una sola pasada: npx ng test --watch=false. |
En producción
La web no se despliega por separado: ng build genera dist/web/browser y la API (NestJS) la sirve
junto con /api, por HTTPS y en el mismo origen. Por eso las llamadas son siempre relativas (/api/...).
npm run publicar (en la raíz) arma la carpeta de despliegue; ver
../../deploy/windows/DEPLOY.md.
Pantallas
| Ruta | Pantalla |
|---|---|
/login |
Usuario y contraseña de SAP B1, con la casilla "Verificar los metadatos de SAP al ingresar". |
/planificaciones |
Listado con filtros (estado, almacén, fechas) y paginación (Atrás / Siguiente, filas por página). Los filtros y la página quedan en la URL. |
/planificaciones/nueva |
Pasos 1 y 2: elegir almacén y fecha, pegar el listado desde Excel (botón Pegar desde el portapapeles o Ctrl/Cmd+V), validar y procesar (FIFO). Con ?reemplaza=<id> rehace una planificación. |
/planificaciones/:docEntry |
Pasos 3 y 4: datos de las Devoluciones y transporte, grilla Padre/Hijo con casillas, Crear devoluciones, Rehacer FIFO, Descargar PDF y Cerrar planificación. |
/configuracion/metadatos |
Estado de tablas, campos y objeto de usuario en SAP, y el botón Reconstruir. |
Flujo de rutas: authGuard exige sesión; metadataGuard verifica los metadatos una vez por sesión y,
si falta algo, lleva a Configuración → Metadatos (se omite si el usuario desmarcó la casilla del login).
Una respuesta 401 en cualquier llamada devuelve al login.
Estructura
src/app/
├── core/ servicios HTTP (auth, metadata, planificaciones), guards, interceptor y errores
├── layout/ shell (barra superior) y stepper de los 4 pasos
└── pages/
├── login/
├── metadatos/
└── planificaciones/ listado · nueva/ · detalle/
Cada página tiene su .ts, .html y .css; los tests (*.spec.ts) están junto a lo que prueban.
La lógica de negocio pura (FIFO, qué líneas se pueden marcar, consolidación por proveedor) se importa
de @dp/shared, la misma que usa la API.
Cosas que conviene saber
- El navegador solo conoce la cookie
dp_sid; la sesión de SAP vive en el servidor y se pierde si la API se reinicia (habrá que volver a iniciar sesión). - Descarga de PDF: la API devuelve los archivos en base64; la pantalla arma
Blobs y enlaces (URL.createObjectURL). Con un solo archivo lo descarga directo; con varios deja un enlace por archivo. - Pegar desde el portapapeles usa
navigator.clipboard.readText(): solo funciona enlocalhosto HTTPS, y el navegador pide permiso. Si lo niega, se puede pegar a mano dentro del cuadro de texto. - Estilos en CSS, no SCSS: en macOS 12 el compilador nativo de Sass exige macOS 14 o superior. Las
variables de color y espaciado están en
src/styles.css. - Tests sin zone.js: tras un
flushdeHttpTestingControllerhay que esperar conawait new Promise((r) => setTimeout(r))y llamar afixture.detectChanges();whenStable()no alcanza para las promesas defirstValueFrom.
Diagnóstico rápido
| Síntoma | Causa probable |
|---|---|
| Pantalla en blanco con "does not provide an export named …" en la consola | @dp/shared cambió y ng serve quedó con la copia vieja. Reiniciarlo. |
| Vuelve al login sin avisar | Sesión de SAP vencida o API reiniciada. |
http proxy error: /api/… ECONNREFUSED en la terminal |
La API no está levantada (o se está reiniciando). |
| La lista de almacenes sale vacía | Mirar el recuadro rojo de la pantalla: indica qué llamada falló. |