# Arquitectura General ## Diagrama de Componentes ```mermaid graph TB subgraph "FastAPI Application" M[main.py\nEntry Point] C[context.py\nRequest ID Context] L[logger_config.py\nStructured Logging] subgraph "Core" SAP[core/sap.py\nSAP Session & Proxy] SES[core/session.py\nEmployee Sessions] end subgraph "Routers" A[auth.py\nLogin / Logout] BP[business_partners.py\nSocios de Negocio] IT[items.py\nArtículos] SL[sales.py\nFacturas / Pedidos] PR[purchases.py\nÓrdenes / Facturas Compra] CT[catalogs.py\nCatálogos] BT[batch.py\nLotes] PM[permissions.py\nPermisos de Menú] end MP[menu_permissions.json] end subgraph "External" SAP_SL[SAP B1 Service Layer] end M --> C M --> L C --> L M --> A M --> BP M --> IT M --> SL M --> PR M --> CT M --> BT M --> PM A --> SAP A --> SES BP --> SAP IT --> SAP SL --> SAP PR --> SAP CT --> SAP BT --> SAP PM --> MP SAP --> SAP_SL SES --> SAP ``` ## Pipeline de Middleware Las peticiones atraviesan los siguientes middleware en orden: ```mermaid flowchart LR REQ[Request] --> CORS[CORSMiddleware\nallow_origins=*] CORS --> CID[correlation_id_middleware\nX-Request-ID] CID --> SES_MW[session_middleware\nValida X-Session-Token] SES_MW --> ROUTER{Router} ROUTER -->|/api/Login| A[auth.py] ROUTER -->|Otros /api/*| SAP_CORE[core/sap.py] ``` ### Detalle de Middleware | Middleware | Función | | -------------------------- | ----------------------------------------------------------- | | `CORSMiddleware` | Permite peticiones desde cualquier origen | | `correlation_id_middleware` | Genera o extrae `X-Request-ID` para trazabilidad en logs | | `session_middleware` | Valida token de sesión, adjunta `emp_id` a `request.state` | ## Arquitectura de Sesiones Existen **dos capas de sesión independientes**: ```mermaid flowchart LR subgraph Employee["Employee Session"] T["Token aleatorio → emp_id"] E["employee_sessions dict"] TK["active_tokens dict"] T --> TK TK --> E end subgraph SAP["SAP B1 Session"] S["sap_session_store"] M["Manager Credentials (.env)"] S -.->|Renueva en 401| M end ``` | Capa | Almacenamiento | Ámbito | Timeout | Renovación | | ------------- | ----------------- | -------- | ------------- | -------------------- | | SAP B1 | `sap_session_store` | Global | Gestionado SAP | Automática al recibir 401 | | Empleado | `active_tokens` | Por empleado | 30 min inactividad | Login manual | ## Estructura de Rutas | Método | Ruta | Router | Descripción | | -------- | --------------------------------- | -------------------- | ------------------------ | | `POST` | `/api/Login` | `auth.py` | Autenticar empleado | | `POST` | `/api/Logout` | `auth.py` | Cerrar sesión | | `GET` | `/api/BusinessPartners` | `business_partners` | Listar socios | | `GET` | `/api/BusinessPartners/{code}` | `business_partners` | Obtener socio | | `POST` | `/api/BusinessPartners` | `business_partners` | Crear socio | | `PATCH` | `/api/BusinessPartners/{code}` | `business_partners` | Actualizar socio | | `GET` | `/api/Items` | `items.py` | Listar artículos | | `GET` | `/api/Items/{code}` | `items.py` | Obtener artículo | | `POST` | `/api/Items` | `items.py` | Crear artículo | | `PATCH` | `/api/Items/{code}` | `items.py` | Actualizar artículo | | `GET` | `/api/Invoices` | `sales.py` | Listar facturas | | `GET` | `/api/Invoices/{key}` | `sales.py` | Obtener factura | | `POST` | `/api/Invoices` | `sales.py` | Crear factura | | `PATCH` | `/api/Invoices/{key}` | `sales.py` | Actualizar factura | | `GET` | `/api/Orders` | `sales.py` | Listar pedidos | | `GET` | `/api/Orders/{key}` | `sales.py` | Obtener pedido | | `POST` | `/api/Orders` | `sales.py` | Crear pedido | | `PATCH` | `/api/Orders/{key}` | `sales.py` | Actualizar pedido | | `GET` | `/api/PurchaseOrders` | `purchases.py` | Listar órdenes de compra | | `GET` | `/api/PurchaseOrders/{key}` | `purchases.py` | Obtener orden de compra | | `PATCH` | `/api/PurchaseOrders/{key}` | `purchases.py` | Actualizar orden compra | | `GET` | `/api/PurchaseInvoices` | `purchases.py` | Listar facturas compra | | `GET` | `/api/PurchaseInvoices/{key}` | `purchases.py` | Obtener factura compra | | `PATCH` | `/api/PurchaseInvoices/{key}` | `purchases.py` | Actualizar factura compra| | `GET` | `/api/Currencies` | `catalogs.py` | Listar monedas | | `GET` | `/api/BusinessPartnerGroups` | `catalogs.py` | Listar grupos de socios | | `GET` | `/api/Warehouses` | `catalogs.py` | Listar almacenes | | `GET` | `/api/ItemGroups` | `catalogs.py` | Listar grupos artículos | | `GET` | `/api/SalesTaxCodes` | `catalogs.py` | Listar códigos de IVA | | `GET` | `/api/BatchNumberDetails` | `batch.py` | Listar lotes | | `GET` | `/api/BatchNumberDetails/{id}` | `batch.py` | Obtener lote | | `PATCH` | `/api/BatchNumberDetails/{id}` | `batch.py` | Actualizar lote | | `GET` | `/api/user/menu` | `permissions.py` | Obtener menú permitido | ## Dependencias del Proyecto ```mermaid graph TD main --> context main --> logger_config logger_config --> context main --> auth main --> business_partners main --> items main --> sales main --> purchases main --> catalogs main --> batch main --> permissions auth --> sap_core auth --> session_core business_partners --> sap_core items --> sap_core sales --> sap_core purchases --> sap_core catalogs --> sap_core batch --> sap_core permissions --> menu_json[menu_permissions.json] ``` ## Configuración por Entorno La aplicación carga siempre `.env` (un solo archivo, sin sufijos de entorno). `.env.aberio` se conserva como plantilla de referencia; para desplegar contra ese entorno, copiar su contenido dentro de `.env`. | Archivo | URL SAP | Company DB | | ------------------ | ------------------------------- | ----------------------- | | `.env` | `192.168.1.175:50000` | `SBO_PRUEBA_TAGUM_22` | | `.env.aberio` | `192.168.9.3:50000` | `PRUEBA_20260609` |