34849-vm/update_callcenter_test_tracking.php
2026-07-10 06:17:47 +00:00

729 lines
28 KiB
PHP

<?php
session_start();
require_once 'db/config.php';
require_once 'includes/callcenter_test_helpers.php';
require_once 'includes/contraentrega_cobertura.php';
header('Content-Type: application/json; charset=utf-8');
if (!isset($_SESSION['user_id']) || !cc_test_current_user_can_access_module(db())) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Método no permitido']);
exit;
}
function cc_test_normalize_nullable_text(string $key, int $maxLen = 3000): ?string
{
$value = trim((string) ($_POST[$key] ?? ''));
if ($value === '') {
return null;
}
if (mb_strlen($value) > $maxLen) {
throw new RuntimeException('El campo ' . $key . ' es demasiado largo.');
}
return $value;
}
function cc_test_fetch_source_order(PDO $pdo, string $sourceKey): ?array
{
$stmt = $pdo->prepare(
'SELECT
source_key,
store_key,
codigo,
import_id,
nombre,
celular,
producto,
cantidad,
precio,
coordenadas,
direccion_drive,
referencia_drive,
sede_drive,
ciudad_drive,
distrito_drive,
dni_drive,
observaciones_drive
FROM callcenter_test_orders
WHERE source_key = ?
LIMIT 1'
);
$stmt->execute([$sourceKey]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row ?: null;
}
function cc_test_build_contraentrega_notes(array $parts): string
{
$cleanParts = [];
foreach ($parts as $part) {
$part = trim((string) $part);
if ($part !== '') {
$cleanParts[] = $part;
}
}
return implode("\n\n", $cleanParts);
}
function cc_test_prepare_route_order_payload(array $sourceOrder, array $formData, int $fallbackUserId): array
{
if (($sourceOrder['store_key'] ?? '') !== 'otra_tienda') {
throw new RuntimeException('En este primer paso la subida automática a ruta está activa solo para TUANI.');
}
$nombreCompleto = trim((string) ($sourceOrder['nombre'] ?? ''));
$celular = trim((string) ($sourceOrder['celular'] ?? ''));
$direccion = trim((string) ($formData['direccion'] ?? ''));
$referencia = trim((string) ($formData['referencia'] ?? ''));
$departamento = trim((string) ($formData['sede'] ?? ''));
$provincia = trim((string) ($formData['ciudad'] ?? ''));
$distrito = trim((string) ($formData['distrito'] ?? ''));
$dni = trim((string) (($formData['dni'] ?? '') !== '' ? ($formData['dni'] ?? '') : ($sourceOrder['dni_drive'] ?? '')));
$observacionesPedido = trim((string) (($formData['observaciones'] ?? '') !== '' ? ($formData['observaciones'] ?? '') : ($sourceOrder['observaciones_drive'] ?? '')));
$notaSeguimiento = trim((string) ($formData['nota_seguimiento'] ?? ''));
$fechaEntrega = $formData['fecha_entrega_programada'] ?? null;
$coordenadasRaw = trim((string) ($formData['coordenadas'] ?? ''));
if ($nombreCompleto === '' || $celular === '') {
throw new RuntimeException('El pedido no tiene nombre o celular suficientes para enviarlo a Ruta Contraentrega.');
}
if ($fechaEntrega === null || $fechaEntrega === '') {
throw new RuntimeException('Debes seleccionar la fecha de entrega antes de subir el pedido.');
}
if ($direccion === '' || $departamento === '' || $provincia === '' || $distrito === '') {
throw new RuntimeException('Para subir el pedido completa dirección, departamento, provincia y distrito.');
}
$departamentos = contraentregaProvinciasPorDepartamento();
$distritosPorProvincia = contraentregaDistritosPorProvincia();
if (!array_key_exists($departamento, $departamentos)) {
throw new RuntimeException('Selecciona un departamento válido para Ruta Contraentrega.');
}
$provinciasPermitidas = $departamentos[$departamento] ?? [];
if ($provincia === '' || !in_array($provincia, $provinciasPermitidas, true)) {
throw new RuntimeException('Selecciona una provincia válida para el departamento elegido.');
}
$distritosPermitidos = $distritosPorProvincia[$provincia] ?? null;
if (is_array($distritosPermitidos) && !empty($distritosPermitidos) && !in_array($distrito, $distritosPermitidos, true)) {
throw new RuntimeException('Selecciona un distrito válido para la provincia elegida.');
}
$coordenadas = cc_test_normalize_contraentrega_coordinates($coordenadasRaw);
if ($coordenadas === null) {
throw new RuntimeException('Ingresa coordenadas válidas con el formato -12.082029, -77.069024.');
}
$productoBase = trim((string) ($formData['producto'] ?? ''));
if ($productoBase === '') {
$productoBase = trim((string) ($sourceOrder['producto'] ?? ''));
}
$cantidadBase = trim((string) ($formData['cantidad'] ?? ''));
if ($cantidadBase === '') {
$cantidadBase = trim((string) ($sourceOrder['cantidad'] ?? ''));
}
$precioBase = trim((string) ($formData['precio'] ?? ''));
if ($precioBase === '') {
$precioBase = trim((string) ($sourceOrder['precio'] ?? ''));
}
$productoPrincipal = trim((string) ($formData['confirmacion_producto'] ?? ''));
if ($productoPrincipal === '') {
$productoPrincipal = $productoBase;
}
$cantidadPrincipalRaw = trim((string) ($formData['confirmacion_cantidad'] ?? ''));
if ($cantidadPrincipalRaw === '') {
$cantidadPrincipalRaw = $cantidadBase;
}
$precioPrincipalRaw = trim((string) ($formData['confirmacion_precio'] ?? ''));
if ($precioPrincipalRaw === '') {
$precioPrincipalRaw = $precioBase;
}
if ($productoPrincipal === '') {
throw new RuntimeException('El pedido no tiene producto principal para subir a Ruta Contraentrega.');
}
$cantidadPrincipal = cc_test_parse_quantity($cantidadPrincipalRaw);
if ($cantidadPrincipal === null) {
throw new RuntimeException('La cantidad principal del pedido no es válida.');
}
$precioPrincipal = cc_test_parse_amount($precioPrincipalRaw);
if ($precioPrincipal === null) {
throw new RuntimeException('El precio principal del pedido no es válido.');
}
$productoExtra = trim((string) ($formData['confirmacion_producto_extra'] ?? ''));
$cantidadExtraRaw = trim((string) ($formData['confirmacion_cantidad_extra'] ?? ''));
$precioExtraRaw = trim((string) ($formData['confirmacion_precio_extra'] ?? ''));
$hayExtra = $productoExtra !== '' || $cantidadExtraRaw !== '' || $precioExtraRaw !== '';
$productos = [$productoPrincipal];
$detalleProductos = [$productoPrincipal . ' (x' . $cantidadPrincipal . ')'];
$cantidadTotal = $cantidadPrincipal;
$montoTotal = $precioPrincipal;
if ($hayExtra) {
if ($productoExtra === '' || $cantidadExtraRaw === '' || $precioExtraRaw === '') {
throw new RuntimeException('Si usas producto adicional, completa producto, cantidad y precio adicional.');
}
$cantidadExtra = cc_test_parse_quantity($cantidadExtraRaw);
if ($cantidadExtra === null) {
throw new RuntimeException('La cantidad del producto adicional no es válida.');
}
$precioExtra = cc_test_parse_amount($precioExtraRaw);
if ($precioExtra === null) {
throw new RuntimeException('El precio del producto adicional no es válido.');
}
$productos[] = $productoExtra;
$detalleProductos[] = $productoExtra . ' (x' . $cantidadExtra . ')';
$cantidadTotal += $cantidadExtra;
$montoTotal += $precioExtra;
}
$identificadorPedido = trim((string) ($sourceOrder['codigo'] ?? ''));
if ($identificadorPedido === '') {
$identificadorPedido = trim((string) ($sourceOrder['import_id'] ?? ''));
}
if ($identificadorPedido === '') {
$identificadorPedido = 'source:' . substr((string) ($sourceOrder['source_key'] ?? ''), 0, 12);
}
$notas = cc_test_build_contraentrega_notes([
'Origen: Call Center TUANI',
'Pedido base: ' . $identificadorPedido,
'Detalle confirmado: ' . implode(', ', $detalleProductos),
$observacionesPedido !== '' ? 'Observaciones del pedido: ' . $observacionesPedido : '',
$notaSeguimiento !== '' ? 'Nota interna Call Center: ' . $notaSeguimiento : '',
]);
$seguimiento = 'Subido desde Call Center TUANI';
$codigoTracking = trim((string) ($sourceOrder['codigo'] ?? ''));
return [
'source_key' => (string) ($sourceOrder['source_key'] ?? ''),
'dni_cliente' => $dni,
'nombre_completo' => $nombreCompleto,
'celular' => $celular,
'agencia' => 'CONTRAENTREGA',
'sede_envio' => $departamento,
'codigo_rastreo' => trim($provincia . ' / ' . $distrito, ' /'),
'codigo_tracking' => $codigoTracking !== '' ? $codigoTracking : null,
'direccion_exacta' => $direccion,
'referencia_domicilio' => $referencia !== '' ? $referencia : null,
'coordenadas' => $coordenadas,
'producto' => implode(', ', $productos),
'cantidad' => $cantidadTotal,
'monto_total' => round($montoTotal, 2),
'asesor_id' => $fallbackUserId > 0 ? $fallbackUserId : null,
'notas' => $notas,
'nota_adicional' => $notaSeguimiento !== '' ? $notaSeguimiento : null,
'observacion' => $observacionesPedido !== '' ? $observacionesPedido : null,
'descargo' => $observacionesPedido !== '' ? $observacionesPedido : null,
'seguimiento' => $seguimiento,
'fecha_entrega' => $fechaEntrega,
'tipo_paquete' => 'CONTRAENTREGA',
'estado' => 'RUTA_CONTRAENTREGA',
];
}
function cc_test_sync_route_order(PDO $pdo, ?int $existingPedidoId, array $payload): array
{
$existing = null;
if ($existingPedidoId !== null && $existingPedidoId > 0) {
$stmtExisting = $pdo->prepare('SELECT * FROM pedidos WHERE id = ? LIMIT 1');
$stmtExisting->execute([$existingPedidoId]);
$existing = $stmtExisting->fetch(PDO::FETCH_ASSOC) ?: null;
}
if ($existing) {
$montoAdelantado = round((float) ($existing['monto_adelantado'] ?? 0), 2);
$montoDebe = round(max(0, $payload['monto_total'] - $montoAdelantado), 2);
$stmtUpdate = $pdo->prepare(
'UPDATE pedidos SET
dni_cliente = :dni_cliente,
nombre_completo = :nombre_completo,
celular = :celular,
agencia = :agencia,
sede_envio = :sede_envio,
codigo_rastreo = :codigo_rastreo,
codigo_tracking = COALESCE(NULLIF(:codigo_tracking, \'\'), codigo_tracking),
referencia_domicilio = :referencia_domicilio,
direccion_exacta = :direccion_exacta,
coordenadas = :coordenadas,
producto = :producto,
cantidad = :cantidad,
monto_total = :monto_total,
monto_debe = :monto_debe,
asesor_id = :asesor_id,
notas = :notas,
nota_adicional = :nota_adicional,
observacion = :observacion,
descargo = :descargo,
seguimiento = :seguimiento,
fecha_entrega = :fecha_entrega,
tipo_paquete = :tipo_paquete,
updated_at = CURRENT_TIMESTAMP
WHERE id = :id'
);
$stmtUpdate->execute([
':dni_cliente' => $payload['dni_cliente'],
':nombre_completo' => $payload['nombre_completo'],
':celular' => $payload['celular'],
':agencia' => $payload['agencia'],
':sede_envio' => $payload['sede_envio'],
':codigo_rastreo' => $payload['codigo_rastreo'],
':codigo_tracking' => $payload['codigo_tracking'] ?? '',
':referencia_domicilio' => $payload['referencia_domicilio'],
':direccion_exacta' => $payload['direccion_exacta'],
':coordenadas' => $payload['coordenadas'],
':producto' => $payload['producto'],
':cantidad' => $payload['cantidad'],
':monto_total' => $payload['monto_total'],
':monto_debe' => $montoDebe,
':asesor_id' => $payload['asesor_id'],
':notas' => !empty(trim((string) ($existing['notas'] ?? ''))) ? $existing['notas'] : $payload['notas'],
':nota_adicional' => !empty(trim((string) ($existing['nota_adicional'] ?? ''))) ? $existing['nota_adicional'] : $payload['nota_adicional'],
':observacion' => !empty(trim((string) ($existing['observacion'] ?? ''))) ? $existing['observacion'] : $payload['observacion'],
':descargo' => !empty(trim((string) ($existing['descargo'] ?? ''))) ? $existing['descargo'] : $payload['descargo'],
':seguimiento' => !empty(trim((string) ($existing['seguimiento'] ?? ''))) ? $existing['seguimiento'] : $payload['seguimiento'],
':fecha_entrega' => $payload['fecha_entrega'],
':tipo_paquete' => $payload['tipo_paquete'],
':id' => (int) $existing['id'],
]);
return [
'pedido_id' => (int) $existing['id'],
'action' => 'updated',
];
}
$stmtInsert = $pdo->prepare(
'INSERT INTO pedidos (
dni_cliente,
nombre_completo,
celular,
agencia,
sede_envio,
codigo_rastreo,
codigo_tracking,
referencia_domicilio,
direccion_exacta,
coordenadas,
producto,
cantidad,
monto_total,
monto_adelantado,
monto_debe,
estado,
asesor_id,
notas,
nota_adicional,
observacion,
descargo,
seguimiento,
fecha_entrega,
tipo_paquete
) VALUES (
:dni_cliente,
:nombre_completo,
:celular,
:agencia,
:sede_envio,
:codigo_rastreo,
:codigo_tracking,
:referencia_domicilio,
:direccion_exacta,
:coordenadas,
:producto,
:cantidad,
:monto_total,
0,
:monto_debe,
:estado,
:asesor_id,
:notas,
:nota_adicional,
:observacion,
:descargo,
:seguimiento,
:fecha_entrega,
:tipo_paquete
)'
);
$stmtInsert->execute([
':dni_cliente' => $payload['dni_cliente'],
':nombre_completo' => $payload['nombre_completo'],
':celular' => $payload['celular'],
':agencia' => $payload['agencia'],
':sede_envio' => $payload['sede_envio'],
':codigo_rastreo' => $payload['codigo_rastreo'],
':codigo_tracking' => $payload['codigo_tracking'],
':referencia_domicilio' => $payload['referencia_domicilio'],
':direccion_exacta' => $payload['direccion_exacta'],
':coordenadas' => $payload['coordenadas'],
':producto' => $payload['producto'],
':cantidad' => $payload['cantidad'],
':monto_total' => $payload['monto_total'],
':monto_debe' => $payload['monto_total'],
':estado' => $payload['estado'],
':asesor_id' => $payload['asesor_id'],
':notas' => $payload['notas'],
':nota_adicional' => $payload['nota_adicional'],
':observacion' => $payload['observacion'],
':descargo' => $payload['descargo'],
':seguimiento' => $payload['seguimiento'],
':fecha_entrega' => $payload['fecha_entrega'],
':tipo_paquete' => $payload['tipo_paquete'],
]);
return [
'pedido_id' => (int) $pdo->lastInsertId(),
'action' => 'created',
];
}
$sourceKey = trim((string) ($_POST['source_key'] ?? ''));
$estado = cc_test_normalize_state(trim((string) ($_POST['estado'] ?? 'POR LLAMAR')));
$validStates = cc_test_valid_states();
$subirARuta = (string) ($_POST['subir_a_ruta'] ?? '') === '1';
if ($sourceKey === '' || !preg_match('/^[a-f0-9]{40}$/', $sourceKey)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Pedido de prueba inválido']);
exit;
}
if (!in_array($estado, $validStates, true)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Estado inválido']);
exit;
}
try {
$nota = cc_test_normalize_nullable_text('nota_seguimiento', 3000);
$direccion = cc_test_normalize_nullable_text('direccion', 1000);
$referencia = cc_test_normalize_nullable_text('referencia', 1000);
$agencia = cc_test_normalize_nullable_text('agencia', 80);
$sedeAgencia = cc_test_normalize_nullable_text('sede_agencia', 120);
$sede = cc_test_normalize_nullable_text('sede', 120);
$ciudad = cc_test_normalize_nullable_text('ciudad', 120);
$distrito = cc_test_normalize_nullable_text('distrito', 120);
$coordenadas = cc_test_normalize_nullable_text('coordenadas', 255);
$dni = cc_test_normalize_nullable_text('dni', 40);
$observaciones = cc_test_normalize_nullable_text('observaciones', 3000);
$producto = cc_test_normalize_nullable_text('producto', 255);
$cantidad = cc_test_normalize_nullable_text('cantidad', 50);
$precio = cc_test_normalize_nullable_text('precio', 80);
$confirmacionProducto = cc_test_normalize_nullable_text('confirmacion_producto', 255);
$confirmacionCantidad = cc_test_normalize_nullable_text('confirmacion_cantidad', 50);
$confirmacionPrecio = cc_test_normalize_nullable_text('confirmacion_precio', 80);
$confirmacionProductoExtra = cc_test_normalize_nullable_text('confirmacion_producto_extra', 255);
$confirmacionCantidadExtra = cc_test_normalize_nullable_text('confirmacion_cantidad_extra', 50);
$confirmacionPrecioExtra = cc_test_normalize_nullable_text('confirmacion_precio_extra', 80);
$pdo = db();
cc_test_ensure_tracking_table($pdo);
$stmtCurrent = $pdo->prepare('SELECT estado, numero_cuenta_enviado_at, user_id, ruta_contraentrega_pedido_id FROM callcenter_test_tracking WHERE source_key = ? LIMIT 1');
$stmtCurrent->execute([$sourceKey]);
$currentTracking = $stmtCurrent->fetch(PDO::FETCH_ASSOC) ?: null;
$role = (string) ($_SESSION['user_role'] ?? '');
$isAdmin = in_array($role, ['Administrador', 'admin'], true);
if (!$isAdmin) {
$currentUserId = (int) ($_SESSION['user_id'] ?? 0);
$trackingUserId = $currentTracking ? (int) ($currentTracking['user_id'] ?? 0) : null;
if (!$currentTracking || $trackingUserId !== $currentUserId) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado para gestionar este pedido.']);
exit;
}
}
$userIdToSet = $isAdmin
? ($currentTracking ? ((int) ($currentTracking['user_id'] ?? 0) > 0 ? (int) $currentTracking['user_id'] : null) : null)
: (int) $_SESSION['user_id'];
$proximaRaw = trim((string) ($_POST['proxima_llamada_at'] ?? ''));
$proximaLlamada = null;
if ($proximaRaw !== '') {
$proximaLlamada = DateTimeImmutable::createFromFormat('Y-m-d\TH:i', $proximaRaw);
if (!$proximaLlamada) {
throw new RuntimeException('La fecha de próxima llamada no es válida.');
}
$proximaLlamada = $proximaLlamada->format('Y-m-d H:i:s');
}
$fechaEntregaRaw = trim((string) ($_POST['fecha_entrega_programada'] ?? ''));
$fechaEntrega = null;
if ($fechaEntregaRaw !== '') {
$fechaEntregaDate = DateTimeImmutable::createFromFormat('Y-m-d', $fechaEntregaRaw);
if (!$fechaEntregaDate) {
throw new RuntimeException('La fecha de entrega no es válida.');
}
$fechaEntrega = $fechaEntregaDate->format('Y-m-d');
}
if (cc_test_requires_delivery_date($estado) && $fechaEntrega === null) {
throw new RuntimeException('Debes seleccionar la fecha de entrega para CONFIRMADO CONTRAENTREGA.');
}
if (!in_array($estado, cc_test_open_states(), true)) {
$proximaLlamada = null;
}
if (!cc_test_requires_delivery_date($estado)) {
$fechaEntrega = null;
}
$numeroCuentaEnviadoAt = $currentTracking['numero_cuenta_enviado_at'] ?? null;
$currentState = cc_test_normalize_state((string) ($currentTracking['estado'] ?? ''));
if ($estado === 'SE ENVIO NUMERO DE CUENTA') {
if ($currentState !== 'SE ENVIO NUMERO DE CUENTA' || trim((string) $numeroCuentaEnviadoAt) === '') {
$numeroCuentaEnviadoAt = (new DateTimeImmutable('now'))->format('Y-m-d H:i:s');
}
}
if ($subirARuta && $estado !== 'CONFIRMADO CONTRAENTREGA') {
throw new RuntimeException('Para subir el pedido a ruta, el estado debe ser CONFIRMADO CONTRAENTREGA.');
}
$formData = [
'nota_seguimiento' => $nota,
'direccion' => $direccion,
'referencia' => $referencia,
'agencia' => $agencia,
'sede_agencia' => $sedeAgencia,
'sede' => $sede,
'ciudad' => $ciudad,
'distrito' => $distrito,
'coordenadas' => $coordenadas,
'dni' => $dni,
'observaciones' => $observaciones,
'producto' => $producto,
'cantidad' => $cantidad,
'precio' => $precio,
'confirmacion_producto' => $confirmacionProducto,
'confirmacion_cantidad' => $confirmacionCantidad,
'confirmacion_precio' => $confirmacionPrecio,
'confirmacion_producto_extra' => $confirmacionProductoExtra,
'confirmacion_cantidad_extra' => $confirmacionCantidadExtra,
'confirmacion_precio_extra' => $confirmacionPrecioExtra,
'fecha_entrega_programada' => $fechaEntrega,
];
$pdo->beginTransaction();
$stmt = $pdo->prepare(
'INSERT INTO callcenter_test_tracking (
source_key,
estado,
nota_seguimiento,
user_id,
direccion,
referencia,
agencia,
sede_agencia,
sede,
ciudad,
distrito,
coordenadas,
dni,
observaciones,
producto,
cantidad,
precio,
confirmacion_producto,
confirmacion_cantidad,
confirmacion_precio,
confirmacion_producto_extra,
confirmacion_cantidad_extra,
confirmacion_precio_extra,
proxima_llamada_at,
fecha_entrega_programada,
numero_cuenta_enviado_at,
ultima_gestion_at
) VALUES (
:source_key,
:estado,
:nota,
:user_id,
:direccion,
:referencia,
:agencia,
:sede_agencia,
:sede,
:ciudad,
:distrito,
:coordenadas,
:dni,
:observaciones,
:producto,
:cantidad,
:precio,
:confirmacion_producto,
:confirmacion_cantidad,
:confirmacion_precio,
:confirmacion_producto_extra,
:confirmacion_cantidad_extra,
:confirmacion_precio_extra,
:proxima_llamada_at,
:fecha_entrega_programada,
:numero_cuenta_enviado_at,
CURRENT_TIMESTAMP
)
ON DUPLICATE KEY UPDATE
estado = VALUES(estado),
nota_seguimiento = VALUES(nota_seguimiento),
user_id = VALUES(user_id),
direccion = VALUES(direccion),
referencia = VALUES(referencia),
agencia = VALUES(agencia),
sede_agencia = VALUES(sede_agencia),
sede = VALUES(sede),
ciudad = VALUES(ciudad),
distrito = VALUES(distrito),
coordenadas = VALUES(coordenadas),
dni = VALUES(dni),
observaciones = VALUES(observaciones),
producto = VALUES(producto),
cantidad = VALUES(cantidad),
precio = VALUES(precio),
confirmacion_producto = VALUES(confirmacion_producto),
confirmacion_cantidad = VALUES(confirmacion_cantidad),
confirmacion_precio = VALUES(confirmacion_precio),
confirmacion_producto_extra = VALUES(confirmacion_producto_extra),
confirmacion_cantidad_extra = VALUES(confirmacion_cantidad_extra),
confirmacion_precio_extra = VALUES(confirmacion_precio_extra),
proxima_llamada_at = VALUES(proxima_llamada_at),
fecha_entrega_programada = VALUES(fecha_entrega_programada),
numero_cuenta_enviado_at = VALUES(numero_cuenta_enviado_at),
ultima_gestion_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP'
);
$stmt->execute([
':source_key' => $sourceKey,
':estado' => $estado,
':nota' => $nota,
':user_id' => $userIdToSet,
':direccion' => $direccion,
':referencia' => $referencia,
':agencia' => $agencia,
':sede_agencia' => $sedeAgencia,
':sede' => $sede,
':ciudad' => $ciudad,
':distrito' => $distrito,
':coordenadas' => $coordenadas,
':dni' => $dni,
':observaciones' => $observaciones,
':producto' => $producto,
':cantidad' => $cantidad,
':precio' => $precio,
':confirmacion_producto' => $confirmacionProducto,
':confirmacion_cantidad' => $confirmacionCantidad,
':confirmacion_precio' => $confirmacionPrecio,
':confirmacion_producto_extra' => $confirmacionProductoExtra,
':confirmacion_cantidad_extra' => $confirmacionCantidadExtra,
':confirmacion_precio_extra' => $confirmacionPrecioExtra,
':proxima_llamada_at' => $proximaLlamada,
':fecha_entrega_programada' => $fechaEntrega,
':numero_cuenta_enviado_at' => $numeroCuentaEnviadoAt,
]);
$rutaPedidoId = isset($currentTracking['ruta_contraentrega_pedido_id']) && (int) $currentTracking['ruta_contraentrega_pedido_id'] > 0
? (int) $currentTracking['ruta_contraentrega_pedido_id']
: null;
$rutaSubidoAt = null;
$rutaAction = null;
if ($subirARuta) {
$sourceOrder = cc_test_fetch_source_order($pdo, $sourceKey);
if (!$sourceOrder) {
throw new RuntimeException('No encontré el pedido base para enviarlo a Ruta Contraentrega.');
}
$routePayload = cc_test_prepare_route_order_payload(
$sourceOrder,
$formData,
(int) ($userIdToSet ?: ($_SESSION['user_id'] ?? 0))
);
$routeSync = cc_test_sync_route_order($pdo, $rutaPedidoId, $routePayload);
$rutaPedidoId = (int) $routeSync['pedido_id'];
$rutaAction = $routeSync['action'];
$rutaSubidoAt = (new DateTimeImmutable('now'))->format('Y-m-d H:i:s');
$stmtRuta = $pdo->prepare(
'UPDATE callcenter_test_tracking
SET ruta_contraentrega_pedido_id = :pedido_id,
ruta_contraentrega_subido_at = :subido_at,
ruta_contraentrega_subido_por = :subido_por,
updated_at = CURRENT_TIMESTAMP
WHERE source_key = :source_key'
);
$stmtRuta->execute([
':pedido_id' => $rutaPedidoId,
':subido_at' => $rutaSubidoAt,
':subido_por' => (int) ($_SESSION['user_id'] ?? 0),
':source_key' => $sourceKey,
]);
}
$pdo->commit();
$message = 'Gestión actualizada correctamente.';
if ($subirARuta && $rutaPedidoId !== null) {
$message = $rutaAction === 'updated'
? 'Pedido actualizado en Ruta Contraentrega #' . $rutaPedidoId . '.'
: 'Pedido subido a Ruta Contraentrega #' . $rutaPedidoId . '.';
}
echo json_encode([
'success' => true,
'message' => $message,
'estado' => $estado,
'proxima_llamada_at' => $proximaLlamada,
'fecha_entrega_programada' => $fechaEntrega,
'numero_cuenta_enviado_at' => $numeroCuentaEnviadoAt,
'ruta_contraentrega_pedido_id' => $rutaPedidoId,
'ruta_contraentrega_subido_at' => $rutaSubidoAt,
]);
} catch (Throwable $exception) {
if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
error_log('update_callcenter_test_tracking.php: ' . $exception->getMessage());
echo json_encode([
'success' => false,
'message' => $exception instanceof RuntimeException ? $exception->getMessage() : 'No se pudo guardar la gestión.',
]);
}