# HITO 2: Carga de Albaranes EDI (DESADV) — Integración EDICOM iPaaS
**Proyecto**: AGRIGEST — Integración EDI con EDICOM iPaaS  
**Documento**: EDICOM-HITO-02-ALBARANES.md  
**Mensaje EDI**: `DESADV` — Despatch Advice (Aviso de Expedición) (UN/EDIFACT D96A)  
**Dirección de flujo**: AGRIGEST → EDICOM → Cliente (Outbound)  
**Versión**: 1.0 — 2026-07-23

---

## 1. Descripción del Hito

La carga de albaranes consiste en el **envío automatizado de avisos de expedición** (albaranes de entrega) a los clientes/cadenas a través de la plataforma EDICOM iPaaS.

Cuando AGRIGEST genera un albarán confirmando la expedición de mercancía, debe enviar el mensaje `DESADV` a EDICOM para que ésta lo convierta al estándar EDI del cliente destino.

**Flujo**: `AGRIGEST (ge_albaranes) → API iPaaS → Plataforma EDICOM → Transformación DESADV → Cliente EDI`

---

## 2. Requerimientos EDICOM para el Envío de Albaranes

### 2.1 Autenticación

Idéntica al Hito 1:
```http
Authorization: Bearer <token_acceso>
X-Eipaas-Ds: <codigo_datasource_cliente>
```

### 2.2 Endpoint de Publicación de Albarán

```http
POST /api/v1/messages/publish
Authorization: Bearer <token>
X-Eipaas-Ds: <datasource>
Content-Type: application/json

{
  "documentType": "DESADV",
  "sender": "<GLN-NUESTRA-EMPRESA>",
  "receiver": "<GLN-CLIENTE>",
  "payload": { ... }
}
```

**Respuesta exitosa**:
```json
{
  "messageId": "MSG-DESADV-20260723-00001",
  "status": "ACCEPTED",
  "createdAt": "2026-07-23T12:00:00Z"
}
```

### 2.3 Estructura Canónica del Payload DESADV

Campos requeridos para el mensaje `DESADV` (Aviso de Expedición):

| Campo EDICOM (Canónico) | Descripción | Fuente AGRIGEST |
|---|---|---|
| `despatchAdviceNumber` | Nº albarán/aviso de expedición | `ge_albaranes.serie + numero` |
| `despatchDate` | Fecha de expedición | `ge_albaranes.fecha` |
| `orderReference` | Nº pedido del cliente (origen) | `ge_pedidos.edi_numero_pedido_cliente` |
| `sellerGLN` | GLN del vendedor/expedidor | `ge_empresas` (GLN de la empresa) |
| `buyerGLN` | GLN del comprador | `ge_clientes.ean` |
| `deliveryPointGLN` | GLN del destino de entrega | `ge_clientes_destinos.ean` |
| `lines[].lineNumber` | Número de línea del albarán | `ge_albaranes_lineas.posicion` |
| `lines[].ean` | EAN del artículo expedido | `ge_albaranes_lineas` → `ge_articulos.ean` |
| `lines[].despatchedQuantity` | Cantidad expedida | `ge_albaranes_lineas.cantidad` |
| `lines[].unitPrice` | Precio unitario | `ge_albaranes_lineas.precio` |
| `lines[].batchNumber` | Número de lote (trazabilidad) | `ge_albaranes_lineas.lotes` |
| `lines[].expiryDate` | Fecha de caducidad | `ge_albaranes_lineas.fecha_caducidad` |
| `lines[].numberOfPackages` | Número de bultos | `ge_albaranes_lineas.bultos` |

---

## 3. Análisis de la Base de Datos Actual — Carencias Detectadas

### 3.1 Tabla `ge_albaranes` — Estado Actual

**Campos existentes relevantes**:
- `id`, `empresa_id`, `cliente_id`, `clientedestino_id`
- `serie`, `numero`, `referencia`
- `fecha`
- `base_imponible`, `total`, `iva`
- `id_pedido` → ✅ Enlace al pedido origen
- `facturado`, `cobrado`, `anulado`

**❌ Carencias para la integración EDI (DESADV)**:

| Campo Faltante | Tipo | Descripción | Necesario Para |
|---|---|---|---|
| `edi_message_id` | `varchar(100)` | ID del mensaje DESADV enviado a EDICOM | Trazabilidad/reintentos |
| `edi_estado_envio` | `enum('NO_ENVIADO','ENVIADO','ERROR','CONFIRMADO')` | Estado del envío EDI del albarán | Control de flujo |
| `edi_enviado_at` | `timestamp` | Fecha/hora de envío a EDICOM | Auditoría |
| `edi_referencia_pedido_cliente` | `varchar(50)` | Nº pedido del cliente (para el DESADV) | Cruce con ORDERS |
| `edi_numero_sscc` | `varchar(50)` | SSCC del pallet/embalaje | Trazabilidad logística |

