Registra sesiones, creaciones y modificaciones en SAP (solo nombres de campos), denegados y cambios de permisos.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
sbo-rows-table reutilizable (también en la ventana de lotes). Direcciones y contactos se envían
completos con reemplazo; los precios solo por filas cambiadas. Probado contra SBODemoCL.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Una ventana por línea con tabla editable; validación de suma de lotes y una serie por unidad.
Probado contra SBODemoCL: entrada de inventario 156 con SU01 y su lote.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Todas las pantallas declaran su DocumentLayout (catálogo FIELDS): ventas y compras dejan de tener la
cabecera escrita en el HTML; el folio solo lo llevan los documentos tributarios.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Configuración declarativa en document-layouts.ts; las líneas de las transferencias van en
StockTransferLines y las de compra/inventario llevan UoMEntry si el artículo tiene grupo de unidades.
Probado contra SBODemoCL (solicitud de compra 2, solicitud de traslado 472, entrada 155).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Probado contra SBODemoCL: crear y actualizar órdenes de venta y de compra, reemplazo de líneas y 412 por conflicto.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Registra lo decidido (login, usuario SAP compartido, concurrencia 1 medida,
TLS, proxy con registro, TaxCode, listas de documentos), cómo verificar
cambios de interfaz con seguridad, el estado actual y el orden de lo
pendiente (paso 9: formulario de documentos).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- sbo-lines-grid: columnas declarativas (texto / número con decimales /
solo lectura / calculadas), celdas con lista de valores (botón "..." y
F4) cuyo apply rellena la línea, añadir y quitar línea, y "Elegir
artículos..." para agregar varias líneas a la vez.
- Teclado: Enter confirma y baja a la misma columna (crea línea en la
última fila), flechas arriba/abajo cambian de fila. Las celdas se
confirman al salir de ellas; un número inválido conserva el anterior.
- Documento cerrado: grilla de solo lectura, sin botones ni listas.
- Columnas estándar de línea de SAP (artículo, descripción, cantidad,
almacén, precio, % dto., impuesto, total) con TaxCode / SalesTaxCodes,
verificado en el Service Layer real; recalcLine (cantidad x precio x
(1 - dto)).
- Corrige el foco al crear una línea con Enter: se pedía antes de que la
fila existiera en el DOM (ahora espera al render).
- /dev/componentes: página de componentes solo para desarrollo
(canMatch isDevMode), sin entrada en el menú y sin escribir en SAP.
- Verificado en Chrome contra SAP real: artículo elegido de la lista,
5 x 10,000 con 10 % = 45,000.00, Enter/flechas, varios artículos a la
vez, quitar línea y subtotal del pie.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- sbo-window: título con insignia de estado, cuerpo, zona de acciones
(sboActions / sboActionsEnd) y barra de estado ok / warn / err / info con
role="status".
- sbo-toolbar con botones .tb y sbo-icon (SVG en línea).
- sbo-tabs / sbo-tab: paneles ocultos conservan su estado, [(selected)],
flechas izquierda/derecha con foco, roles y aria-controls.
- sbo-menu-button: lista de acciones ("Copiar de/a") que abre hacia arriba o
abajo; Esc y clic fuera la cierran; opciones deshabilitables.
- sbo-badge compartido con las listas (data-table lo usa); tono 'info'.
- Verificado en Chrome contra el mockup oferta_venta.html: misma estructura,
pestañas por clic y teclado, menú hacia arriba, estados ok/err.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Los radios estaban escritos en cada componente. Ahora salen de --radius
(campos), --radius-lg (botones), --radius-pill (insignias) y --radius-panel
(tablas y ventanas, 0 por defecto). Sin cambio visual: un tema nuevo puede
redondear la interfaz sin tocar componentes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cada pantalla de documento del menú abre primero la lista de los últimos
documentos; desde ahí se crea uno (/nuevo) o se abre uno (/:docEntry).
- sbo-list-view: título, botón de alta, barra de filtros, tabla y paginación
(50 por página, más recientes primero).
- sbo-filter-bar (como el FilterBar del mini-erp): búsqueda por la columna
activa + filtros declarativos text / select (con valor por defecto) /
multi (chips + lista de valores) / date (siempre rango [desde – hasta]),
con Ir y Limpiar. Ir aplica búsqueda y filtros en una sola consulta.
- Búsqueda numérica por igualdad (DocNum eq 314) con aviso si no es número;
una columna con texto calculado (format) ya no es buscable por defecto.
- Piezas compartidas con sbo-value-help, que se refactoriza sobre ellas:
createSlList (estado de búsqueda/paginación), sbo-data-table, sbo-pager,
sbo-search-bar. Insignias de estado (tone) y estilos de botón globales.
- DOCUMENT_SCREENS: columnas y filtros de 17 documentos (ventas, compras,
inventario) según los campos verificados en el Service Layer real
(PurchaseRequests no tiene CardCode; StockTransfers no tiene estado).
- Rutas generadas desde el registro: lista, nuevo y :docEntry bajo el
permiso de la ruta de menú. El formulario es un marcador (paso 9).
- Presupuesto: el aviso del bundle inicial sube a 300 kB; httpResource
aporta ~18 kB al chunk compartido (278 kB, 78 kB comprimido).
- Verificado en Chrome contra SAP real: 49 órdenes abiertas, 314 en total,
rango de fechas, chips de monedas, búsqueda por número, navegación y
botón atrás, tema oscuro; ofertas (4391), transferencias y entradas.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
El mockup muestra que una fila es etiqueta + uno o varios controles en la
misma línea (Cliente = input + "...", Canal / Zona = dos mitades, Serie +
Número = 72 px + resto, select + número + botón) y que la cabecera tiene a
lo sumo 2 columnas. Los campos de un solo control no lo permitían.
- Controles sin etiqueta combinables dentro de sbo-field: sbo-input,
sbo-textarea, sbo-number, sbo-date, sbo-select y el botón .sbo-btn;
ocupan el espacio sobrante o un width fijo.
- El primer control de la fila toma el id de la etiqueta (claimId); los
demás se nombran con ariaLabel. El error de la fila marca todos sus
controles (aria-invalid / aria-describedby).
- Los campos con etiqueta (sbo-text-field, sbo-number-field, ...,
sbo-lookup-field) pasan a ser atajos de un solo control con la misma API.
- CSS global: .sbo-group y .sbo-btn reemplazan a .sbo-pick/.sbo-pair.
- CLAUDE.md apunta al mockup renombrado (tools/oferta_venta.html).
- Verificado en Chrome contra SAP real, con una cabecera que reproduce las
filas compuestas del mockup.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- sbo-field: fila etiqueta + control, con obligatorio (*), flecha dorada,
etiqueta enlazable y mensaje de error.
- sbo-text-field, sbo-textarea-field, sbo-number-field, sbo-date-field,
sbo-select-field y sbo-lookup-field, con enlace bidireccional por señales
([(value)]) y entradas comunes (label, required, readonly, disabled, error).
- sbo-number-field: formateado fuera de foco (1,234.50), acepta 12,5 y
1,234.50 al escribir, redondea a los decimales indicados y conserva el
valor si el texto no es un número (parseDecimal).
- sbo-select-field devuelve el valor con su tipo original (número o texto).
- sbo-lookup-field: botón "…" y F4 abren sbo-value-help (VhLookup); elegir
rellena el campo, emite la fila y devuelve el foco; escribir el código a
mano sigue siendo válido.
- Estilos globales de formulario (forms.css) tomados del mockup, con
ancho de etiqueta configurable (--label-w).
- Verificado en Chrome contra SAP real, en claro y oscuro: cliente elegido
de la lista rellena código, nombre y RUC; edición de números; selects.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- sbo-value-help: búsqueda por columna con contains(), columnas declarativas
(texto, número, importe, fecha, format a medida), paginación del servidor
con total, baseFilter/orderby, Esc/Enter, errores con reintento.
- Selección única (un clic confirma) o múltiple (casillas, seleccionar
página, Confirmar (n)). Mejoras sobre el sistema anterior: lo marcado se
conserva entre páginas, el filtro base va entre paréntesis (un "or" ya no
rompe la precedencia) y las comillas del texto buscado se escapan.
- Cambiar la columna elegida no consulta hasta pulsar Buscar.
- Peticiones con httpResource: las obsoletas se cancelan solas.
- Helpers reutilizables: core/sl/odata (escape, contains, combinar filtros)
y core/format (importes y fechas sin desfase de zona horaria).
- Verificado en Chrome contra SAP real (253 clientes, 1209 artículos):
búsqueda por Nombre, paginación, selección múltiple entre páginas y
tema oscuro.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Login contra POST /api/auth/login; SessionStore en localStorage con el
timeout deslizante que informa el servidor (sessionTimeoutMinutes).
- Interceptor: Bearer en /api, renueva actividad y, ante 401, cierra la
sesión y vuelve al login recordando la ruta (solo rutas internas).
- Guards: sesión, invitado y permiso por pantalla (data.path). Corrige que
inject() no puede usarse tras un await en permissionGuard.
- Layout con barra superior (empresa, usuario, tema, salir) y menú lateral
filtrado por GET /api/user/menu; plegable y con botón en pantallas angostas.
- Menú único en libs/sap-types (MENU, filterMenu); el backend verifica por
test que las rutas de permiso de sus recursos existan en él.
- Una ruta por pantalla del menú; las no construidas muestran "no disponible".
- Verificado en Chrome headless contra el backend y SAP reales: redirección
sin sesión, menú de 20 pantallas, navegación, plegado, tema oscuro y
persistencia, vista móvil, salir, token inválido y credenciales malas.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- apps/web: Angular 22 standalone, zoneless, OnPush, vitest; proxy /api
hacia el backend; presupuesto de bundle (aviso 260 kB, error 400 kB).
- libs/sap-types: tipos de auth/permisos/Service Layer y el evaluador de
patrones de menú, compartidos por api y web (se compila en postinstall).
El backend deja de tener su propia copia del evaluador.
- Temas por variables CSS: claro por defecto con la paleta del mockup de
Oferta de ventas, oscuro incluido; ThemeService + selector, con el tema
guardado aplicado antes del primer pintado. Agregar un tema = 1 css +
1 import + 1 entrada.
- Criterios de interfaz ligera en CLAUDE.md y README.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
El frontend envía parámetros OData y cuerpo; el backend valida y ejecuta.
- GET lista/por clave, POST y PATCH sobre /api/sl/:recurso, solo para
recursos registrados (ventas, compras, inventario y maestros estándar);
EmployeesInfo no se registra nunca (contiene U_WEB_PASS).
- Permisos de menú por recurso (lectura/escritura); catálogos de consulta
abiertos a cualquier sesión. Evaluador de patrones compartible
(/inventario/* ya no habilita /inventario-x).
- Parámetros OData validados con lista cerrada, $top máx. 500, $expand solo
si el recurso lo declara, claves validadas y escapadas por tipo, cabeceras
B1S-* con lista blanca. $inlinecount y B1S-PageSize automáticos.
- configureApp() compartido entre main.ts y e2e (prefijo y límite de 5 mb).
- Verificado contra SAP real: los 27 recursos existen; listado con total,
filtro, paginación y claves. InventoryRequests no existe en el SL: se
registra InventoryTransferRequests.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- SQLite (better-sqlite3 + TypeORM, WAL) con tabla menu_permissions
(usuario web, patrón de ruta); archivo fuera del repo.
- GET /api/user/menu para el frontend; GET/PUT/DELETE /api/permissions
solo para administradores (acceso "*").
- ADMIN_WEB_USERS garantiza el acceso total al arrancar; no se puede
quitar el "*" al último administrador (409, dentro de una transacción).
- Patrones validados (`*`, `/modulo/ruta`, `/modulo/*`). A diferencia del
frontend anterior, `/inventario/*` ya no habilita `/inventario-x`.
- Helper de e2e compartido (SAP simulado, SQLite en memoria).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- POST /api/auth/login (U_WEB_USER/U_WEB_PASS de EmployeesInfo), logout y me.
- Token opaco (32 bytes) en Authorization: Bearer; una sesión por usuario,
timeout deslizante configurable (SESSION_TIMEOUT_MINUTES, 30 por defecto).
- AuthGuard global con @Public(); /health/sap ahora exige sesión.
- Usuario inexistente y contraseña errónea devuelven el mismo mensaje;
comparación en tiempo constante; filtro OData escapado; se rechazan
U_WEB_USER duplicados.
- LoginAttemptsService: 429 tras 5 fallos por usuario o 20 por IP (15 min).
- Tests unitarios y e2e con SAP simulado.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- SapSessionService: una sesión para todos; un solo login aunque lleguen
peticiones concurrentes o 401 simultáneos (loginInFlight); logout al apagar.
- SapClientService: proxy con reintento único ante 401, errores SAP
traducidos (SapHttpException) y fallos de red/TLS mapeados a 502/504.
Un login rechazado se informa como 502, nunca 401 (el frontend lo toma
como sesión web expirada).
- Confianza TLS: SAPB1_SL_CA_FILE opcional (autofirmado de SAP o CA de
firewall) sumado a las CA del sistema; VERIFY_SSL=true por defecto y no
se puede apagar en producción.
- SAPB1_SL_MAX_CONCURRENCY (default 1): medido en SAP10, más de ~2
peticiones en paralelo retrasan ~7 s cada una extra; en serie ~60 ms.
- GET /api/health/sap, tests unitarios (MockAgent) y e2e opcional contra
SAP real (SAP_LIVE=1). apps/api/certs documentado; *.pem/*.cer ignorados.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Nest 12 (ESM, vitest, oxlint). El .env se valida con zod al arrancar;
prefijo global /api, CORS configurable y GET /api/health.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Raíz con workspaces apps/* y libs/*, reglas del proyecto base y flujo
por branch de cliente en CLAUDE.md, y el mockup de Oferta de ventas.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>