12 KiB
API Reference
Base URL:
http://<host>:8000API Version: 1.1.0 Content-Type:application/json
Headers Globales
| Header | Requerido | Descripción |
|---|---|---|
Content-Type |
Sí | application/json |
X-Session-Token |
Sí (excepto /api/Login) |
Token obtenido en el login |
X-Request-ID |
Opcional | UUID para trazabilidad; si no se envía, el servidor lo genera |
Formato de Errores
Todas las respuestas de error siguen el mismo formato:
{
"detail": "Mensaje de error de SAP o del servidor"
}
| Código | Significado |
|---|---|
| 400 | Error de negocio SAP (ej: código duplicado, validación fallida) |
| 401 | Token inválido/expirado, o credenciales incorrectas |
| 404 | Recurso no encontrado en SAP |
| 500 | Error de conexión con SAP o error interno |
Autenticación
POST /api/Login
Inicia sesión de empleado. Busca en SAP EmployeesInfo al empleado cuyo
campo de usuario U_WEB_USER coincida con Username, y valida Password
contra su campo U_WEB_PASS. También exige que el empleado esté activo
(Active == "tYES").
Request body:
{
"Username": "jgarcia",
"Password": "********"
}
Response 200:
{
"message": "Login exitoso",
"token": "aB3x...token_urlsafe_32_chars...",
"username": "Juan",
"company": "NOMBRE_COMPANYDB"
}
Response 401:
{
"detail": "Usuario o contraseña incorrectos"
}
Otros posibles detail en 401: "Usuario no registrado" (no existe ningún
empleado con ese U_WEB_USER) y "Usuario inactivo" (el empleado existe
pero Active != "tYES").
POST /api/Logout
Cierra la sesión del empleado.
Headers: X-Session-Token: <token>
Response 200:
{
"message": "Logout exitoso"
}
Socios de Negocio
GET /api/BusinessPartners
Lista paginada de socios de negocio.
Query parameters:
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
skip |
int | 0 | Registros a saltar ($skip) |
top |
int | 50 | Registros por página ($top) |
fields |
string | — | Campos a retornar, separados por coma ($select) |
filter |
string | — | Filtro OData ($filter). Activa B1S-CaseInsensitive |
Response 200:
{
"odata.metadata": "https://.../$metadata#BusinessPartners",
"value": [
{
"CardCode": "C001",
"CardName": "Cliente Demo",
"CardType": "C"
}
],
"odata.count": 150
}
GET /api/BusinessPartners/{bp_code}
Obtiene un socio de negocio por CardCode.
Response 200:
{
"CardCode": "C001",
"CardName": "Cliente Demo",
"CardType": "C",
"Phone1": "123456789",
"EmailAddress": "cliente@demo.com"
}
POST /api/BusinessPartners
Crea un nuevo socio de negocio.
Request body:
{
"CardCode": "C001",
"CardName": "Cliente Demo",
"CardType": "C"
}
Response 201:
{
"CardCode": "C001"
}
PATCH /api/BusinessPartners/{bp_code}
Actualiza un socio de negocio existente.
Request body:
{
"CardName": "Nuevo Nombre",
"Phone1": "987654321"
}
Response 204: Sin contenido.
Artículos
GET /api/Items
Lista paginada de artículos.
Query parameters:
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
skip |
int | 0 | Registros a saltar |
top |
int | 50 | Registros por página |
fields |
string | — | Campos a retornar ($select) |
filter |
string | — | Filtro OData ($filter) |
Response 200:
{
"odata.metadata": "https://.../$metadata#Items",
"value": [
{
"ItemCode": "A001",
"ItemName": "Artículo Demo",
"InventoryUOM": "UN"
}
],
"odata.count": 250
}
GET /api/Items/{item_code}
Obtiene un artículo por ItemCode.
Response 200:
{
"ItemCode": "A001",
"ItemName": "Artículo Demo",
"InventoryUOM": "UN",
"SalesPrice": 100.50
}
POST /api/Items
Crea un nuevo artículo.
Request body:
{
"ItemCode": "A001",
"ItemName": "Artículo Demo",
"InventoryUOM": "UN"
}
Response 201:
{
"ItemCode": "A001"
}
PATCH /api/Items/{item_code}
Actualiza un artículo existente.
Request body:
{
"ItemName": "Nuevo Nombre",
"SalesPrice": 120.00
}
Response 204: Sin contenido.
Ventas
Facturas (A/R Invoices)
GET /api/Invoices
Lista paginada de facturas de venta.
Query parameters:
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
skip |
int | 0 | Registros a saltar |
top |
int | 50 | Registros por página |
fields |
string | — | Campos a retornar |
filter |
string | — | Filtro OData |
orderby |
string | — | Ordenamiento ($orderby) |
Response 200:
{
"odata.metadata": "https://.../$metadata#Invoices",
"value": [
{
"DocEntry": 1001,
"CardCode": "C001",
"DocTotal": 1500.00,
"DocDate": "2026-07-06"
}
],
"odata.count": 45
}
POST /api/Invoices
Crea una factura de venta.
Response 201:
{
"DocEntry": 1001
}
GET /api/Invoices/{invoice_key}
Obtiene una factura por DocEntry.
PATCH /api/Invoices/{invoice_key}
Actualiza una factura. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Pedidos (Sales Orders)
GET /api/Orders
Lista paginada de pedidos de venta. Mismos parámetros que Invoices.
POST /api/Orders
Crea un pedido de venta.
Response 201:
{
"DocEntry": 2001
}
GET /api/Orders/{order_key}
Obtiene un pedido por DocEntry.
PATCH /api/Orders/{order_key}
Actualiza un pedido. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Guías de Remisión de Venta (Delivery Notes)
GET /api/DeliveryNotes
Lista paginada de guías de remisión de venta. Mismos parámetros que Invoices/Orders.
POST /api/DeliveryNotes
Crea una guía de remisión de venta.
Response 201:
{
"DocEntry": 3001
}
GET /api/DeliveryNotes/{key}
Obtiene una guía de remisión por DocEntry.
PATCH /api/DeliveryNotes/{key}
Actualiza una guía de remisión. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Compras
Órdenes de Compra
GET /api/PurchaseOrders
Lista paginada. Mismos parámetros que Invoices/Orders.
POST /api/PurchaseOrders
Crea una orden de compra.
Response 201:
{
"DocEntry": 4001
}
GET /api/PurchaseOrders/{key}
Obtiene una orden de compra por DocEntry.
PATCH /api/PurchaseOrders/{key}
Actualiza una orden de compra. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Facturas de Compra (A/P Invoices)
GET /api/PurchaseInvoices
Lista paginada. Mismos parámetros que Invoices/Orders.
POST /api/PurchaseInvoices
Crea una factura de compra.
Response 201:
{
"DocEntry": 4501
}
GET /api/PurchaseInvoices/{key}
Obtiene una factura de compra por DocEntry.
PATCH /api/PurchaseInvoices/{key}
Actualiza una factura de compra. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Guías de Recepción de Compra (Purchase Delivery Notes)
GET /api/PurchaseDeliveryNotes
Lista paginada. Mismos parámetros que Invoices/Orders.
POST /api/PurchaseDeliveryNotes
Crea una guía de recepción de compra.
Response 201:
{
"DocEntry": 5001
}
GET /api/PurchaseDeliveryNotes/{key}
Obtiene una guía de recepción de compra por DocEntry.
PATCH /api/PurchaseDeliveryNotes/{key}
Actualiza una guía de recepción de compra. Usa header B1S-ReplaceCollectionsOnPatch: true.
Response 204: Sin contenido.
Catálogos
GET /api/Currencies
Lista de monedas.
Response 200:
{
"value": [
{ "Code": "USD", "Name": "US Dollar" },
{ "Code": "EUR", "Name": "Euro" }
]
}
GET /api/BusinessPartnerGroups
Lista de grupos de socios de negocio.
Response 200:
{
"value": [
{ "Number": 1, "GroupName": "Clientes Nacionales" }
]
}
GET /api/Warehouses
Lista paginada de almacenes. Acepta skip, top, fields, filter.
GET /api/ItemGroups
Lista de grupos de artículos.
Response 200:
{
"value": [
{ "Number": 1, "GroupName": "Materia Prima" }
]
}
GET /api/SalesTaxCodes
Lista paginada de códigos de IVA. Acepta skip, top, fields, filter.
GET /api/FactoringIndicators
Lista paginada de indicadores de factoring. Acepta skip, top, fields, filter.
GET /api/Sunat/BusinessPartners/DocumentType
Lista los valores del campo de usuario EXX_TIPODOCU (tabla OCRD, tipo de
documento SUNAT del socio de negocio), consultando UserFieldsMD en SAP.
Endpoint fijo, sin parámetros de paginación.
Response 200:
{
"value": [
{ "FieldID": 1, "Description": "DNI" },
{ "FieldID": 2, "Description": "RUC" }
]
}
Lotes
GET /api/BatchNumberDetails
Lista paginada de lotes/números de serie. Acepta skip, top, fields, filter, orderby.
GET /api/BatchNumberDetails/{batch_id}
Obtiene un lote por ID.
PATCH /api/BatchNumberDetails/{batch_id}
Actualiza un lote.
Response 204: Sin contenido.
Permisos
GET /api/user/menu
Retorna las rutas de menú permitidas para el empleado autenticado.
Headers: X-Session-Token: <token>
Response 200:
{
"allowedPaths": [
"/inventario/*",
"/ventas/*",
"/compras/*"
]
}
Response 401:
{
"detail": "Usuario no autenticado"
}
Reportes (API Gateway — Crystal Reports)
Estos endpoints no van contra el Service Layer sino contra el SAP API
Gateway (core/api_gateway.py), que expone los reportes Crystal Reports
autorizados para la compañía.
GET /api/apigateway/reports
Lista los reportes Crystal Reports autorizados para el usuario/compañía.
Response 200:
[
{ "DocCode": "R001", "DocName": "Guía de Remisión" }
]
GET /api/apigateway/reports/{docCode}/parameters
Obtiene los parámetros de entrada que requiere un reporte puntual (por
DocCode) antes de exportarlo.
POST /api/apigateway/reports/{docCode}/export
Exporta el reporte a PDF. El body es la lista de parámetros que el reporte necesita (formato definido por el propio API Gateway / Crystal Reports).
Request body:
[
{ "name": "DocEntry", "value": "1001" }
]
Response 200: application/pdf (streaming, Content-Disposition: inline).
Reportes (Jinja/HTML → PDF)
Generados desde plantillas HTML propias (templates/reports/) renderizadas
con Jinja2 y convertidas a PDF con WeasyPrint, a partir de datos consultados
directamente en HANA (core/hana.py), sin pasar por el Service Layer.
POST /api/reports/stickers
Genera el sticker de una guía de remisión de venta (DeliveryNotes) para
imprimir etiquetas de despacho.
Request body:
{
"doc_entry": 3001,
"cantidad": 4,
"formato": "pdf",
"papel": "Carta"
}
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
doc_entry |
int | Sí | DocEntry de la guía de remisión en HANA |
cantidad |
int | Sí | Cantidad de stickers a generar |
formato |
"pdf" | "html" |
No (default "pdf") |
Formato de salida |
papel |
"A4" | "Carta" |
No (default "Carta") |
Tamaño de papel del PDF |
Response 200: application/pdf o text/html según formato, streaming.
Response 404:
{
"detail": "No se encontró el documento 3001"
}
Response 500: error al consultar HANA.
Resumen de Códigos de Respuesta
| Método | Éxito | Cuerpo en éxito | Error SAP | Error de conexión |
|---|---|---|---|---|
| GET | 200 | JSON del recurso | 4xx con detail |
500 |
| POST | 201 | {"CardCode"/"ItemCode"/"DocEntry": valor} |
4xx con detail |
500 |
| PATCH | 204 | Sin cuerpo | 4xx con detail |
500 |