primer commit

This commit is contained in:
George committed 2026-08-17 11:58:38 -05:00
1 parent ab3c613165
commit b2fb4e2d0a
18 files changed
+1291 -277

No files matched your search

@@ -0,0 +1,169 @@
# 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<br/>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: <MarketingDocumentForm endpoint="Invoices" copyFromSources=[Orden, Entrega] />
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: <CopyFromModal source={Orden} cardCode docType />
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.