### 3.2 Tabla `ge_albaranes_lineas` — Estado Actual

**Campos existentes relevantes**:
- `albaran_id`, `articulo_id`, `articulo_codigo`
- `posicion`, `descripcion`
- `lotes` → ✅ Número de lote (para trazabilidad EDI)
- `fecha_caducidad` → ✅ Fecha de caducidad
- `bultos`, `cantidad_bulto`, `cantidad`
- `precio`, `base`, `total`

**❌ Carencias para la integración EDI (DESADV)**:

| Campo Faltante | Tipo | Descripción |
|---|---|---|
| `edi_ean_enviado` | `varchar(20)` | EAN efectivamente enviado en el DESADV |
| `edi_numero_linea_pedido` | `int(11)` | Número de línea del pedido original al que corresponde |

### 3.3 Tablas `edi_cabalbaran`, `edi_detalbaran`, `edi_embalbaran`, `edi_lugaresentrega`, `edi_marcasembalaje`

**📋 Observación**: Existen tablas `edi_*` que parecen mapear campos EDICOM para albaranes con un enfoque de posiciones/longitudes de campos (plano/flat-file). Esto sugiere una integración **legacy vía fichero plano**.

Con la **nueva API REST iPaaS**, el enfoque cambia a **JSON canónico**. Estas tablas pueden:
- Mantenerse como referencia histórica
- Adaptarse para documentar el mapeo JSON ↔ BD

---

## 4. SQL Propuesto — Campos a Añadir

> ⚠️ **IMPORTANTE**: Este script debe ser revisado y ejecutado **manualmente** por el usuario según la regla de seguridad de la empresa.

```sql
-- ========================================
-- HITO 2: Campos EDI para ge_albaranes
-- ========================================
ALTER TABLE `ge_albaranes`
  ADD COLUMN `edi_message_id`              varchar(100)  DEFAULT NULL 
      COMMENT 'ID del mensaje DESADV enviado a EDICOM'                                    AFTER `id_pedido`,
  ADD COLUMN `edi_estado_envio`            enum('NO_ENVIADO','ENVIADO','ERROR','CONFIRMADO') 
      DEFAULT 'NO_ENVIADO' COMMENT 'Estado del envío EDI del albarán'                      AFTER `edi_message_id`,
  ADD COLUMN `edi_enviado_at`              timestamp NULL DEFAULT NULL 
      COMMENT 'Fecha/hora de envío del DESADV a EDICOM'                                   AFTER `edi_estado_envio`,
  ADD COLUMN `edi_referencia_pedido_cliente` varchar(50) DEFAULT NULL 
      COMMENT 'Nº pedido del cliente para incluir en el DESADV'                            AFTER `edi_enviado_at`,
  ADD COLUMN `edi_numero_sscc`             varchar(50)   DEFAULT NULL 
      COMMENT 'SSCC del pallet/embalaje (Serial Shipping Container Code)'                 AFTER `edi_referencia_pedido_cliente`,
  ADD INDEX `idx_ge_albaranes_edi_estado` (`edi_estado_envio`),
  ADD INDEX `idx_ge_albaranes_edi_message_id` (`edi_message_id`);

-- ========================================
-- HITO 2: Campos EDI para ge_albaranes_lineas
-- ========================================

ALTER TABLE `ge_albaranes_lineas`
  ADD COLUMN `edi_ean_enviado`             varchar(20)   DEFAULT NULL 
      COMMENT 'EAN efectivamente enviado en el mensaje DESADV'                            AFTER `descuento_precio`,
  ADD COLUMN `edi_numero_linea_pedido`     int(11)       DEFAULT NULL 
      COMMENT 'Número de línea del pedido original ORDERS correspondiente'                AFTER `edi_ean_enviado`;
```

---

## 5. Proceso de Implementación en AGRIGEST (Delphi)

### 5.1 Módulo Delphi Propuesto

**Nuevo módulo**: `uEdicomAlbaranesClient.pas`

**Responsabilidades**:
1. `SeleccionarAlbaranesParaEnvio(): TDataSet` — Consultar albaranes con `edi_estado_envio = 'NO_ENVIADO'` y cliente con GLN
2. `ConstruirPayloadDESADV(AlbaranId: Integer): TJSONObject` — Mapear `ge_albaranes` + `ge_albaranes_lineas` al formato canónico EDICOM
3. `EnviarDESADV(Payload: TJSONObject): string` — POST a EDICOM, retorna `messageId`
4. `MarcarAlbaranEnviado(AlbaranId: Integer; MessageId: string)` — UPDATE estado EDI

