Integrar Zipnova y futuros carriers en el sistema existente de gestión de envíos, usando tags de 4 letras para identificar carriers.
Los carriers se identifican con tags de 4 letras personalizables:
| Tipo | Tag (ejemplo) | Nombre (personalizable) |
|---|---|---|
| Zipnova | ZNVA | Zipnova Principal |
| Zipnova | ZNV2 | Zipnova Secundaria |
| Otro | OTRO | Otro carrier |
Nota: El tag y nombre son editables por el usuario en la configuración.
{
"method": "standard",
"service_name": "Envío estándar",
"cost": 2500,
"address": {
"street": "...",
"city": "...",
"province": "...",
"postal_code": "...",
"country": "AR"
},
"estimated_delivery": "3-5",
// Multi-carrier fields
"carrier": "ZNVA", // Tag del carrier (ZNVA, OTRO, null)
"carrier_shipment_id": "123456", // ID del envío en el carrier
"carrier_status": "in_transit", // Estado RAW del carrier API
"tracking_id": "TRACK123", // Tracking ID público
// Estado base universal
"status": "en_transito", // Estado base del sistema (pendiente, en_transito, entregada, etc.)
// Metadata
"created_at": "2025-12-22 10:00:00",
"updated_at": "2025-12-22 12:00:00",
"history": []
}
// Nota: El tag del carrier se renderiza dinámicamente en la UI
// Display: "En tránsito (ZNVA)" se genera desde status + carrier
}Para órdenes existentes con zipnova_shipment_id:
- Se lee
zipnova_shipment_idsicarrier_shipment_idno existe - Se asume
carrier = "ZNVA"si tienezipnova_shipment_id - No se requiere migración de datos
| Estado | Descripción | Display sin carrier | Display con carrier |
|---|---|---|---|
pendiente |
Pendiente de procesamiento | Pendiente | Pendiente (ZNVA) |
en_transito |
En camino | En tránsito | En tránsito (ZNVA) |
en_reparto |
Salió para entrega | En reparto | En reparto (ZNVA) |
entregada |
Entregada al cliente | Entregada | Entregada (ZNVA) |
fallida |
Problema en la entrega | Fallida | Fallida (ZNVA) |
devuelta |
Devuelto al origen | Devuelta | Devuelta (ZNVA) |
cancelada |
Envío cancelado | Cancelada | Cancelada (ZNVA) |
Estados actuales del sistema (legacy):
cobrada→ se mapea apendienteenviada→ se mapea aen_transitoentregada→ se mantiene igual
Cada carrier mapea sus estados propios a los estados base del sistema:
Zipnova (ZNVA):
carrier_status → status (base)
──────────────────────────────────
pending → pendiente
in_transit → en_transito
out_for_delivery → en_reparto
delivered → entregada
failed → fallida
returned → devuelta
cancelled → cancelada
Otros carriers (futuro): Cada carrier define su propio mapeo a los mismos estados base.
// Ejemplo de rendering
function render_shipping_status($order) {
$status = $order['shipping']['status']; // Estado base
$carrier = $order['shipping']['carrier'] ?? null; // Tag del carrier
$status_label = get_status_label($status); // "En tránsito"
if ($carrier) {
return $status_label . ' <span class="carrier-badge">' . $carrier . '</span>';
// Output: "En tránsito (ZNVA)"
}
return $status_label; // "En tránsito"
}Ventaja:
- Con 100 carriers, sigues teniendo solo 7 estados base
- El tag se agrega dinámicamente según el carrier
- Escalable infinitamente
IMPORTANTE - Credenciales:
- Las credenciales de sandbox y producción son las mismas (NO hay que crear campos separados).
- El campo
modesolo es un flag para diferenciar el entorno. - Zipnova pasa las credenciales a producción cuando sea necesario.
{
"carriers": {
"ZNVA": {
"tag": "ZNVA", // Tag de 4 letras (personalizable por usuario)
"name": "Zipnova Principal", // Nombre descriptivo (personalizable)
"type": "zipnova", // Tipo de carrier (determina qué integración usar)
"enabled": false,
"mode": "sandbox", // "sandbox" o "production" - NO afecta credenciales
"credentials": {
"client_id": "", // Mismas credenciales para sandbox Y producción
"client_secret": "", // Mismas credenciales para sandbox Y producción
"access_token": "",
"refresh_token": "",
"token_expires_at": null
},
"api_urls": {
"sandbox": "https://sandbox.zipnova.com/api/v1",
"production": "https://api.zipnova.com/api/v1"
},
"origin": {
"name": "",
"address": "",
"city": "",
"province": "",
"postal_code": "",
"country": "AR",
"phone": "",
"email": ""
},
"default_package": {
"weight": 1,
"length": 20,
"width": 15,
"height": 10
},
"options": {
"webhook_secret": "",
"auto_create_shipment": true,
"shipping_cost_margin": 0,
"cache_quotes_minutes": 5,
"timeout_seconds": 30,
"max_retries": 3
},
"enabled_services": {
"standard": true,
"express": true,
"same_day": false
}
}
}
}Cambios:
-
Nueva columna en tabla: Carrier
- Muestra tag + icono (ej: "🚚 ZNVA")
- Vacío si es envío manual
-
Nuevo filtro: Por Carrier
- Todos
- ZNVA (Zipnova)
- Manual (sin carrier)
-
Columna Estado mejorada:
- Estado del sistema (enviada, entregada)
- Estado del carrier cuando aplica (En tránsito ZNVA)
-
Acciones específicas por carrier:
- Si carrier = ZNVA y no tiene carrier_shipment_id:
- Botón "Crear Envío en Zipnova"
- Si carrier = ZNVA y tiene carrier_shipment_id:
- Botón "Sincronizar Estado"
- Botón "Cancelar Envío"
- Botón "Ver Tracking"
- Si carrier = ZNVA y no tiene carrier_shipment_id:
Cambios:
-
UI con Tabs:
┌─────────────────────────────────────────┐ │ [ZNVA - Zipnova Principal] [+ Agregar] │ ├─────────────────────────────────────────┤ │ │ │ ┌─ Información del Carrier ─────────┐ │ │ │ Tag (4 letras): [ZNVA] │ │ │ │ Nombre: [Zipnova Principal] │ │ │ │ Tipo: [Zipnova ▼] │ │ │ │ Habilitado: [✓] │ │ │ └───────────────────────────────────┘ │ │ │ │ Configuración de Zipnova │ │ (formulario actual) │ │ │ └─────────────────────────────────────────┘ -
Campos editables:
- Tag: Input de 4 letras (validación: solo letras mayúsculas/números)
- Nombre: Input de texto libre para describir el carrier
- Tipo: Select con opciones (Zipnova, Manual, etc.)
-
Futuro:
- Botón "+ Agregar Carrier" para agregar nuevos
- Cada carrier en su propio tab
- Validación de tags únicos
- Modificar
build_shipping_data()para usar campos multi-carrier - Mantener backward compatibility con
zipnova_shipment_id - Agregar
get_carrier_name()helper - Agregar
get_carrier_status_label()helper
- Agregar funciones para leer/escribir usando estructura multi-carrier
- Mantener funciones legacy para backward compatibility
- Agregar columna Carrier
- Agregar filtro por carrier
- Mostrar acciones específicas del carrier
- Mejorar display de estados
- Reestructurar UI con tabs
- Leer/escribir usando estructura multi-carrier
- Reestructurar a formato multi-carrier
- Migración automática desde formato anterior
/app/pages/admin/shipping-list.php- Funcionalidad integrada en envios-pendientes.php
Antes:
📦 Envíos
├─ 📋 Gestión de envíos
├─ 🚚 Logística
└─ 📦 Archivo
Después:
📦 Envíos
├─ 📋 Gestión de envíos (integra todo)
└─ 📦 Archivo
- No requiere migración de datos - backward compatible
- Configuración: Se migra automáticamente al abrir config-shipping.php
- Órdenes antiguas: Se interpretan automáticamente
- ✅ Sin duplicación de funcionalidad
- ✅ Escalable para múltiples carriers
- ✅ Backward compatible - no rompe órdenes existentes
- ✅ UI centralizada y consistente
- ✅ Fácil agregar nuevos carriers en el futuro
Siguiente paso: Revisar y aprobar arquitectura antes de implementar