Files
mini-erp/mini-backend/docs/api-reference.md
T
GeorgeandClaude Sonnet 5 ab3c613165 Initial commit: mini-erp (backend FastAPI + frontend React/Vite)
Base para el flujo de ramas por cliente.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 10:34:12 -05:00

527 lines
8.1 KiB
Markdown

# API Reference
> **Base URL:** `http://<host>:8000`
> **API 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:
```json
{
"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. Valida contra SAP EmployeesInfo usando el apellido como contraseña.
**Request body:**
```json
{
"Username": "123",
"Password": "Garcia"
}
```
**Response 200:**
```json
{
"message": "Login exitoso",
"token": "aB3x...token_urlsafe_32_chars...",
"username": "Juan"
}
```
**Response 401:**
```json
{
"detail": "Usuario o contraseña incorrectos"
}
```
---
### `POST /api/Logout`
Cierra la sesión del empleado.
**Headers:** `X-Session-Token: <token>`
**Response 200:**
```json
{
"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:**
```json
{
"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:**
```json
{
"CardCode": "C001",
"CardName": "Cliente Demo",
"CardType": "C",
"Phone1": "123456789",
"EmailAddress": "cliente@demo.com"
}
```
---
### `POST /api/BusinessPartners`
Crea un nuevo socio de negocio.
**Request body:**
```json
{
"CardCode": "C001",
"CardName": "Cliente Demo",
"CardType": "C"
}
```
**Response 201:**
```json
{
"CardCode": "C001"
}
```
---
### `PATCH /api/BusinessPartners/{bp_code}`
Actualiza un socio de negocio existente.
**Request body:**
```json
{
"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:**
```json
{
"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:**
```json
{
"ItemCode": "A001",
"ItemName": "Artículo Demo",
"InventoryUOM": "UN",
"SalesPrice": 100.50
}
```
---
### `POST /api/Items`
Crea un nuevo artículo.
**Request body:**
```json
{
"ItemCode": "A001",
"ItemName": "Artículo Demo",
"InventoryUOM": "UN"
}
```
**Response 201:**
```json
{
"ItemCode": "A001"
}
```
---
### `PATCH /api/Items/{item_code}`
Actualiza un artículo existente.
**Request body:**
```json
{
"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:**
```json
{
"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:**
```json
{
"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:**
```json
{
"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.
---
## Compras
### Órdenes de Compra
#### `GET /api/PurchaseOrders`
Lista paginada. Mismos parámetros que Invoices/Orders.
#### `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.
#### `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.
---
## Catálogos
### `GET /api/Currencies`
Lista de monedas.
**Response 200:**
```json
{
"value": [
{ "Code": "USD", "Name": "US Dollar" },
{ "Code": "EUR", "Name": "Euro" }
]
}
```
---
### `GET /api/BusinessPartnerGroups`
Lista de grupos de socios de negocio.
**Response 200:**
```json
{
"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:**
```json
{
"value": [
{ "Number": 1, "GroupName": "Materia Prima" }
]
}
```
---
### `GET /api/SalesTaxCodes`
Lista paginada de códigos de IVA. Acepta `skip`, `top`, `fields`, `filter`.
---
## 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:**
```json
{
"allowedPaths": [
"/inventario/*",
"/ventas/*",
"/compras/*"
]
}
```
**Response 401:**
```json
{
"detail": "Usuario no autenticado"
}
```
---
## 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 |