Files
basic-erp/CLAUDE.md
T

8.6 KiB
Raw Blame History

basic-erp

ERP base para SAP Business One (Service Layer). Migración del mini-erp (React + FastAPI, en /Users/george/Documents/Desarrollo/React/mini-erp) a NestJS + Angular, ambos en TypeScript. Sirve de base para crear una rama por cliente.

Monorepo npm workspaces:

  • apps/api — NestJS 12 (ESM): proxy hacia el Service Layer, login, sesión SAP compartida, permisos de menú (SQLite). Ver apps/api/README.md.
  • apps/web — Angular 22 (standalone, zoneless, señales): componentes reutilizables estilo SAP Business One. Ver apps/web/README.md.
  • libs/sap-types — tipos y utilidades compartidos por api y web (MENU, evaluador de permisos, tipos de auth/SL). Se compila en postinstall.
  • tools/ — mockup oferta_venta.html (ejemplo: tiene algunos campos no estándar, pero se conserva la idea).

Reglas del proyecto base

  • Solo campos estándar de SAP Business One. Ningún campo de usuario (U_*) salvo U_WEB_USER / U_WEB_PASS de EmployeesInfo, usados para el login web.
  • Los formularios se construyen con componentes reutilizables y configuración declarativa; no se duplica markup por documento.
  • Aspecto por variables CSS (temas). Tema por defecto: claro, con la paleta del mockup. Esquinas contenidas (--radius*, como SBO).
  • La fila de un formulario es etiqueta + uno o varios controles (input, select, número, fecha, botón); la cabecera tiene como máximo 2 columnas.
  • Impuesto de las líneas: TaxCode con el maestro SalesTaxCodes (verificado en el Service Layer; VatGroups no tiene Rate). Un cliente con VatGroup lo cambia en su rama.

Criterios de la interfaz

Es un ERP, no una página de publicidad: ligera y rápida. Sin librerías de componentes (Material/PrimeNG), sin webfonts ni animaciones, componentes propios y densos (13 px), zoneless + OnPush, rutas con carga diferida, listas largas paginadas en el servidor (50 por página). Presupuesto del bundle inicial en angular.json (aviso 300 kB; hoy ~287 kB, 81 kB comprimido: httpResource aporta ~18 kB al chunk compartido; si hace falta recuperarlos, reemplazarlo por RxJS).

Comandos

  • npm install — npm 11 (npm 10 falla al resolver las dependencias de Nest 12: npx npm@11 install); instala todo y compila libs/sap-types.
  • npm run dev:api (:3000) · npm run dev:web (:4200, proxy /api) · npm run build · npm test.
  • Backend contra SAP real (opt-in): SAP_LIVE=1 npm run test:e2e -w apps/api.
  • Página de componentes solo desarrollo: http://localhost:4200/dev/componentes (toolbar, ventana, campos, pestañas, grilla y listas de valores con datos reales; no guarda nada).

