Backport de mejoras genéricas de frontend (desde cliente/tagumedica)

- Nuevo Icon.tsx (reemplaza emojis en toda la app), FieldTooltip, ConfirmModal, PageLoader, SecondaryButton, hook useSapCatalog, utils/errors (getErrorMessage).
- App.tsx: code-splitting con lazy()+Suspense+PageLoader para todas las rutas.
- MainLayout.tsx: menú usa Icon.tsx en vez de emojis.
- FormattedField/SelectField: soporte de dbField+tooltip, multiline.
- DenseTable/FilterBar/ListViewTemplate: onClear, mejoras varias.
- PrimaryButton: variante de tamaño sm/md.
- Renombres *View.tsx para uniformar el naming de vistas de detalle/mantenimiento (Dashboard, Items, BatchNumberDetails, Customers, Suppliers, Invoices, Orders, PurchaseOrders, PurchaseInvoices) y SapLogin -> SapLoginForm.
- BatchNumberDetailsList: filtros y columna de descripción de artículo.
- Configs de reportes e iconos de módulos actualizados a Icon.tsx.
- Ajustes de paleta en los 4 temas CSS.
- Docs actualizadas.

Se excluyó explícitamente del backport (queda solo en cliente/tagumedica, no es reusable sin adaptar a los UDFs propios de cada cliente):
- Vistas InmovilizarLotesView, LiberarLotesView, ConfirmarLiberacionLoteView y sus rutas/ítems de menú.
- types/sapInventoryLock.ts (contrato con los UDFs U_SIS_MOVINV/U_EXX_TIPOOPER/U_SIS_TIPDESP/U_SIS_MOTALM de Tagumedica).
- En BatchForm.tsx: los 3 campos U_SIS_MOTEST/U_SIS_COMEST/U_SIS_ACCTOM (Motivo/Comentario/Acción), manteniendo el resto de mejoras genéricas del archivo y reactivando el campo estándar "Detalles/Observaciones" que en tagumedica había quedado comentado sin justificación genérica.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5 committed 2026-09-28 14:28:29 -05:00
1 parent fef21898f9
commit f58f4292c3
55 files changed
+1014 -356

No files matched your search