### 5.2 Construcción del Payload DESADV

```pascal
// Pseudocódigo del mapeo AGRIGEST → DESADV
function ConstruirPayloadDESADV(AlbaranId: Integer): TJSONObject;
var
  Albaran: TJSONObject;
  Lines: TJSONArray;
  Line: TJSONObject;
begin
  // Cabecera
  Result := TJSONObject.Create;
  Result.AddPair('documentType', 'DESADV');
  Result.AddPair('despatchAdviceNumber', Serie + PadLeft(Numero, 8, '0'));
  Result.AddPair('despatchDate', FormatDateTime('yyyy-mm-dd', Fecha));
  Result.AddPair('orderReference', edi_numero_pedido_cliente);
  Result.AddPair('sellerGLN', GlnEmpresa);
  Result.AddPair('buyerGLN', GlnCliente);       // ge_clientes.ean
  Result.AddPair('deliveryPointGLN', GlnDestino); // ge_clientes_destinos.ean
  
  // Líneas
  Lines := TJSONArray.Create;
  // Por cada línea en ge_albaranes_lineas...
  Line := TJSONObject.Create;
  Line.AddPair('lineNumber', Posicion);
  Line.AddPair('ean', ge_articulos.ean);
  Line.AddPair('despatchedQuantity', Cantidad);
  Line.AddPair('unitPrice', Precio);
  Line.AddPair('batchNumber', Lotes);
  Line.AddPair('expiryDate', FormatDateTime('yyyy-mm-dd', FechaCaducidad));
  Line.AddPair('numberOfPackages', Bultos);
  Lines.AddElement(Line);
  
  Result.AddPair('lines', Lines);
end;
```

### 5.3 Flujo de Proceso

```
USUARIO confirma expedición en AGRIGEST
  │
  ├── 1. Albarán guardado con edi_estado_envio = 'NO_ENVIADO'
  │
  ├── 2. [Botón "Enviar EDI" o proceso automático]
  │
  ├── 3. AutenticarEdicom() → Bearer Token
  │
  ├── 4. ConstruirPayloadDESADV(albaranId) → JSON
  │   ├── Leer ge_albaranes + ge_albaranes_lineas
  │   ├── Resolver GLN cliente: ge_clientes.ean
  │   ├── Resolver GLN destino: ge_clientes_destinos.ean
  │   └── Resolver EAN artículo: ge_articulos.ean
  │
  ├── 5. EnviarDESADV(JSON) → POST a EDICOM
  │   └── Respuesta: messageId
  │
  └── 6. MarcarAlbaranEnviado()
      ├── UPDATE ge_albaranes SET edi_message_id = messageId
      ├── UPDATE ge_albaranes SET edi_estado_envio = 'ENVIADO'
      └── UPDATE ge_albaranes SET edi_enviado_at = NOW()
```

### 5.4 Integración en la UI

- Columna visual en el listado de albaranes: indicador de estado EDI
- Botón: **"Enviar DESADV EDI"** (individual o en lote para los seleccionados)
- Tooltip/detalle: mostrar `edi_message_id` y `edi_enviado_at`

---

## 6. Datos a Solicitar a EDICOM

- [ ] Endpoint exacto de publicación de DESADV (`POST /api/v1/...`)
- [ ] Esquema JSON canónico del payload DESADV completo
- [ ] GLN de nuestra empresa (vendedor)
- [ ] Requisito de datos de embalaje (SSCC, pallets) si aplica
- [ ] Formato de fecha/hora requerido
- [ ] Obligatoriedad del campo lote/caducidad por tipo de cliente

---

## 7. Consideraciones Especiales

- **Trazabilidad de Lotes**: Los campos `ge_albaranes_lineas.lotes` y `fecha_caducidad` son críticos para el `DESADV`. Verificar que se informan correctamente al confirmar la expedición.
- **Vinculación ORDERS→DESADV**: El `DESADV` debe referenciar el número de pedido del cliente (`edi_numero_pedido_cliente`). Si el albarán no tiene pedido origen, el DESADV se enviará sin referencia a `ORDERS`.
- **Tablas `edi_*` legacy**: Las tablas `edi_cabalbaran`, `edi_detalbaran`, etc. de la BD parecen ser una integración anterior basada en archivo plano. Con iPaaS REST se migra a JSON. Estas tablas pueden archivarse.
- **Albaranes sin GLN cliente**: Si `ge_clientes.ean` está vacío, no se puede enviar el DESADV. Debe validarse antes del envío.
