primer commit
This commit is contained in:
1 parent
ab3c613165
commit
b2fb4e2d0a
18 files changed
+1291
-277
No files matched your search
@@ -0,0 +1,172 @@
|
||||
# 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 |
|
||||
Reference in new issue
Block a user