# Flujo de Procesamiento — Documentos de Marketing (Ventas / Compras) Cubre los documentos comerciales de SAP Business One que la app gestiona: Órdenes de Venta, Facturas de Venta, Órdenes de Compra y Facturas de Proveedor. Los cuatro comparten un único formulario genérico (`MarketingDocumentForm.tsx`) parametrizado por vista. ## Arquitectura General ```mermaid graph TB subgraph "Frontend React (sap-frontend)" OL[OrdersList.tsx] O[Orders.tsx] IL[InvoicesList.tsx] I[Invoices.tsx] POL[PurchaseOrdersList.tsx] PO[PurchaseOrders.tsx] PIL[PurchaseInvoicesList.tsx] PI[PurchaseInvoices.tsx] FORM[MarketingDocumentForm.tsx] COPY[CopyFromModal.tsx] SEARCH[ModalSearchTemplate.tsx] BADGE[StatusBadge.tsx] LVT[ListViewTemplate.tsx] TYPES[types/sapMarketing.ts] API[api.ts] end subgraph "Backend FastAPI (mini-backend)" SALES[routers/sales.py] PURCH[routers/purchases.py] CORE[core/sap.py] end subgraph "SAP Business One" SL[Service Layer
Orders / Invoices / PurchaseOrders / PurchaseInvoices] end OL --> LVT IL --> LVT POL --> LVT PIL --> LVT LVT --> BADGE O --> FORM I --> FORM PO --> FORM PI --> FORM FORM --> COPY FORM --> SEARCH FORM --> TYPES FORM --> API API -->|GET/POST/PATCH| SALES API -->|GET/POST/PATCH| PURCH SALES --> CORE PURCH --> CORE CORE --> SL ``` Cada vista de mantenimiento (`Orders.tsx`, `Invoices.tsx`, `PurchaseOrders.tsx`, `PurchaseInvoices.tsx`) es una capa delgada: mantiene el estado del documento (`doc`, tipado como `MarketingDocument` en `types/sapMarketing.ts`) y le pasa a `MarketingDocumentForm` la configuración específica de ese tipo de documento — el componente de formulario en sí no sabe si está editando una orden o una factura, solo renderiza lo que recibe por props. ## Cómo un solo formulario sirve a los 4 documentos `MarketingDocumentForm` recibe por props todo lo que varía entre documentos: | Prop | Qué controla | Ejemplo | |---|---|---| | `endpoint` | Endpoint del backend a consultar/enviar (`GET/POST/PATCH /api/{endpoint}`) | `"Orders"`, `"Invoices"`, `"PurchaseOrders"`, `"PurchaseInvoices"` | | `tipoDocumento` | Etiqueta tipada (`OrdenVenta`, `FacturaVenta`, `OrdenCompra`, `FacturaProveedor`) declarada en `DocumentConfigProps` | — no se usa dentro de la lógica del propio formulario en el código leído; parece ser solo metadata para quien lo invoca | | `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 | | `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. ## Flujo: Crear una Factura de Venta copiando una Orden ```mermaid sequenceDiagram actor User as Usuario participant List as InvoicesList participant View as Invoices.tsx participant Form as MarketingDocumentForm participant Copy as CopyFromModal participant API as api.ts participant Backend as backend sales.py participant SAP as SAP Service Layer User->>List: /ventas/facturas → "Nueva Factura" List->>View: navigate("/ventas/facturas/mantenimiento") View->>Form: Form->>API: GET /api/Currencies API->>Backend: fetch Backend->>SAP: GET Currencies SAP-->>Form: lista de monedas User->>Form: busca y selecciona Cliente (🔍) Form->>View: onBuscarSocio() abre ModalSearchTemplate(BusinessPartners) View-->>Form: setDoc({CardCode, CardName}) User->>Form: clic "📋 Copiar de" → "Orden de Venta" Form->>Copy: Copy->>API: GET /api/Orders?filtro por CardCode/BaseType API->>Backend: fetch Backend->>SAP: GET Orders SAP-->>Copy: documentos abiertos del cliente User->>Copy: selecciona una orden Copy-->>Form: onConfirm(lines, sourceLabel) Note over Form: Si ya hay líneas, confirm() pregunta reemplazar o agregar Form->>Form: setDoc({DocumentLines: lines}) — cada línea trae BaseType/BaseEntry/BaseLine User->>Form: clic "Crear Documento" Form->>API: POST /api/Invoices (doc + DocumentLines, sin BaseRef) API->>Backend: fetch POST Backend->>SAP: POST Invoices (con líneas BaseEntry → SAP cierra la orden origen) SAP-->>Backend: 201 Created Backend-->>Form: ok Form-->>User: "Documento creado exitosamente en SAP" ``` El mismo patrón aplica a Facturas de Proveedor copiando desde Órdenes de Compra, solo cambian `endpoint` y `copyFromSources`. ## Árbol de Componentes ``` App.tsx (BrowserRouter) └── / (ProtectedRoute → MainLayout) ├── /ventas │ ├── /ordenes → OrdersList.tsx → ListViewTemplate → StatusBadge │ ├── /ordenes/mantenimiento → Orders.tsx → MarketingDocumentForm │ ├── /entrega → stub "Entregas / Guías" (sin vista real, ver Hallazgos) │ └── /facturas │ ├── (lista) → InvoicesList.tsx → ListViewTemplate → StatusBadge │ └── /mantenimiento → Invoices.tsx → MarketingDocumentForm └── /compras ├── /ordenes → PurchaseOrdersList.tsx → ListViewTemplate → StatusBadge ├── /ordenes/mantenimiento → PurchaseOrders.tsx → MarketingDocumentForm ├── /recepcion → stub "Recepciones de Compra" (sin vista real, ver Hallazgos) └── /facturas ├── (lista) → PurchaseInvoicesList.tsx → ListViewTemplate → StatusBadge └── /mantenimiento → PurchaseInvoices.tsx → MarketingDocumentForm (+ Retención/Detracción) MarketingDocumentForm.tsx ├── FormattedField.tsx / SelectField.tsx (cabecera) ├── CopyFromModal.tsx (botón "Copiar de") └── (por vista) ModalSearchTemplate.tsx ×4 (Socios, Artículos, Almacén, Código de Impuesto) ``` ## Archivos Clave | Archivo | Ruta | Propósito | |---|---|---| | `MarketingDocumentForm.tsx` | `src/components/` | Formulario genérico: cabecera, grilla de líneas, totales, copiar-de, submit GET/POST/PATCH | | `Orders.tsx` / `Invoices.tsx` | `src/views/ventas/` | Configuran el formulario para Órdenes y Facturas de venta | | `PurchaseOrders.tsx` / `PurchaseInvoices.tsx` | `src/views/compras/` | Configuran el formulario para Compras; Facturas agrega retención/detracción | | `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` | | `sunat.ts` | `src/utils/` | `DETRACCION_CODIGOS` (porcentajes SUNAT usados en Facturas de Proveedor) | | `sales.py` / `purchases.py` | `mini-backend/routers/` | Endpoints REST que proxean a SAP Service Layer | ## Hallazgos (código tal cual está hoy, sin corregir) - **`ventas/entrega` y `compras/recepcion` son stubs**: en `App.tsx` son componentes en línea que solo muestran un título ("Entregas / Guías" / "Recepciones de Compra"), sin listado ni formulario real todavía. - **`DeliveryNotesList.tsx` existe pero no está enrutado**: el archivo `src/views/ventas/DeliveryNotesList.tsx` está escrito pero ninguna ruta en `App.tsx` lo importa o lo usa — no es alcanzable desde la navegación actual. - El endpoint `PurchaseDeliveryNotes` (documentado en `mini-backend/docs/api-reference.md`) tampoco tiene vista de frontend correspondiente todavía.