# Flujo de Proxy SAP ## Función Central: `forward_to_sapb1` Todas las operaciones CRUD pasan por esta función en `core/sap.py`, que actúa como proxy hacia SAP Service Layer. ```mermaid flowchart TD START([Inicio]) --> INPUT["method, endpoint_path,\njson_data, params, headers"] INPUT --> BUILD["Construye URL:\nSAPB1_SL_URL / endpoint_path"] BUILD --> HEADERS["Adjunta headers:\nCookie: B1SESSION=...\nContent-Type: application/json"] HEADERS --> SEND[Envía request a SAP] SEND --> CHECK{Respuesta} CHECK -->|2xx| SUCCESS[Retorna Response al router] CHECK -->|401| REFRESH["Force refresh:\nensure_sap_session()"] CHECK -->|Timeout / Error| FAIL[ConnectionError] REFRESH --> RETRY{Es reintento?} RETRY -->|No| SEND2["Reintenta request\ncon nueva sesión"] RETRY -->|Sí| ERROR["Extrae error.message.value\nde SAP y lanza HTTPException"] SEND2 --> CHECK2{Respuesta} CHECK2 -->|2xx| SUCCESS CHECK2 -->|4xx/5xx| ERROR SUCCESS --> END([Fin]) FAIL --> END ERROR --> END style ERROR fill:#f96,stroke:#a33 ``` ## Diagrama de Secuencia — Operación CRUD Típica Ejemplo con `GET /api/Items`: ```mermaid sequenceDiagram participant F as Frontend participant MW as Middleware participant R as router/items.py participant C as core/sap.py participant SAP as SAP Service Layer F->>MW: GET /api/Items?$skip=0&$top=20\nX-Session-Token: [token] MW->>MW: Valida sesión MW->>R: request.state.emp_id = "123" R->>C: forward_to_sapb1(\n GET, "Items?$skip=0&$top=20&$inlinecount=allpages") C->>SAP: GET /b1s/v1/Items?$skip=0&$top=20\nCookie: B1SESSION=abc123 SAP-->>C: 200 - value: [...], odata.count: 150 C-->>R: Response R-->>F: 200 - data: [...], total: 150 ``` ## Re-autenticación Automática ante 401 Cuando SAP rechaza la sesión actual (401), el sistema renueva automáticamente la sesión de SAP y reintenta: ```mermaid sequenceDiagram participant R as Router participant C as core/sap.py participant SAP as SAP Service Layer R->>C: forward_to_sapb1(GET, "Items?...") C->>SAP: GET /b1s/v1/Items?...\nCookie: B1SESSION=abc123 SAP-->>C: 401 Unauthorized Note over C: Sesión SAP expirada\n→ Re-autentica y reintenta C->>SAP: POST /Login\nUserName: manager, Password: ..., CompanyDB: ... SAP-->>C: 200 SessionId: xyz789 C->>C: Actualiza sap_session_store C->>SAP: GET /b1s/v1/Items?...\nCookie: B1SESSION=xyz789 SAP-->>C: 200 - value: [...] C-->>R: Response 200 Note over R,C: Si el reintento también falla (4xx/5xx)\n→ se extrae error.message.value\n→ se lanza HTTPException ``` ## Parámetros OData y Headers SAP Soportados ### Query Parameters (OData) | Parámetro | Uso | Ejemplo | | -------------- | ---------------------------------- | -------------------------------- | | `$skip` | Paginación — desplazamiento | `$skip=20` | | `$top` | Paginación — límite por página | `$top=20` | | `$select` | Selección de campos | `$select=ItemCode,ItemName` | | `$filter` | Filtrado | `$filter=ItemCode eq 'A001'` | | `$orderby` | Ordenamiento | `$orderby=ItemCode asc` | | `$inlinecount` | Contar registros totales | `$inlinecount=allpages` | ### Headers SAP | Header | Función | | ----------------------------- | ----------------------------------------- | | `B1S-PageSize` | Tamaño de página personalizado | | `B1S-CaseInsensitive` | Búsqueda sin distinción mayúsc/minúscula | | `B1S-ReplaceCollectionsOnPatch` | Reemplazar colecciones completas en PATCH | ## Manejo de Errores | Situación | Comportamiento | | ----------------------- | ---------------------------------------------------------- | | SAP devuelve 2xx | Retorna `Response` al router (200 body, 201 body, 204 vacío) | | SAP devuelve 401 | Re-autentica automáticamente y reintenta 1 vez | | SAP devuelve 4xx/5xx | Extrae `error.message.value` y lanza `HTTPException(status_code, detail)` | | Timeout de conexión | Lanza `ConnectionError` | | Error de red | Lanza `ConnectionError` | | Reintento también falla | Lanza `HTTPException` con el mensaje de error SAP | | SAP no disponible | `HTTPException(500)` |