Decisiones tomadas (con su porqué)

  • Login web con U_WEB_USER/U_WEB_PASS (se mantiene). Mismo mensaje para usuario inexistente y clave errónea; comparación en tiempo constante; 429 tras 5 fallos por usuario / 20 por IP; una sesión por usuario; timeout deslizante 30 min (el servidor informa sessionTimeoutMinutes); token Authorization: Bearer.
  • Usuario SAP compartido (hoy Manager de pruebas; luego un usuario de licencia indirecta). Todo sale auditado con ese usuario.
  • Concurrencia hacia el Service Layer = 1 (SAPB1_SL_MAX_CONCURRENCY): medido en SAP10 (MSSQL, 32 GB), 12 peticiones tardan 0.6 s en serie y 7.5 s con 2 en paralelo. Un pool de sesiones no ayuda; la cola sí. Repetir la medición en cada cliente.
  • TLS: SAPB1_SL_CA_FILE opcional (certificado autofirmado de SAP o CA de firewall); VERIFY_SSL=true por defecto y no se puede apagar en producción. fortinet.cer no sirve para SAP10: presenta su propio certificado autofirmado (apps/api/certs/sap10.pem, ignorado por git).
  • Proxy /api/sl/:recurso: el frontend arma $select/$filter/...; el backend valida y ejecuta solo recursos registrados (apps/api/src/sl/sl-resources.ts), con permiso de menú y cabeceras B1S-* de lista blanca. Nunca registrar EmployeesInfo (tiene U_WEB_PASS). InventoryRequests no existe: es InventoryTransferRequests.
  • Permisos de menú en SQLite (SQLITE_PATH), patrones *, /ventas/*, /ventas/ordenes; ADMIN_WEB_USERS garantiza el acceso total; no se puede quitar el último admin.
  • Listas de documentos: más recientes primero (DocEntry desc), 50 por página, Estado = Abierto por defecto (como el mini-erp; cambiarlo es un defaultValue), filtro de fecha siempre rango [desde – hasta], multi-selección con chips, búsqueda numérica por igualdad. Sin filtro base DocumentSubType (excluiría notas de débito, etc.). El PDF y los reportes se migran después vía API Gateway (otro servicio, con su propia cola y sesión).
  • Reportes/PDF no se generan en la base; el botón PDF queda pendiente hasta migrar el API Gateway.

Flujo de las pantallas de documento

Cada menú abre primero una lista de los últimos documentos (barra de filtros + búsqueda por columna); desde ahí se crea uno nuevo (/…/nuevo, formulario vacío) o se abre uno existente (/…/:docEntry, ver/editar; los cerrados/cancelados en solo lectura). Las pantallas se definen en apps/web/src/app/features/documents/document-screens.ts (17 documentos: ventas, compras, inventario). Las columnas de línea estándar están en features/documents/line-columns.ts.

Cómo verificar cambios de interfaz

  • Probar contra el SAP real con la extensión de Chrome (list_connected_browsers debe mostrar un navegador). Si no conecta, usar Chrome headless por CDP.
  • No escribir contraseñas en formularios: obtener el token con curl a /api/auth/login (la clave de prueba se lee de EmployeesInfo solo para eso, nunca se imprime ni se guarda) e inyectar solo el token en localStorage (erp_session).
  • Al terminar: cerrar la sesión de prueba (POST /api/auth/logout), borrar erp_session/erp_theme del navegador, cerrar la pestaña, apagar los servidores y borrar archivos temporales (token, apps/api/data/). No dejar páginas de demostración fuera de /dev/componentes.
  • Escrituras a SAP (POST/PATCH): el usuario autorizó (2026-10-14) escribir en SBODemoCL, su ambiente propio de pruebas; ya se probaron crear/actualizar órdenes de venta y de compra, reemplazo de líneas y el 412 por conflicto. Documentos de prueba creados: orden de venta 315 y orden de compra 2883 (comentario "PRUEBA basic-erp"). Aun así, avisar antes de escribir en cualquier otra base.
  • Los tests no detectan todo: el foco tras crear una línea (se pedía antes de que existiera la fila) solo falló en el navegador real.

Estado y próximos pasos

Hecho (commits en main): monorepo · API (config, capa SAP con sesión compartida y cola, login, permisos SQLite, proxy /api/sl) · web (temas, login, layout con menú por permisos, sbo-value-help, campos y filas compuestas, listas con filtros, ventana/toolbar/pestañas/menús, grilla de líneas, /dev/componentes).

Pendiente, en orden:

  1. Paso 9 — formulario de documentos: hecho para ventas y compras (document-form.page, document-model.ts: cargar, crear, actualizar con If-Match/412, navegación, totales con SalesTaxCodes (también en compras), solo lectura), probado con SAP simulado y contra SBODemoCL (leer, crear, actualizar, líneas, 412). Un código escrito a mano (socio, artículo, almacén, impuesto) se resuelve al salir del campo con SlLookupApi (mismo recurso y filtro base que la lista "…"); si no existe se avisa. Falta: "Copiar de/a", botón PDF, fila del flete, toolbar de ancho completo, formularios de inventario y solicitudes de compra.
  2. Pantallas de maestros (Items, BusinessPartners: Clientes/Proveedores, Artículos), hoy "no disponible".
  3. Pantalla web de permisos — hecha (/admin/permisos).
  4. Auditoría (audit_log en SQLite; hoy solo líneas AUDIT en el log) y nestjs-cls para el usuario en los logs.
  5. Migrar reportes/PDF vía API Gateway (módulo y cola aparte; no registrar credenciales de los tools/ del mini-erp, traen contraseñas en claro).
  6. Revisar las vulnerabilidades de npm audit y definir una política para U_WEB_PASS (texto plano, claves cortas) antes de producción.
  7. Docker/despliegue (HTTPS tras Fortinet; sesiones web en memoria ⇒ un solo proceso).

Flujo de trabajo por cliente (branches)

  1. main es la versión base/genérica, sin personalizaciones de cliente.
  2. Cada cliente tiene su branch (cliente/<nombre-cliente>); ahí viven sus personalizaciones y fixes.
  3. Los cambios de una branch de cliente no se mezclan con main ni con otro cliente, salvo backport genérico decidido explícitamente.
  4. Antes de crear branches, mergear a main, o hacer merge/backport entre clientes, confirmar con el usuario. No hacer git push sin confirmación. Cada paso termina en un commit propio.