@@ -69,12 +69,30 @@ Cada vista de mantenimiento (`Orders.tsx`, `Invoices.tsx`, `PurchaseOrders.tsx`,
| `titulo` | Encabezado visible del formulario | `"Factura de Ventas (OINV)"` |
| `headerExtraFields` | Campos de cabecera exclusivos de ese documento | Facturas: `FolioPrefixString`, `FolioNumber`, `GroupNum` |
| `lineColumns` | Columnas de la grilla de líneas, cada una con un `show(doc)` opcional para ocultar/mostrar según `DocType` | Compras oculta `ItemCode`/`Almacén` si `DocType` es de servicio |
| `copyFromSources` | Documentos origen habilitados para el botón "📋 Copiar de" | Facturas de Venta: Orden de Venta y Entrega; Facturas de Proveedor: Orden de Compra |
| `copyFromSources` | Documentos origen habilitados para el botón "Copiar de" (ícono de portapapeles) | Facturas de Venta: Orden de Venta y Entrega; Facturas de Proveedor: Orden de Compra |
| `retencionConfig` / `detraccionConfig` | Solo presentes en `PurchaseInvoices.tsx` — habilitan los bloques de Retención (3%/6%) y Detracción (SUNAT) en el resumen de totales | No se pasan en Órdenes ni en Facturas de Venta |
| `onBuscarSocio`, `onBuscarArticulos`, `onCellSearch` | Callbacks que abren los `ModalSearchTemplate` de Socios, Artículos, Almacén y Código de Impuesto | Cada vista instancia sus propios modales y decide qué endpoint/filtro usar |
El cálculo de totales (subtotal, impuesto 18% fijo, retención, detracción, total general) vive dentro del propio `MarketingDocumentForm`, no en las vistas.
Los íconos de acción (búsqueda, copiar de, catálogo, eliminar línea) son SVG inline definidos en `src/components/ui/Icon.tsx` — no hay emojis ni dependencias externas de iconografía en el proyecto.
### Campo técnico en tooltip, no en el label
Cada `CampoConfig`/`HeaderExtraFieldConfig` de `genericHeaderFields` acepta un `dbField` (= su propio `name`, ya que ambos son literalmente el nombre del campo en `MarketingDocument`) que `FormattedField`/`SelectField` muestran como un ícono ⓘ junto al label; al pasar el mouse aparece el nombre técnico SAP (ej. `DocEntry`, `CardCode`). Antes el label concatenaba ambos textos ("Documento (DocEntry)"), lo que a veces partía el campo en dos líneas y deformaba la grilla — ver `FieldTooltip.tsx`.
### Campos de solo lectura (`readOnly` / `readOnlyOnUpdate`)
`CampoConfig` soporta dos flags que `MarketingDocumentForm` traduce a `mode="display"` (o `disabled` en los `SelectField`):
| Campo | Flag | Comportamiento |
|---|---|---|
| `DocEntry` | `readOnly: true` | Nunca editable (ni al crear ni al actualizar) — lo asigna SAP |
| `DocNum` | `readOnlyOnUpdate: true` | Editable al crear, bloqueado al actualizar |
| `CardCode` | `readOnlyOnUpdate: true` | Editable al crear, bloqueado al actualizar; además oculta el botón de búsqueda de socio cuando está bloqueado |
`readOnlyOnUpdate` se evalúa contra `isEditMode` (`!!docEntry`), definido dentro del propio `MarketingDocumentForm`.
## Flujo: Crear una Factura de Venta copiando una Orden
```mermaid
@@ -96,11 +114,11 @@ sequenceDiagram
Backend->>SAP: GET Currencies
SAP-->>Form: lista de monedas
User->>Form: busca y selecciona Cliente (🔍)
User->>Form: busca y selecciona Cliente (ícono de lupa)
Form->>View: onBuscarSocio() abre ModalSearchTemplate(BusinessPartners)
View-->>Form: setDoc({CardCode, CardName})
User->>Form: clic "📋 Copiar de" → "Orden de Venta"
User->>Form: clic "Copiar de" → "Orden de Venta"
Form->>Copy: <CopyFromModal source={Orden} cardCode docType />
Copy->>API: GET /api/Orders?filtro por CardCode/BaseType
API->>Backend: fetch
@@ -143,11 +161,16 @@ App.tsx (BrowserRouter)
└── /mantenimiento → PurchaseInvoices.tsx → MarketingDocumentForm (+ Retención/Detracción)
MarketingDocumentForm.tsx
├── FormattedField.tsx / SelectField.tsx (cabecera)
├── FormattedField.tsx / SelectField.tsx (cabecera, con FieldTooltip por campo)
├── PrimaryButton.tsx / SecondaryButton.tsx (submit / cancelar)
├── Icon.tsx (íconos SVG: buscar, copiar, catálogo, eliminar)
├── PageLoader.tsx ("Cargando documento..." mientras hace fetch)
├── CopyFromModal.tsx (botón "Copiar de")
└── (por vista) ModalSearchTemplate.tsx ×4 (Socios, Artículos, Almacén, Código de Impuesto)
```
Cada vista de mantenimiento (`Orders`, `Invoices`, `PurchaseOrders`, `PurchaseInvoices`) se carga con `React.lazy()` desde `App.tsx`: el JS de un módulo no se descarga hasta que el usuario navega a él (ver `docs/index.md`).
## Archivos Clave
| Archivo | Ruta | Propósito |
@@ -158,8 +181,11 @@ MarketingDocumentForm.tsx
| `OrdersList.tsx`, `InvoicesList.tsx`, `PurchaseOrdersList.tsx`, `PurchaseInvoicesList.tsx` | `src/views/ventas/`, `src/views/compras/` | Listados vía `ListViewTemplate`, con `StatusBadge` por estado del documento |
| `CopyFromModal.tsx` | `src/components/ui/` | Modal para copiar líneas desde un documento base (Orden→Entrega→Factura) |
| `ModalSearchTemplate.tsx` | `src/components/ui/` | Modal de búsqueda genérico reutilizado para Socios, Artículos, Almacenes, Códigos de Impuesto |
| `sapMarketing.ts` | `src/types/` | `MarketingDocument`, `DocumentLine`, `DocumentConfigProps`, `CopyFromSource`, `LineColumnConfig` |
| `sapMarketing.ts` | `src/types/` | `MarketingDocument`, `DocumentLine`, `DocumentConfigProps`, `CopyFromSource`, `LineColumnConfig` (`key`/`name` tipados como `keyof DocumentLine`/`keyof MarketingDocument`, no `string` suelto) |
| `sunat.ts` | `src/utils/` | `DETRACCION_CODIGOS` (porcentajes SUNAT usados en Facturas de Proveedor) |
| `Icon.tsx` | `src/components/ui/` | Registro de íconos SVG inline (reemplaza los emojis que se usaban antes en botones y menú) |
| `FieldTooltip.tsx` | `src/components/ui/` | Ícono ⓘ con el nombre técnico SAP del campo, usado por `FormattedField`/`SelectField` |
| `errors.ts` | `src/utils/` | `getErrorMessage(err, fallback)` — evita `catch (err: any)` en cada formulario |
| `sales.py` / `purchases.py` | `mini-backend/routers/` | Endpoints REST que proxean a SAP Service Layer |
## Hallazgos (código tal cual está hoy, sin corregir)