173 lines
9.5 KiB
Markdown
173 lines
9.5 KiB
Markdown
# Flujo de Procesamiento — Socios de Negocio (Clientes / Proveedores)
|
|
|
|
## Arquitectura General
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Frontend React (sap-frontend)"
|
|
RT[Router App.tsx]
|
|
CLIST[CustomersList.tsx]
|
|
SLIST[SuppliersList.tsx]
|
|
CVIEW[Customers.tsx]
|
|
SVIEW[Suppliers.tsx]
|
|
BPFORM[BusinessPartnerForm.tsx]
|
|
LIST_TMPL[ListViewTemplate.tsx]
|
|
UI_TABLE[DenseTable.tsx]
|
|
API[api.ts]
|
|
end
|
|
|
|
subgraph "Backend FastAPI (mini-backend)"
|
|
ROUTER[routers/business_partners.py<br/>make_crud_router]
|
|
CORE[core/crud_router.py]
|
|
SAP_CORE[core/sap.py]
|
|
SUNAT[Sunat/BusinessPartners/DocumentType]
|
|
end
|
|
|
|
subgraph "SAP Business One"
|
|
SL[Service Layer<br/>BusinessPartners]
|
|
end
|
|
|
|
RT --> CLIST
|
|
RT --> SLIST
|
|
RT --> CVIEW
|
|
RT --> SVIEW
|
|
CLIST --> LIST_TMPL
|
|
SLIST --> LIST_TMPL
|
|
CVIEW --> BPFORM
|
|
SVIEW --> BPFORM
|
|
LIST_TMPL --> UI_TABLE
|
|
LIST_TMPL --> API
|
|
BPFORM --> API
|
|
|
|
API -->|GET/POST/PATCH BusinessPartners| ROUTER
|
|
API -->|GET DocumentType| SUNAT
|
|
ROUTER --> CORE
|
|
CORE --> SAP_CORE
|
|
SAP_CORE -->|B1SESSION| SL
|
|
```
|
|
|
|
## Un solo formulario para Clientes y Proveedores
|
|
|
|
A diferencia de otros módulos, acá **no hay un componente por tipo de socio**: `BusinessPartnerForm.tsx` es un único formulario genérico parametrizado por props, y `Customers.tsx` / `Suppliers.tsx` son wrappers finos que solo le pasan configuración distinta:
|
|
|
|
| Prop | `Customers.tsx` | `Suppliers.tsx` |
|
|
| ----------------- | --------------------------- | --------------------------------------------------- |
|
|
| `cardType` | `"cCustomer"` | `"cSupplier"` |
|
|
| `entityLabel` | `"Cliente"` | `"Proveedor"` |
|
|
| `listPath` | `/socios/clientes` | `/socios/proveedores` |
|
|
| `codePlaceholder` | `Ej. C00001` | `Ej. P00001` |
|
|
| `extraFields` | `[]` (sin campos extra hoy) | `U_EXX_TIPODOCU` (Tipo de Documento SUNAT, select) |
|
|
|
|
La diferenciación entre "es cliente" o "es proveedor" para el propio dato de SAP la hace el campo `CardType` (`cCustomer` / `cSupplier`), que viaja fijo en el `body` del POST/PATCH según qué wrapper se use — el formulario en sí no lo deja editar.
|
|
|
|
El mecanismo `extraFields` (tipo `ExtraFieldConfig[]`, definido en `BusinessPartnerForm.tsx`) permite agregar campos exclusivos de un tipo de socio sin tocar el formulario base: cada entrada define `name`, `label`, `type` (`text` | `email` | `select`), y opcionalmente `loadOptions` (una función async que trae las opciones del backend). Hoy el único caso real es el campo `U_EXX_TIPODOCU` en Proveedores, que carga sus opciones desde `GET /api/Sunat/BusinessPartners/DocumentType` (catálogo SUNAT expuesto vía SAP).
|
|
|
|
## Flujo Vista de Lista → Editar Socio (caso Clientes)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
actor User as Usuario
|
|
participant Router as App.tsx
|
|
participant ListView as CustomersList
|
|
participant LVT as ListViewTemplate
|
|
participant DTable as DenseTable
|
|
participant DetailView as Customers.tsx
|
|
participant Form as BusinessPartnerForm
|
|
participant API as api.ts
|
|
participant Backend as backend business_partners.py
|
|
participant SAP as SAP Service Layer
|
|
|
|
User->>Router: /socios/clientes
|
|
Router->>ListView: render
|
|
ListView->>LVT: <ListViewTemplate endpoint="BusinessPartners" baseFilter="CardType eq 'cCustomer'" .../>
|
|
LVT->>API: GET /api/BusinessPartners?...&$filter=CardType eq 'cCustomer'
|
|
API->>Backend: fetch con X-Session-Token
|
|
Backend->>SAP: GET BusinessPartners (con B1SESSION)
|
|
SAP-->>Backend: JSON con datos
|
|
Backend-->>API: JSON response
|
|
API-->>LVT: json.value[]
|
|
LVT->>DTable: render rows
|
|
DTable-->>User: tabla de clientes
|
|
|
|
User->>DTable: clic en editar (CardCode "C00001")
|
|
DTable->>Router: navigate("/socios/clientes/mantenimiento?code=C00001")
|
|
Router->>DetailView: render con searchParams.code
|
|
DetailView->>Form: <BusinessPartnerForm cardType="cCustomer" .../>
|
|
Form->>API: GET /api/BusinessPartners/C00001
|
|
API->>Backend: fetch
|
|
Backend->>SAP: GET BusinessPartners('C00001')
|
|
SAP-->>Backend: {CardCode, CardName, FederalTaxID, BPAddresses[], ...}
|
|
Backend-->>API: JSON raw SAP
|
|
API-->>Form: data
|
|
Form->>Form: setFormData(data) — sin mapeo de nombres, usa los campos SAP tal cual
|
|
Form-->>User: formulario con pestañas "General" / "Direcciones"
|
|
|
|
User->>Form: edita campos y clic "Actualizar Cliente"
|
|
Form->>API: PATCH /api/BusinessPartners/C00001
|
|
Note over Form,API: body: {CardName, FederalTaxID, Phone1, EmailAddress, BPAddresses[], ...extraFields}
|
|
API->>Backend: fetch PATCH
|
|
Backend->>SAP: PATCH BusinessPartners('C00001')
|
|
SAP-->>Backend: 204 No Content
|
|
Backend-->>API: 204
|
|
API-->>Form: ok
|
|
Form-->>User: "Cliente actualizado correctamente"
|
|
```
|
|
|
|
El flujo de Proveedores es idéntico, cambiando el `baseFilter` a `CardType eq 'cSupplier'` en `SuppliersList.tsx` y usando `Suppliers.tsx` como vista de detalle.
|
|
|
|
Para un socio **nuevo** (`isEditMode = false`), el submit hace `POST /api/BusinessPartners` en vez de `PATCH`, y tras la respuesta exitosa navega de vuelta al listado (`listPath`) después de 1.5s.
|
|
|
|
## Árbol de Componentes
|
|
|
|
```
|
|
App.tsx (BrowserRouter)
|
|
└── / (ProtectedRoute → MainLayout)
|
|
└── /socios
|
|
├── /clientes
|
|
│ └── CustomersList.tsx
|
|
│ └── ListViewTemplate.tsx
|
|
│ ├── SearchInput.tsx
|
|
│ ├── PrimaryButton.tsx
|
|
│ ├── DenseTable.tsx
|
|
│ └── PaginationBar.tsx
|
|
├── /clientes/mantenimiento
|
|
│ └── Customers.tsx
|
|
│ └── BusinessPartnerForm.tsx (cardType="cCustomer")
|
|
├── /proveedores
|
|
│ └── SuppliersList.tsx
|
|
│ └── ListViewTemplate.tsx (mismo árbol que CustomersList)
|
|
└── /proveedores/mantenimiento
|
|
└── Suppliers.tsx
|
|
└── BusinessPartnerForm.tsx (cardType="cSupplier", extraFields=[U_EXX_TIPODOCU])
|
|
```
|
|
|
|
## Campos del Formulario
|
|
|
|
A diferencia del módulo de Lotes, acá **no hay mapeo de nombres SAP → amigable**: el formulario usa los nombres de campo de SAP directamente como `name` de cada input (`CardCode`, `CardName`, `FederalTaxID`, `Phone1`, `EmailAddress`).
|
|
|
|
| Campo SAP | Pestaña | Tipo | Notas |
|
|
| ------------------------- | ------------ | ------------------------------ | ------------------------------------------------------------- |
|
|
| `CardCode` | General | input text (solo lectura en edición) | Llave primaria en SAP; no editable una vez creado el socio |
|
|
| `CardName` | General | input text | Razón social / nombre |
|
|
| `CardType` | General | fijo, no editable en UI | `cCustomer` o `cSupplier` según el wrapper usado |
|
|
| `FederalTaxID` | General | input text | RUC / documento de identidad |
|
|
| `Phone1` | General | input text | Teléfono principal |
|
|
| `EmailAddress` | General | input email | Correo |
|
|
| `U_EXX_TIPODOCU` | General | select (dinámico, solo Proveedores) | Catálogo SUNAT vía `/api/Sunat/BusinessPartners/DocumentType` |
|
|
| `BPAddresses[].Street`, `City`, `County`, `GlobalLocationNumber` | Direcciones | input text | Dos direcciones por defecto: `bo_BillTo` (Facturación) y `bo_ShipTo` (Despacho) |
|
|
|
|
## Archivos Clave
|
|
|
|
| Archivo | Ruta | Propósito |
|
|
| ------------------------- | --------------------------------- | --------------------------------------------------------------------------- |
|
|
| `BusinessPartnerForm.tsx` | `src/components/` | Formulario genérico único para Clientes y Proveedores, parametrizable |
|
|
| `Customers.tsx` | `src/views/socios/` | Wrapper que configura `BusinessPartnerForm` para `cCustomer` |
|
|
| `Suppliers.tsx` | `src/views/socios/` | Wrapper que configura `BusinessPartnerForm` para `cSupplier` + campo SUNAT |
|
|
| `CustomersList.tsx` | `src/views/socios/` | Lista de clientes, filtra `CardType eq 'cCustomer'` |
|
|
| `SuppliersList.tsx` | `src/views/socios/` | Lista de proveedores, filtra `CardType eq 'cSupplier'` |
|
|
| `ListViewTemplate.tsx` | `src/components/ui/` | Template genérico de listado con paginación/búsqueda/filtros |
|
|
| `api.ts` | `src/utils/` | Cliente HTTP con sesión, token, timeout |
|
|
| `business_partners.py` | `mini-backend/routers/` | Router CRUD genérico (`make_crud_router("BusinessPartners", key_field="CardCode")`) |
|
|
| `crud_router.py` | `mini-backend/core/` | Factory que genera GET/POST/PATCH proxificados hacia SAP |
|
|
| `sap.py` | `mini-backend/core/` | Proxy universal a SAP Service Layer |
|