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.', ]); }