# 🧠 MANUAL DE INTEGRACIÓN Y DOCUMENTACIÓN TÉCNICA - API IA (ApiControllerIa)
### PosCloud V12 - Sistema de Inteligencia Artificial y Servicios REST

> **Destinatarios:** Desarrolladores Backend, Frontend, Integradores de Software, Agentes de IA, Bots de Automatización (n8n, Make, Flowise, Custom GPTs).  
> **Controlador Principal:** [`app/Http/Controllers/ApiControllerIa.php`](file:///c:/xampp/htdocs/Admin_PosCloud_V12/app/Http/Controllers/ApiControllerIa.php)  
> **Archivo de Rutas:** [`routes/api.php`](file:///c:/xampp/htdocs/Admin_PosCloud_V12/routes/api.php) (Grupo de rutas con prefijo `ia`)  
> **Versión del Framework:** Laravel 11 / PHP 8.2+  
> **Fecha de Actualización:** Septiembre 2026

---

## 📑 TABLA DE CONTENIDO

1. [Arquitectura y Conceptos Clave](#1-arquitectura-y-conceptos-clave)
2. [Autenticación y Conexión Multi-Empresa (Tenant)](#2-autenticación-y-conexión-multi-empresa-tenant)
3. [Convenciones Globales de la API](#3-convenciones-globales-de-la-api)
4. [Matriz Rápida de Endpoints](#4-matriz-rápida-de-endpoints)
5. [Documentación Detallada de Servicios](#5-documentación-detallada-de-servicios)
   - [5.1 `GET /api/ia/inventario` (Inventario en Tiempo Real)](#51-get-api-ia-inventario-inventario-en-tiempo-real)
   - [5.2 `GET /api/ia/inventario-cambios` (Inventario Modificado Hoy / Delta)](#52-get-api-ia-inventario-cambios-inventario-modificado-hoy--delta)
   - [5.3 `GET /api/ia/ventas` (Estadísticas Financieras y KPIs)](#53-get-api-ia-ventas-estadísticas-financieras-y-kpis)
   - [5.4 `GET /api/ia/rotacion` (Rotación Física en Cajas y Fracciones)](#54-get-api-ia-rotacion-rotación-física-en-cajas-y-fracciones)
   - [5.5 `POST /api/ia/traslados` (Crear Movimiento de Traslado)](#55-post-api-ia-traslados-crear-movimiento-de-traslado)
   - [5.6 `POST /api/ia/traslados/guardar` (Cerrar Consecutivo de Traslado)](#56-post-api-ia-trasladosguardar-cerrar-consecutivo-de-traslado)
   - [5.7 `POST /api/ia/traslados/lote` (Múltiples Traslados en Lote)](#57-post-api-ia-trasladoslote-múltiples-traslados-en-lote)
   - [5.8 `POST /api/ia/traslados/ejecutar-sugeridos` (Ejecución Automática de Traslados)](#58-post-api-ia-trasladosejecutar-sugeridos-ejecución-automática-de-traslados)
   - [5.9 `GET /api/ia/clientes` (Consulta y Búsqueda de Clientes)](#59-get-api-ia-clientes-consulta-y-búsqueda-de-clientes)
   - [5.10 `POST /api/ia/clientes` (Crear / Registrar Cliente)](#510-post-api-ia-clientes-crear--registrar-cliente)
   - [5.11 `GET /api/ia/ventas-clientes` (Ventas Detalladas por Cliente)](#511-get-api-ia-ventas-clientes-ventas-detalladas-por-cliente)
6. [Servicio Complementario: Motor de Sugerencias de Traslado](#6-servicio-complementario-motor-de-sugerencias-de-traslado)
7. [Manejo de Errores y Códigos de Estado HTTP](#7-manejo-de-errores-y-códigos-de-estado-http)
8. [Ejemplos de Consumo en Código (cURL, JavaScript, Python, PHP)](#8-ejemplos-de-consumo-en-código)

---

## 1. ARQUITECTURA Y CONCEPTOS CLAVE

El controlador `ApiControllerIa` fue diseñado para servir como el **núcleo de integración analítico, transaccional y de datos** entre el sistema POS PosCloud V12 y plataformas externas (Inteligencia Artificial, CRM, ERP, tableros BI, apps móviles y automatizaciones).

### ¿Por qué se encuentra bajo el prefijo `/api/ia`?
En Laravel 11 (`bootstrap/app.php`), todas las rutas declaradas en `routes/api.php` reciben automáticamente el prefijo `/api`. A su vez, `routes/api.php` agrupa estos endpoints dentro del grupo:

```php
Route::group(['prefix' => 'ia'], function () {
    // Endpoints de ApiControllerIa
});
```
Por lo tanto, la URL base absoluta para todos los servicios de este controlador es:
```text
https://tu-servidor-poscloud.com/api/ia/{endpoint}
```

---

## 2. AUTENTICACIÓN Y CONEXIÓN MULTI-EMPRESA (TENANT)

El sistema opera bajo una arquitectura **Multi-Tenant dinámica**. Cada cliente o sucursal tiene su propia base de datos MySQL aislada.

### Mecanismo de Conexión Dinámica (`setDynamicConnection`)
Al recibir una petición, el controlador extrae el token de seguridad y conmuta la conexión MySQL en tiempo de ejecución:

```mermaid
flowchart TD
    Req[Cliente HTTP / Desarrollador] -->|Petición con Token| Route[Route: /api/ia/*]
    Route --> Controller[ApiControllerIa]
    Controller --> CheckToken{¿Token Válido?}
    CheckToken -- No --> Ret401[HTTP 401: Token inválido o no autorizado]
    CheckToken -- Sí --> SwitchDB[DB::purge & DB::reconnect a BD del Tenant]
    SwitchDB --> Exec[Ejecuta Consulta / Transacción SQL]
    Exec --> Res[Retorna JSON al Desarrollador]
```

### ¿Cómo enviar el Token?
Puedes utilizar cualquiera de las siguientes 2 opciones:

1. **Opción A (Estándar recomendada - Header HTTP):**
   ```http
   Authorization: Bearer TU_TOKEN_DE_EMPRESA
   ```

2. **Opción B (Query String o Body Parameter):**
   ```text
   GET /api/ia/inventario?token=TU_TOKEN_DE_EMPRESA
   ```

> ⚠️ **Configuración de Tokens:** Los tokens y sus credenciales de base de datos se configuran dentro de la función privada `setDynamicConnection()` en `ApiControllerIa.php`. Si tu token no está registrado o está vencido, la API responderá con estado `401 Unauthorized`.

---

## 3. CONVENCIONES GLOBALES DE LA API

- **Formato de Petición:** JSON (`Content-Type: application/json`) o Form-Data / Query Parameters según el método.
- **Formato de Respuesta:** Siempre JSON (`Content-Type: application/json; charset=utf-8`).
- **Codificación:** UTF-8.
- **Formato de Fechas:** Estándar ISO `YYYY-MM-DD` (ej. `2026-09-23`) o `YYYY-MM-DD HH:MM:SS` para marcas de tiempo completas.
- **Unidades de Medida:**
  - `inventario` y `cajas`: Cantidad entera o decimal de cajas cerradas.
  - `fracciones` / `frcc`: Cantidad de unidades sueltas / pastillas / fracciones.
  - `factor`: Cantidad de fracciones que contiene una caja completa (ej. caja de 100 tabletas tiene factor = 100).
  - `total_fracciones_equivalentes = (cajas * factor) + fracciones`.
- **Moneda:** Pesos Colombianos (COP) redondeados a 2 decimales.

---

## 4. MATRIZ RÁPIDA DE ENDPOINTS

| # | Método | Ruta del Endpoint | Función del Controlador | Propósito Principal |
| :-: | :---: | :--- | :--- | :--- |
| **1** | `GET` | `/api/ia/inventario` | `getInventario` | Catálogo de existencias en tiempo real con precios 1, 2 y 3, costos y stock > 0. |
| **2** | `GET` | `/api/ia/inventario-cambios`| `getInventarioCambios` | Consulta de inventario delta (solo productos modificados hoy o desde fecha X). |
| **3** | `GET` | `/api/ia/ventas` | `getVentas` | Reporte financiero de ventas en dinero, costos, margen, IVA y gráficos por dimensión. |
| **4** | `GET` | `/api/ia/rotacion` | `getRotacion` | Cálculo exacto de demanda física (cajas, fracciones, frecuencia de venta y stock). |
| **5** | `POST` | `/api/ia/traslados` | `crearTraslado` | Movimiento de traslado (descuenta origen, suma a destino y valida stock). |
| **6** | `POST` | `/api/ia/traslados/guardar` | `guardarTraslado` | Asignación y cierre del consecutivo numerado del traslado. |
| **7** | `POST` | `/api/ia/traslados/lote` | `crearTrasladosLote` | Creación y cierre masivo de múltiples rutas de traslado en un solo viaje. |
| **8** | `POST` | `/api/ia/traslados/ejecutar-sugeridos` | `ejecutarSugeridosLote` | Motor autónomo que calcula desabastecimientos y traslada automáticamente. |
| **9** | `GET` | `/api/ia/clientes` | `getClientes` | Directorio de clientes con filtros por cédula, teléfono, nombre y paginación. |
| **10**| `POST` | `/api/ia/clientes` | `crearCliente` | Alta de clientes en el sistema POS con datos DIAN, comerciales y de contacto. |
| **11**| `GET` | `/api/ia/ventas-clientes` | `getVentasClientes` | Detalle analítico de compras netas por cliente (restando devoluciones). |
| *Extra* | `GET` | `/api/ia/sugerido-traslados`| `SugerenciaTrasladosController` | Motor matemático de sugerencias entre bodegas donantes y receptoras. |

---

## 5. DOCUMENTACIÓN DETALLADA DE SERVICIOS

---

### 5.1 `GET /api/ia/inventario` (Inventario en Tiempo Real)

Obtiene el stock actual disponible de la empresa para productos con existencias (`inventario > 0`), con sus listas de precios de venta (Precio 1, Precio 2, Precio 3), precios de fracción, costos y fechas de último movimiento.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/inventario`
- **Autenticación:** Obligatoria (`Bearer token` o `?token=...`)

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso a la base de datos de la sucursal. |
| `bodega` | `integer` | 🟢 No | Todas | ID numérico de una bodega específica (Ej. `1`). |
| `bodegas` | `array` / `string` | 🟢 No | Todas | Lista de bodegas separadas por comas (Ej. `1,2,3`) o array (`bodegas[]=1&bodegas[]=2`). |
| `codigo` | `string` | 🟢 No | Ninguno | Código de barras o código interno exacto (`codigoProd`). |
| `nombre` | `string` | 🟢 No | Ninguno | Búsqueda parcial (`LIKE`) en nombre del producto, marca, categoría o código. |
| `modificado_hoy` | `integer` | 🟢 No | `0` | Si se envía `1`, solo devuelve productos con ventas o entradas hoy. |
| `desde_fecha` | `string` | 🟢 No | Ninguno | Filtra productos con última venta o entrada `>= YYYY-MM-DD HH:MM:SS`. |
| `limit` | `integer` | 🟢 No | Sin límite | Cantidad máxima de registros a retornar. |

#### Ejemplo de Petición:
```http
GET /api/ia/inventario?bodega=1&nombre=acetaminofen&limit=10 HTTP/1.1
Host: tu-dominio.com
Authorization: Bearer TU_TOKEN_DE_EMPRESA
Accept: application/json
```

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "data": [
    {
      "idbodega": 1,
      "codigoProd": "77020010001",
      "nombre": "ACETAMINOFEN 500 MG CAJA X 100 TAB",
      "inventario": 45.0,
      "costocaja": 12500.0,
      "costofrcc": 125.0,
      "VentaCaja": 18000.0,
      "VentaFrcc": 200.0,
      "VentaCaja2": 17000.0,
      "VentaFrcc2": 190.0,
      "VentaCaja3": 16500.0,
      "VentaFrcc3": 180.0,
      "fechaUltimaVenta": "2026-09-22 18:45:10",
      "fechaUltimaEntrada": "2026-09-15 09:30:00",
      "factor": 100,
      "nommarca": "GENFAR",
      "nomcategoria": "ANALGESICOS"
    }
  ]
}
```

---

### 5.2 `GET /api/ia/inventario-cambios` (Inventario Modificado Hoy / Delta)

Versión de alto rendimiento diseñada para sincronizaciones periódicas y agentes de IA. Si no se especifican parámetros de fecha, **automáticamente asume `modificado_hoy = 1`**, retornando únicamente los productos que se vendieron o ingresaron en la jornada actual.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/inventario-cambios`
- **Autenticación:** Obligatoria (`Bearer token` o `?token=...`)

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso. |
| `bodega` | `integer` | 🟢 No | Todas | ID de bodega a monitorear. |
| `desde_fecha` | `string` | 🟢 No | `Hoy 00:00:00` | Marca de tiempo inicial (`YYYY-MM-DD HH:MM:SS`) para traer cambios acumulados. |
| `codigo` / `nombre`| `string` | 🟢 No | Ninguno | Filtros opcionales de búsqueda específica. |

#### Ejemplo de Petición:
```http
GET /api/ia/inventario-cambios?bodega=1&desde_fecha=2026-09-23+12:00:00 HTTP/1.1
Host: tu-dominio.com
Authorization: Bearer TU_TOKEN_DE_EMPRESA
Accept: application/json
```

---

### 5.3 `GET /api/ia/ventas` (Estadísticas Financieras y KPIs)

Devuelve los indicadores financieros clave (KPIs de ingresos, costo de mercancía vendida, utilidad neta, IVA generado y facturas emitidas) junto con el desglose gráfico agrupado por Bodega, Categoría, Marca, Top 15 de Productos y Evolución Diaria.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/ventas`
- **Autenticación:** Obligatoria (`Bearer token` o `?token=...`)

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso. |
| `fi` | `string` | 🟢 No | Hace 30 días | Fecha Inicial (`YYYY-MM-DD`). |
| `ff` | `string` | 🟢 No | Hoy | Fecha Final (`YYYY-MM-DD`). |
| `bodega` | `integer` | 🟢 No | Todas (`0`) | ID de bodega (`0` o vacío analiza todas). |
| `marca` | `string` | 🟢 No | `Todas` | Filtrar por código o nombre de marca (búsqueda inteligente con tolerancia a nombres). |
| `categoria` | `string` | 🟢 No | `Todas` | Filtrar por código o nombre de categoría. |
| `producto` | `string` | 🟢 No | Todos | Código o coincidencia en nombre de producto. |
| `comparar` | `string` / `bool` | 🟢 No | `false` | Enviar `"true"` para activar comparativa con otro periodo. |
| `fi_comp` | `string` | 🟢 No | Ninguno | Fecha inicial del periodo comparativo (`YYYY-MM-DD`). |
| `ff_comp` | `string` | 🟢 No | Ninguno | Fecha final del periodo comparativo (`YYYY-MM-DD`). |

#### Ejemplo de Respuesta (200 OK):
```json
{
  "actual": {
    "kpis": {
      "ventas": 28450000.0,
      "costos": 19200000.0,
      "iva": 3540000.0,
      "utilidad": 9250000.0,
      "facturas": 684
    },
    "graficos": {
      "categoria": {
        "labels": ["ANALGESICOS", "ANTIBIOTICOS", "DERMATOLOGIA"],
        "data": [12400000, 9500000, 6550000]
      },
      "marca": {
        "labels": ["GENFAR", "MK", "TECNOQUIMICAS"],
        "data": [11000000, 9800000, 7650000]
      },
      "producto": {
        "labels": ["DOLEX FORTE X 24 TAB", "AMOXICILINA 500MG"],
        "data": [3200000, 2150000]
      },
      "bodega": {
        "labels": ["Bodega Principal", "Sucursal Norte"],
        "data": [18450000, 10000000]
      },
      "evolucion": {
        "labels": ["2026-09-01", "2026-09-02"],
        "data": [950000, 1120000]
      }
    }
  },
  "periodo_consultado": {
    "fecha_inicio": "2026-09-01",
    "fecha_fin": "2026-09-23"
  }
}
```

---

### 5.4 `GET /api/ia/rotacion` (Rotación Física en Cajas y Fracciones)

Muestra la rotación en **unidades físicas reales**, descontando devoluciones parciales y devoluciones totales de productos mediante una consulta SQL optimizada con `UNION ALL`. Incluye frecuencia de compras y el stock actual en cada bodega.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/rotacion`
- **Autenticación:** Obligatoria (`Bearer token` o `?token=...`)

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso. |
| `fecha_inicio`| `string` | 🟢 No | Hace 30 días | Fecha inicio de cálculo (`YYYY-MM-DD`). |
| `fecha_fin` | `string` | 🟢 No | Hoy | Fecha fin de cálculo (`YYYY-MM-DD`). |
| `bodega` | `integer` | 🟢 No | Todas | Filtrar por ID de bodega. |
| `bodegas` | `array` / `string` | 🟢 No | Todas | Lista de bodegas (Ej. `1,2`). |
| `codigo` | `string` | 🟢 No | Ninguno | Código exacto de producto. |
| `nombre` | `string` | 🟢 No | Ninguno | Búsqueda por nombre, marca, categoría o código. |
| `limit` | `integer` | 🟢 No | Sin límite | Límite de paginación (Ej. `50`). |
| `page` | `integer` | 🟢 No | `1` | Número de página. |

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "periodo_consultado": {
    "fecha_inicio": "2026-08-24",
    "fecha_fin": "2026-09-23"
  },
  "paginacion": {
    "total_registros": 412,
    "pagina_actual": 1,
    "limite": 1
  },
  "data": [
    {
      "codigo": "7702001",
      "nombre": "ACETAMINOFEN 500MG X 100 TAB",
      "factor_producto": 100,
      "rotacion_global": {
        "total_fracciones": 240,
        "equivalente_cajas": 2.4,
        "frecuencia_ventas_total": 18,
        "formato_amigable": "2 Cajas y 40 Fracciones"
      },
      "desglose_bodegas": [
        {
          "id_bodega": 1,
          "nombre_bodega": "Bodega Principal",
          "rotacion_equivalente_cajas": 1.9,
          "frecuencia_ventas": 14,
          "inventario_actual_cajas": 15.0,
          "fecha_ultima_entrada": "2026-09-10 14:00:00",
          "cantid_traslada": 0
        },
        {
          "id_bodega": 2,
          "nombre_bodega": "Sucursal Norte",
          "rotacion_equivalente_cajas": 0.5,
          "frecuencia_ventas": 4,
          "inventario_actual_cajas": 1.0,
          "fecha_ultima_entrada": "2026-08-20 08:30:00",
          "cantid_traslada": 0
        }
      ]
    }
  ]
}
```

---

### 5.5 `POST /api/ia/traslados` (Crear Movimiento de Traslado)

Genera la transferencia de inventario restando existencias de la bodega de salida y sumándolas a la bodega de entrada.
- Ejecuta bloqueos de fila (`lockForUpdate()`) para garantizar concurrencia segura.
- Valida que el stock disponible en la bodega de origen sea suficiente.
- Admite traslados tanto en cajas como en fracciones.
- Si un producto de la lista no cuenta con inventario suficiente, se omite y se registra en `productos_omitidos`, continuando con el resto.

- **Método:** `POST`
- **URL:** `https://tu-dominio.com/api/ia/traslados`
- **Autenticación:** Obligatoria
- **Headers:** `Content-Type: application/json`, `Accept: application/json`

#### Estructura del Body (JSON):
| Campo | Tipo | Obligatorio | Descripción |
| :--- | :---: | :---: | :--- |
| `bodega_salida` | `integer` | 🔴 **SÍ** | ID de la bodega origen donante. |
| `bodega_entrada`| `integer` | 🔴 **SÍ** | ID de la bodega destino receptora. |
| `productos` | `array` | 🔴 **SÍ** | Lista de productos a trasladar (mínimo 1 producto). |
| `productos[].codigo` | `string` | 🔴 **SÍ** | Código del producto en el POS. |
| `productos[].caja` | `number` | 🟢 No* | Cantidad de cajas enteras a trasladar (defecto `0`). |
| `productos[].frcc` | `number` | 🟢 No* | Cantidad de fracciones a trasladar (defecto `0`). |

*\* Al menos uno entre `caja` o `frcc` debe ser mayor a 0.*

#### Ejemplo de Petición:
```http
POST /api/ia/traslados HTTP/1.1
Host: tu-dominio.com
Authorization: Bearer TU_TOKEN_DE_EMPRESA
Content-Type: application/json

{
  "bodega_salida": 1,
  "bodega_entrada": 2,
  "productos": [
    {
      "codigo": "7702001",
      "caja": 5,
      "frcc": 0
    },
    {
      "codigo": "7702002",
      "caja": 2,
      "frcc": 10
    }
  ]
}
```

#### Ejemplo de Respuesta Exitosa (200 OK):
```json
{
  "estado": "ok",
  "mensaje": "Proceso Realizado con exito",
  "numero": 1284,
  "fecha": "2026-09-23 14:40:15",
  "productos_omitidos": []
}
```

#### Respuesta con Productos Omitidos por Stock Insuficiente:
```json
{
  "estado": "ok",
  "mensaje": "Proceso Realizado con exito",
  "numero": 1284,
  "fecha": "2026-09-23 14:40:15",
  "productos_omitidos": [
    {
      "codigo": "7702099",
      "nombre": "INSULINA NPH 100UI",
      "motivo": "Stock insuficiente (disponible: 1.0 cajas)"
    }
  ]
}
```

---

### 5.6 `POST /api/ia/traslados/guardar` (Cerrar Consecutivo de Traslado)

Cierra formalmente el traslado y actualiza el contador de consecutivos de traslados en la base de datos de la empresa para la bodega de salida.

- **Método:** `POST`
- **URL:** `https://tu-dominio.com/api/ia/traslados/guardar`
- **Autenticación:** Obligatoria
- **Headers:** `Content-Type: application/json`

#### Estructura del Body (JSON):
```json
{
  "bodega_salida": 1
}
```

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "mensaje": "Proceso Realizado con exito",
  "numero": 1284,
  "fecha": "2026-09-23 14:40:20"
}
```

---

### 5.7 `POST /api/ia/traslados/lote` (Múltiples Traslados en Lote)

Permite crear y cerrar múltiples rutas de traslado de diferentes bodegas en **una única petición HTTP**. Ejecuta internamente la creación de movimiento y el cierre de consecutivo para cada ruta.

- **Método:** `POST`
- **URL:** `https://tu-dominio.com/api/ia/traslados/lote`
- **Autenticación:** Obligatoria

#### Estructura del Body (JSON):
```json
{
  "traslados": [
    {
      "bodega_salida": 1,
      "bodega_entrada": 2,
      "productos": [
        { "codigo": "7702001", "caja": 5, "frcc": 0 }
      ]
    },
    {
      "bodega_salida": 1,
      "bodega_entrada": 3,
      "productos": [
        { "codigo": "7703050", "caja": 2, "frcc": 0 }
      ]
    }
  ]
}
```

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "traslados_completados": 2,
  "traslados_fallidos": 0,
  "resultados": [
    {
      "ruta": "Bodega 1 → Bodega 2",
      "productos_count": 1,
      "estado": "completado",
      "productos_omitidos": []
    },
    {
      "ruta": "Bodega 1 → Bodega 3",
      "productos_count": 1,
      "estado": "completado",
      "productos_omitidos": []
    }
  ],
  "errores": []
}
```

---

### 5.8 `POST /api/ia/traslados/ejecutar-sugeridos` (Ejecución Automática de Traslados)

Ejecuta el cálculo inteligente de transferencias óptimas entre bodegas (evitando desabastecimientos y sobrestocks) y traslada automáticamente los productos sugeridos en un solo paso, con capacidad de excluir marcas o palabras clave.

- **Método:** `POST`
- **URL:** `https://tu-dominio.com/api/ia/traslados/ejecutar-sugeridos`
- **Autenticación:** Obligatoria

#### Estructura del Body (JSON):
| Campo | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `bodega_origen` | `integer` | 🟢 No | Todas | ID de bodega donante específica. |
| `bodega_destino`| `integer` | 🟢 No | Todas | ID de bodega receptora específica. |
| `bodegas_destino`| `array` | 🟢 No | Todas | Múltiples bodegas receptoras permitidas. |
| `dias_provision`| `integer` | 🟢 No | `7` | Días de stock objetivo a garantizar en la bodega destino. |
| `fecha_inicio` | `string` | 🟢 No | Hace 30 días | Periodo de análisis de demanda (`YYYY-MM-DD`). |
| `fecha_fin` | `string` | 🟢 No | Hoy | Periodo de análisis de demanda (`YYYY-MM-DD`). |
| `conservar_minimo`| `boolean`| 🟢 No | `false` | Si es `true`, garantiza que el origen conserve al menos su stock de seguridad. |
| `omitir_productos`| `array` | 🟢 No | `[]` | Palabras clave, marcas o nombres a excluir (reconoce singular y plural, ej. `["helados", "mk"]`). |

#### Ejemplo de Petición:
```json
{
  "bodega_origen": 1,
  "dias_provision": 10,
  "conservar_minimo": true,
  "omitir_productos": ["helados", "gaseosas", "bayer"]
}
```

---

### 5.9 `GET /api/ia/clientes` (Consulta y Búsqueda de Clientes)

Permite identificar y buscar clientes por su documento de identidad, número telefónico/WhatsApp o coincidencia parcial en nombre, apellido o alias.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/clientes`
- **Autenticación:** Obligatoria

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso. |
| `cedula` | `string` | 🟢 No | Ninguno | Cédula, NIT o documento exacto. |
| `telefono` | `string` | 🟢 No | Ninguno | Búsqueda parcial de teléfono o celular (`LIKE`). |
| `nombre` | `string` | 🟢 No | Ninguno | Coincidencia en Nombre, Apellido o Alias. |
| `limit` | `integer` | 🟢 No | `50` | Registros por página. |
| `page` | `integer` | 🟢 No | `1` | Número de página. |

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "paginacion": {
    "total": 1,
    "limit": 50,
    "page": 1,
    "paginas": 1
  },
  "data": [
    {
      "id": 154,
      "cedula": "1085245890",
      "Nombre": "MARIANA",
      "apellido": "LOPEZ",
      "Alias": "Mariana Drogueria",
      "telefono": "3158941234",
      "direccion": "Carrera 23 # 14-50",
      "correo": "mariana.lopez@gmail.com",
      "tipoId": "13",
      "dv": null,
      "naturaleza": "Natural",
      "regimen": "No Responsable de IVA",
      "responsabilidad": "R-99-PN",
      "codigociudad": "52001",
      "estadoC": 1
    }
  ]
}
```

---

### 5.10 `POST /api/ia/clientes` (Crear / Registrar Cliente)

Registra un nuevo tercero / cliente en la base de datos del POS con todos los parámetros normativos colombianos (DIAN) y comerciales.

- **Método:** `POST`
- **URL:** `https://tu-dominio.com/api/ia/clientes`
- **Autenticación:** Obligatoria
- **Headers:** `Content-Type: application/json`

#### Campos Disponibles en el Body:
| Campo | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `cedula` | `string` | 🔴 **SÍ** | — | Cédula, NIT o Identificación (única). |
| `nombre` | `string` | 🔴 **SÍ** | — | Nombre de pila o Razón Social. |
| `apellido` | `string` | 🟢 No | `""` | Apellidos del cliente. |
| `alias` / `Alias` | `string` | 🟢 No | `""` | Apodo o nombre comercial. |
| `telefono` | `string` | 🟢 No | `""` | Celular o WhatsApp. |
| `direccion` | `string` | 🟢 No | `""` | Dirección domiciliaria. |
| `barrio` | `string` | 🟢 No | `""` | Barrio o sector de ubicación. |
| `correo` | `string` | 🟢 No | `""` | Correo electrónico para facturas. |
| `tipoId` | `string` | 🟢 No | `"13"` | Tipo de Documento DIAN (`13`=CC, `31`=NIT, `22`=CE, `41`=Pasaporte). |
| `dv` | `string` | 🟢 No | `null` | Dígito de verificación para NIT. |
| `naturaleza` | `string` | 🟢 No | `"Natural"`| `"Natural"` o `"Juridica"`. |
| `regimen` | `string` | 🟢 No | `"No Responsable de IVA"` | Régimen tributario (`Responsable de IVA`, `No Responsable de IVA`). |
| `responsabilidad`| `string`| 🟢 No | `"R-99-PN"`| Responsabilidad fiscal DIAN (Ej. `R-99-PN`, `O-13`, `O-47`). |
| `codigociudad` | `string` | 🟢 No | `"11001"` | Código DANE del municipio (Ej. `11001`=Bogotá, `52001`=Pasto). |
| `cupo` | `number` / `string`| 🟢 No | `"0"` | Cupo máximo de crédito en dinero. |
| `credicto` | `number` / `string`| 🟢 No | `"0"` | Días de crédito permitidos (plazo). |
| `credValor` | `number` / `string`| 🟢 No | `"0"` | Saldo de crédito inicial. |
| `dtoclie` | `number` / `string`| 🟢 No | `"0"` | Porcentaje de descuento permanente al cliente. |
| `puntos` | `number` / `string`| 🟢 No | `"0"` | Saldo de puntos de fidelización acumulados. |
| `ValorBono` | `number` / `string`| 🟢 No | `"0"` | Valor de bonos de descuento disponibles. |
| `listaprecio_defec`| `string`| 🟢 No | `"sistema"`| Lista de precios asignada (`sistema`, `precio1`, `precio2`, `precio3`). |
| `fechaNacimiento`| `date` | 🟢 No | Fecha hoy | Fecha de nacimiento (`YYYY-MM-DD`). |
| `vendedorDefecto`| `string`| 🟢 No | `"0"` | ID del vendedor asignado por defecto al cliente. |
| `notaComentario` | `string` | 🟢 No | `""` | Observaciones, notas médicas o comentarios del cliente. |
| `metodoPagoDefec`| `string` | 🟢 No | `null` | Método de pago habitual (`Efectivo`, `Transferencia`, `Crédito`). |
| `otros` | `string` | 🟢 No | `"0"` | Campo auxiliar para parametrizaciones personalizadas. |
| `estadoC` | `integer`| 🟢 No | `1` | Estado del cliente (`1`=Activo, `0`=Inactivo). |

#### Ejemplo de Petición:
```json
{
  "cedula": "1085300400",
  "nombre": "CARLOS ANDRES",
  "apellido": "PEREZ RIASCOS",
  "telefono": "3209876543",
  "direccion": "Calle 18 # 25-10",
  "correo": "carlosperez@ejemplo.com",
  "codigociudad": "52001",
  "tipoId": "13"
}
```

#### Respuestas Posibles:
- `201 Created`: Cliente registrado con éxito.
- `400 Bad Request`: Falta la cédula o el nombre.
- `409 Conflict`: Ya existe un cliente registrado con esa cédula en la base de datos.

---

### 5.11 `GET /api/ia/ventas-clientes` (Ventas Detalladas por Cliente)

Permite auditar y consultar **qué productos específicos ha comprado cada cliente**, calculando automáticamente el valor neto real (restando devoluciones parciales y devoluciones totales de dinero o producto), precios promedio ponderados y bodegas de despacho.

- **Método:** `GET`
- **URL:** `https://tu-dominio.com/api/ia/ventas-clientes`
- **Autenticación:** Obligatoria

#### Parámetros (Query String):
| Parámetro | Tipo | Obligatorio | Defecto | Descripción |
| :--- | :---: | :---: | :---: | :--- |
| `token` | `string` | 🔴 **SÍ** | — | Token de acceso. |
| `fi` / `fecha_inicio`| `string`| 🟢 No | Hace 30 días | Fecha inicial (`YYYY-MM-DD`). |
| `ff` / `fecha_fin` | `string`| 🟢 No | Hoy | Fecha final (`YYYY-MM-DD`). |
| `cliente` / `cedula`| `string`| 🟢 No | Todos | Filtrar por cédula o teléfono del cliente. |
| `nombre` | `string`| 🟢 No | Todos | Coincidencia en nombre, apellido o alias del cliente. |
| `producto` | `string`| 🟢 No | Todos | Coincidencia en código, nombre, marca o categoría del producto. |
| `bodega` / `bodegas`| `string`| 🟢 No | Todas | Filtrar por ID de bodega(s). |
| `limit` | `integer` | 🟢 No | `50` | Límite de clientes por página (`0` para todos). |
| `page` | `integer` | 🟢 No | `1` | Número de página. |

#### Ejemplo de Respuesta (200 OK):
```json
{
  "estado": "ok",
  "periodo_consultado": {
    "fecha_inicio": "2026-08-24",
    "fecha_fin": "2026-09-23"
  },
  "paginacion": {
    "total_clientes": 1,
    "pagina_actual": 1,
    "limite": 50,
    "total_paginas": 1
  },
  "data": [
    {
      "cliente": {
        "cedula": "1085245890",
        "nombre": "MARIANA",
        "apellido": "LOPEZ",
        "nombre_completo": "MARIANA LOPEZ",
        "telefono": "3158941234",
        "direccion": "Carrera 23 # 14-50",
        "correo": "mariana.lopez@gmail.com",
        "alias": "Mariana Drogueria",
        "codigo_ciudad": "52001"
      },
      "resumen_cliente": {
        "total_comprado_neto": 145000.0,
        "total_cajas": 8.0,
        "total_fracciones": 12.0,
        "cantidad_facturas": 3,
        "total_items_distintos": 2
      },
      "productos_comprados": [
        {
          "codigo": "7702001",
          "nombre": "ACETAMINOFEN 500MG X 100 TAB",
          "marca": "GENFAR",
          "categoria": "ANALGESICOS",
          "factor": 100,
          "cant_cajas": 5.0,
          "cant_fracciones": 0.0,
          "valor_total_neto": 90000.0,
          "precio_promedio_caja": 18000.0,
          "precio_promedio_fraccion": 180.0,
          "bodega_id": 1,
          "nombre_bodega": "Bodega Principal",
          "ultima_compra": "2026-09-20 17:30:00"
        }
      ]
    }
  ]
}
```

---

## 6. SERVICIO COMPLEMENTARIO: MOTOR DE SUGERENCIAS DE TRASLADO

### `GET /api/ia/sugerido-traslados`
Ubicado en [`App\Http\Controllers\SugerenciaTrasladosController::class`](file:///c:/xampp/htdocs/Admin_PosCloud_V12/app/Http/Controllers/SugerenciaTrasladosController.php). Este servicio calcula las sugerencias matemáticas que utiliza internamente `ejecutarSugeridosLote`:

```http
GET /api/ia/sugerido-traslados?bodega_origen=1&bodega_destino=2&dias_provision=10 HTTP/1.1
Authorization: Bearer TU_TOKEN_DE_EMPRESA
```

**Parámetros:**
- `dias_provision`: Días que se proyecta abastecer la bodega destino (defecto: `7`).
- `fecha_inicio` y `fecha_fin`: Ventana de tiempo para calcular la velocidad de venta diaria.
- `bodega_origen` y `bodega_destino`: Restringir el análisis a rutas específicas.
- `conservar_minimo`: (`true`/`false`) Protege el stock mínimo de la bodega origen.

---

## 7. MANEJO DE ERRORES Y CÓDIGOS DE ESTADO HTTP

| Código HTTP | Significado | Causa Común | Estructura de Respuesta |
| :---: | :--- | :--- | :--- |
| `200 OK` | Éxito | Consulta procesada correctamente. | `{"estado": "ok", "data": [...]}` |
| `201 Created` | Creación exitosa | Cliente o recurso registrado. | `{"estado": "ok", "mensaje": "..."}` |
| `400 Bad Request` | Parámetros inválidos o faltantes | Faltan campos obligatorios (`bodega_salida`, `cedula`, `nombre`). | `{"estado": "error", "mensaje": "..."}` |
| `401 Unauthorized` | No autorizado / Token inválido | El token no fue enviado o no existe en `setDynamicConnection()`. | `{"Mensaje": "Token inválido o no autorizado"}` |
| `409 Conflict` | Conflicto de unicidad | La cédula del cliente ya existe en el sistema. | `{"estado": "error", "mensaje": "El cliente con esta cédula ya existe."}` |
| `500 Server Error`| Error interno del servidor | Fallo en la base de datos o excepción no controlada. | `{"estado": "error", "mensaje": "Error interno..."}` |

---

## 8. EJEMPLOS DE CONSUMO EN CÓDIGO

### 8.1 cURL
```bash
# Consultar inventario con filtro de bodega
curl -X GET "https://tu-dominio.com/api/ia/inventario?bodega=1&nombre=dolex" \
     -H "Authorization: Bearer TU_TOKEN_DE_EMPRESA" \
     -H "Accept: application/json"

# Crear un traslado
curl -X POST "https://tu-dominio.com/api/ia/traslados" \
     -H "Authorization: Bearer TU_TOKEN_DE_EMPRESA" \
     -H "Content-Type: application/json" \
     -d '{
       "bodega_salida": 1,
       "bodega_entrada": 2,
       "productos": [
         {"codigo": "7702001", "caja": 3, "frcc": 0}
       ]
     }'
```

### 8.2 JavaScript (Fetch / Node.js)
```javascript
const BASE_URL = 'https://tu-dominio.com/api/ia';
const TOKEN = 'TU_TOKEN_DE_EMPRESA';

// 1. Obtener ventas del periodo
async function obtenerVentas(fi, ff) {
  const url = `${BASE_URL}/ventas?fi=${fi}&ff=${ff}`;
  const response = await fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${TOKEN}`,
      'Accept': 'application/json'
    }
  });
  const data = await response.json();
  console.log('KPIs:', data.actual.kpis);
  return data;
}

// 2. Registrar nuevo cliente
async function registrarCliente(cliente) {
  const response = await fetch(`${BASE_URL}/clientes`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${TOKEN}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    },
    body: JSON.stringify(cliente)
  });
  return await response.json();
}
```

### 8.3 Python (Requests)
```python
import requests

BASE_URL = "https://tu-dominio.com/api/ia"
HEADERS = {
    "Authorization": "Bearer TU_TOKEN_DE_EMPRESA",
    "Content-Type": "application/json",
    "Accept": "application/json"
}

# Consultar rotación de productos
params = {
    "bodega": 1,
    "limit": 20,
    "page": 1
}
response = requests.get(f"{BASE_URL}/rotacion", headers=HEADERS, params=params)
rotacion = response.json()

for prod in rotacion.get("data", []):
    print(f"{prod['codigo']} - {prod['nombre']}: {prod['rotacion_global']['formato_amigable']}")
```

### 8.4 PHP (GuzzleHttp / cURL)
```php
<?php
$token = 'TU_TOKEN_DE_EMPRESA';
$ch = curl_init('https://tu-dominio.com/api/ia/inventario-cambios?bodega=1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer {$token}",
    "Accept: application/json"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);
print_r($data);
```

---

## 9. GUÍA DE MANTENIMIENTO: CÓMO AGREGAR NUEVOS TENANTS / BASES DE DATOS

Para habilitar el acceso a una nueva sucursal o cliente, abre [`app/Http/Controllers/ApiControllerIa.php`](file:///c:/xampp/htdocs/Admin_PosCloud_V12/app/Http/Controllers/ApiControllerIa.php) y añade la nueva clave al arreglo `$tokens` en la función `setDynamicConnection()`:

```php
private function setDynamicConnection($token)
{
    $tokens = [
        'nuevo_token_seguro_cliente_123' => [
            'bd'   => 'nombre_base_datos_cliente',
            'user' => 'usuario_mysql',
            'pass' => 'clave_segura_mysql'
        ],
        // ... otros tokens existentes
    ];

    if (!isset($tokens[$token])) {
        return 'Token inválido o no autorizado';
    }
    // ...
}
```

---
*Manual generado y validado con base en el código fuente de PosCloud V12.*
