From 3e16c3adace9a7d2764f3aafc62796c71bba343a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 18 Jul 2026 00:36:25 +0000 Subject: [PATCH] Autosave: 20260718-003740 --- call_center_pro.php | 264 ++++++- .../092_add_estado_shalom_cache_columns.sql | 4 + download_ruta_contraentrega.php | 2 +- gestiones_callcenter.php | 33 +- includes/shalom_scraper.js | 166 +++++ pedidos_en_transito.php | 672 ++++++++++-------- ruta_contraentrega.php | 15 +- shalom_api.php | 346 ++++++--- update_shalom_status.php | 45 ++ 9 files changed, 1100 insertions(+), 447 deletions(-) create mode 100644 db/migrations/092_add_estado_shalom_cache_columns.sql create mode 100644 includes/shalom_scraper.js create mode 100644 update_shalom_status.php diff --git a/call_center_pro.php b/call_center_pro.php index 3f116ff6..744c492e 100644 --- a/call_center_pro.php +++ b/call_center_pro.php @@ -72,6 +72,35 @@ function cc_test_display_value(?string $value, string $fallback = 'No registrado return $value !== '' ? $value : $fallback; } +function cc_test_build_url(string $path, array $params = []): string +{ + foreach ($params as $key => $value) { + if ($value === '' || $value === null) { + unset($params[$key]); + } + } + + $query = http_build_query($params); + + return $query !== '' ? $path . '?' . $query : $path; +} + +function cc_test_find_assessor_key_by_user_id(?int $userId, array $assessors): ?string +{ + $userId = $userId !== null && $userId > 0 ? $userId : null; + if ($userId === null) { + return null; + } + + foreach ($assessors as $assessorKey => $assessor) { + if ((int) ($assessor['id'] ?? 0) === $userId) { + return (string) $assessorKey; + } + } + + return null; +} + function cc_test_order_label(array $order): string { if (!empty($order['is_agregado'])) { @@ -177,6 +206,9 @@ $assessors = []; $orders = []; $visibleOrders = []; $modalsHtml = []; +$isAdmin = false; +$selectedAssessorFilter = ''; +$selectedAssessorFilterLabel = ''; $totalRows = 0; $agregadosCount = 0; $lastProcessedRow = null; @@ -295,7 +327,16 @@ try { $role = (string) ($_SESSION['user_role'] ?? ''); $currentUserId = (int) ($_SESSION['user_id'] ?? 0); - if (!in_array($role, ['Administrador', 'admin'], true)) { + $isAdmin = in_array($role, ['Administrador', 'admin'], true); + $selectedAssessorFilter = cc_test_normalize_user_key($_GET['assessor'] ?? ''); + if (!$isAdmin || ($selectedAssessorFilter !== '' && !isset($assessors[$selectedAssessorFilter]))) { + $selectedAssessorFilter = ''; + } + $selectedAssessorFilterLabel = $selectedAssessorFilter !== '' + ? (string) ($assessors[$selectedAssessorFilter]['label'] ?? $selectedAssessorFilter) + : ''; + + if (!$isAdmin) { $orders = array_values(array_filter($orders, static function (array $order) use ($currentUserId): bool { return (int) ($order['user_id'] ?? 0) === $currentUserId; })); @@ -326,6 +367,15 @@ try { $order['es_nuevo_hoy'] = $importDate ? $importDate->format('Y-m-d') === $todayStart->format('Y-m-d') : false; $order['es_pendiente_hoy'] = !$order['es_promo_final'] && (in_array($order['estado'], $openStates, true) || $order['pendiente_logistica']); $order['es_cerrado'] = in_array($order['estado'], $closedStates, true); + $order['assessor_key'] = cc_test_find_assessor_key_by_user_id(isset($order['user_id']) ? (int) $order['user_id'] : null, $assessors); + $order['assessor_label'] = $order['assessor_key'] !== null + ? (string) ($assessors[$order['assessor_key']]['label'] ?? $order['assessor_key']) + : 'Sin asignar'; + $order['matches_assessor_filter'] = $selectedAssessorFilter === '' || (($order['assessor_key'] ?? '') === $selectedAssessorFilter); + + if (!$order['matches_assessor_filter']) { + continue; + } $stats['total']++; if ($order['es_nuevo_hoy']) { @@ -352,7 +402,11 @@ try { } unset($order); - $visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view): bool { + $visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view, $selectedAssessorFilter): bool { + if ($selectedAssessorFilter !== '' && !($order['matches_assessor_filter'] ?? false)) { + return false; + } + return match ($view) { 'pendientes_hoy' => (bool) ($order['es_pendiente_hoy'] ?? false), 'nuevos_hoy' => (bool) ($order['es_nuevo_hoy'] ?? false), @@ -442,6 +496,15 @@ try { $errorMessage = $exception->getMessage(); } +$callCenterBaseParams = [ + 'view' => $view, + 'store' => $storeKey, +]; +$callCenterParams = $callCenterBaseParams; +if ($selectedAssessorFilter !== '') { + $callCenterParams['assessor'] = $selectedAssessorFilter; +} + require_once 'layout_header.php'; ?> @@ -456,48 +519,140 @@ require_once 'layout_header.php'; } .cc-callcenter-assign-form { - padding: .5rem !important; + width: 100%; + padding: .72rem !important; + border: 1px solid rgba(0, 0, 0, .10) !important; + border-left: .55rem solid #FFFFFF; + background-color: #FFFFFF; + color: #212529; + box-shadow: 0 .65rem 1.4rem rgba(15, 23, 42, .06), inset 0 0 0 1px rgba(0, 0, 0, .05); } .cc-callcenter-assign-form.has-accent { - border-left: .45rem solid var(--cc-assessor-accent, #adb5bd); - background: linear-gradient(135deg, rgba(var(--cc-assessor-accent-rgb, 173, 181, 189), .12) 0%, rgba(255, 255, 255, .98) 72%); + border-color: rgba(var(--cc-assessor-accent-rgb, 173, 181, 189), .38) !important; + border-left-color: var(--cc-assessor-accent, #adb5bd); + background-color: var(--cc-assessor-accent, #adb5bd); + color: var(--cc-assessor-accent-contrast, #212529); + box-shadow: none; +} + +.cc-callcenter-assign-form.is-neutral { + border-color: rgba(108, 117, 125, .22) !important; + border-left-color: #ADB5BD; + background-color: #F1F3F5; + color: #495057; + box-shadow: none; +} + +.cc-callcenter-assign-form .text-muted { + color: #6C757D !important; + opacity: 1; +} + +.cc-callcenter-assign-form.has-accent .text-muted { + color: var(--cc-assessor-accent-contrast, #212529) !important; + opacity: .88; } .cc-callcenter-assessor-badge { display: inline-flex; align-items: center; gap: .3rem; - background-color: rgba(var(--cc-assessor-accent-rgb, 173, 181, 189), .12); - color: #212529; - border-color: rgba(var(--cc-assessor-accent-rgb, 173, 181, 189), .28) !important; + background-color: #F8F9FA; + color: #6C757D; + border-color: rgba(0, 0, 0, .12) !important; + font-weight: 600; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .04); +} + +.cc-callcenter-assign-form.has-accent .cc-callcenter-assessor-badge { + background-color: rgba(255, 255, 255, .18); + color: var(--cc-assessor-accent-contrast, #212529); + border-color: rgba(255, 255, 255, .42) !important; + box-shadow: none; } .cc-callcenter-color-dot { width: .55rem; height: .55rem; border-radius: 999px; - background: var(--cc-assessor-accent, #adb5bd); + background: #ADB5BD; border: 1px solid rgba(0, 0, 0, .12); - box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22); + box-shadow: none; flex: 0 0 auto; } +.cc-callcenter-assign-form.has-accent .cc-callcenter-assessor-badge .cc-callcenter-color-dot { + background: var(--cc-assessor-accent-contrast, #212529); + border: 1px solid rgba(255, 255, 255, .35); +} + .cc-callcenter-assign-row { display: flex; flex-wrap: nowrap; align-items: center; gap: .35rem; + padding: .5rem; + border-radius: .95rem; + background-color: #FFFFFF; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08); +} + +.cc-callcenter-assign-form.has-accent .cc-callcenter-assign-row { + background-color: transparent; + box-shadow: none; +} + +.cc-callcenter-assign-form.is-neutral .cc-callcenter-assign-row { + background-color: rgba(255, 255, 255, .72); + box-shadow: inset 0 0 0 1px rgba(108, 117, 125, .12); } .cc-callcenter-assign-row .form-select { min-width: 11rem; flex: 1 1 11rem; + border-color: rgba(0, 0, 0, .16); + background-color: #FFFFFF; + color: #212529; + font-weight: 700; + box-shadow: none; +} + +.cc-callcenter-assign-form.has-accent .cc-callcenter-assign-row .form-select { + border-color: rgba(255, 255, 255, .48); + background-color: rgba(255, 255, 255, .18); + color: var(--cc-assessor-accent-contrast, #212529); +} + +.cc-callcenter-assign-row .form-select:focus { + border-color: rgba(0, 0, 0, .18); + box-shadow: none; +} + +.cc-callcenter-assign-form.has-accent .cc-callcenter-assign-row .form-select:focus { + border-color: rgba(255, 255, 255, .72); + box-shadow: 0 0 0 .2rem rgba(255, 255, 255, .18); } .cc-callcenter-assign-submit { flex: 0 0 auto; white-space: nowrap; + border-color: rgba(0, 0, 0, .12) !important; + background-color: #F1F3F5 !important; + color: #495057 !important; + font-weight: 700; + box-shadow: none; +} + +.cc-callcenter-assign-form.has-accent .cc-callcenter-assign-submit { + border-color: rgba(255, 255, 255, .42) !important; + background-color: rgba(255, 255, 255, .18) !important; + color: var(--cc-assessor-accent-contrast, #212529) !important; +} + +.cc-callcenter-assign-submit:hover:not(:disabled) { + filter: brightness(.97); + transform: translateY(-1px); } .cc-callcenter-actions { @@ -518,17 +673,17 @@ require_once 'layout_header.php';

Pedidos Asignados

@@ -555,7 +710,7 @@ require_once 'layout_header.php';
+ +
+
+
+ + + +
+ + +
+ +
+ +
+
Usa este filtro para revisar solo los pedidos de una asesora y ver sus tarjetas por estado dentro de esta misma pantalla.
+
+
+
+
+ +

Estados disponibles: Por llamar, Devolver llamada, Observado, Se envió número de cuenta, Confirmado contraentrega, Confirmado envío, Cancelado y Repetido. Promo Final se habilita desde el Día 4 y exige imagen de sustento para mover el pedido.

- pedidos en esta bandeja +
+ + Asesora: + + pedidos en esta bandeja +
@@ -662,7 +854,11 @@ require_once 'layout_header.php'; - No hay pedidos en esta bandeja por ahora. + + No hay pedidos en esta bandeja para . + + No hay pedidos en esta bandeja por ahora. + @@ -780,30 +976,22 @@ require_once 'layout_header.php';
- + 0 ? (int) $orderUserId : null) : null; $unassigned = $orderUserIdNorm === null; - $assignedAssessorKey = null; - if (!$unassigned) { - foreach ($assessors as $assessorKey => $assessor) { - if ((int) ($assessor['id'] ?? 0) === (int) $orderUserIdNorm) { - $assignedAssessorKey = (string) $assessorKey; - break; - } - } - } + $assignedAssessorKey = $order['assessor_key'] ?? null; - $assignFormClass = 'border rounded-3 p-1 text-start shadow-sm cc-callcenter-assign-form'; + $assignFormClass = 'border rounded-3 p-1 text-start cc-callcenter-assign-form'; $assignFormStyle = ''; if ($unassigned) { - $assignFormClass .= ' bg-light'; + $assignFormClass .= ' is-unassigned'; } elseif ($assignedAssessorKey !== null) { $assignFormClass .= ' has-accent'; $assignFormStyle = cc_test_assessor_css_vars($assignedAssessorKey, $assessors[$assignedAssessorKey]['color_hex'] ?? null); } else { - $assignFormClass .= ' bg-secondary-subtle border-secondary'; + $assignFormClass .= ' is-neutral'; } $selectedAssessorKeyForSelect = $unassigned ? '' : ($assignedAssessorKey !== null ? (string) $assignedAssessorKey : ''); diff --git a/db/migrations/092_add_estado_shalom_cache_columns.sql b/db/migrations/092_add_estado_shalom_cache_columns.sql new file mode 100644 index 00000000..2ca2bcf7 --- /dev/null +++ b/db/migrations/092_add_estado_shalom_cache_columns.sql @@ -0,0 +1,4 @@ +-- Cachea el último estado consultado de Shalom para la vista de Pedidos en Tránsito. +ALTER TABLE `pedidos` + ADD COLUMN IF NOT EXISTS `estado_shalom` VARCHAR(120) NULL AFTER `seguimiento`, + ADD COLUMN IF NOT EXISTS `estado_shalom_actualizado_at` DATETIME NULL AFTER `estado_shalom`; diff --git a/download_ruta_contraentrega.php b/download_ruta_contraentrega.php index 75b77bc7..3f7ae1ad 100644 --- a/download_ruta_contraentrega.php +++ b/download_ruta_contraentrega.php @@ -286,7 +286,7 @@ $is_admin = in_array($user_role, ['Administrador', 'admin'], true); // Exportar solo los pedidos con fecha de entrega "mañana" $date_condition = "DATE(p.fecha_entrega) = DATE_ADD(CURDATE(), INTERVAL 1 DAY)"; - $sql = "SELECT p.* FROM pedidos p WHERE p.estado IN ('RUTA_CONTRAENTREGA', 'PENDIENTE', 'NO CONTESTO, VOLVER A LLAMAR', 'NO CONTESTO, DEVOLVER LLAMADA', 'CANCELADO', 'REPROGRAMADO', 'ENTREGA EXITOSA', 'RETORNADO')"; + $sql = "SELECT p.* FROM pedidos p WHERE p.estado IN ('RUTA_CONTRAENTREGA', 'NO CONTESTO, VOLVER A LLAMAR', 'NO CONTESTO, DEVOLVER LLAMADA', 'CANCELADO', 'REPROGRAMADO', 'ENTREGA EXITOSA', 'RETORNADO')"; $params = []; if ($user_role === 'Asesor') { diff --git a/gestiones_callcenter.php b/gestiones_callcenter.php index 43482b28..56b4d30e 100644 --- a/gestiones_callcenter.php +++ b/gestiones_callcenter.php @@ -870,10 +870,10 @@ require_once 'layout_header.php'; } .cc-callcenter-assign-form .cc-callcenter-assessor-badge { - background-color: rgba(0, 0, 0, .16); + background-color: rgba(255, 255, 255, .18); color: var(--cc-assessor-accent-contrast, #212529); - border-color: rgba(0, 0, 0, .16) !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08); + border-color: rgba(255, 255, 255, .42) !important; + box-shadow: none; } .cc-callcenter-assign-form.is-unassigned .cc-callcenter-assessor-badge { @@ -884,7 +884,7 @@ require_once 'layout_header.php'; } .cc-callcenter-assign-form .cc-callcenter-assessor-badge .cc-callcenter-color-dot { - border: 1px solid rgba(0, 0, 0, .18); + border: 1px solid rgba(255, 255, 255, .65); box-shadow: none; } @@ -912,10 +912,11 @@ require_once 'layout_header.php'; .cc-callcenter-assign-row .form-select { min-width: 10rem; flex: 1 1 10rem; - border-color: rgba(0, 0, 0, .18); - background-color: rgba(0, 0, 0, .12); + border-color: rgba(255, 255, 255, .48); + background-color: rgba(255, 255, 255, .18); color: var(--cc-assessor-accent-contrast, #212529); font-weight: 700; + box-shadow: none; } .cc-callcenter-assign-form.is-unassigned .cc-callcenter-assign-row .form-select { @@ -925,18 +926,18 @@ require_once 'layout_header.php'; } .cc-callcenter-assign-row .form-select:focus { - border-color: rgba(0, 0, 0, .24); - box-shadow: 0 0 0 .2rem rgba(0, 0, 0, .12); + border-color: rgba(255, 255, 255, .72); + box-shadow: 0 0 0 .2rem rgba(255, 255, 255, .18); } .cc-callcenter-assign-submit { flex: 0 0 auto; white-space: nowrap; - border-color: rgba(0, 0, 0, .18) !important; - background-color: rgba(0, 0, 0, .16) !important; + border-color: rgba(255, 255, 255, .42) !important; + background-color: rgba(255, 255, 255, .18) !important; color: var(--cc-assessor-accent-contrast, #212529) !important; font-weight: 700; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08); + box-shadow: none; } .cc-callcenter-assessor-badge { @@ -956,11 +957,11 @@ require_once 'layout_header.php'; gap: .3rem; padding: .2rem .55rem; white-space: nowrap; - border-color: rgba(0, 0, 0, .18) !important; - background-color: rgba(0, 0, 0, .12); + border-color: rgba(255, 255, 255, .42) !important; + background-color: rgba(255, 255, 255, .18); color: var(--cc-assessor-accent-contrast, #212529); font-weight: 700; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08); + box-shadow: none; } .cc-callcenter-color-trigger:hover:not(:disabled), @@ -971,7 +972,7 @@ require_once 'layout_header.php'; .cc-callcenter-color-trigger:disabled { opacity: .72; - background-color: rgba(0, 0, 0, .10); + background-color: rgba(255, 255, 255, .12); } .cc-callcenter-assign-form.is-unassigned .cc-callcenter-color-trigger { @@ -990,7 +991,7 @@ require_once 'layout_header.php'; height: .72rem; border-radius: 999px; background: var(--cc-assessor-accent, #adb5bd); - border: 1px solid rgba(0, 0, 0, .24); + border: 1px solid rgba(255, 255, 255, .65); box-shadow: none; flex: 0 0 auto; } diff --git a/includes/shalom_scraper.js b/includes/shalom_scraper.js new file mode 100644 index 00000000..4248f2b3 --- /dev/null +++ b/includes/shalom_scraper.js @@ -0,0 +1,166 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const puppeteer = require('puppeteer'); + +function detectChromeExecutable() { + const candidates = []; + const cacheRoot = '/home/ubuntu/.cache/puppeteer/chrome'; + + try { + if (fs.existsSync(cacheRoot)) { + const versions = fs.readdirSync(cacheRoot).sort().reverse(); + for (const version of versions) { + candidates.push(path.join(cacheRoot, version, 'chrome-linux64', 'chrome')); + } + } + } catch (error) { + // Ignoramos y seguimos con rutas fijas. + } + + if (process.env.PUPPETEER_EXECUTABLE_PATH) { + candidates.unshift(process.env.PUPPETEER_EXECUTABLE_PATH); + } + + candidates.push( + '/usr/bin/google-chrome-stable', + '/usr/bin/google-chrome', + '/usr/bin/chromium', + '/usr/bin/chromium-browser' + ); + + return candidates.find((candidate) => candidate && fs.existsSync(candidate)) || null; +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function main() { + const orderNumber = (process.argv[2] || '').trim(); + const orderCode = (process.argv[3] || '').trim(); + + if (!orderNumber || !orderCode) { + console.log(JSON.stringify({ + success: false, + error: 'Número de orden y código de orden son requeridos.' + })); + process.exit(1); + } + + const trackingUrl = `https://shalom.com.pe/rastrea/${encodeURIComponent(orderNumber)}/${encodeURIComponent(orderCode)}`; + let browser = null; + + try { + const executablePath = detectChromeExecutable(); + + browser = await puppeteer.launch({ + headless: 'new', + executablePath: executablePath || undefined, + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage' + ] + }); + + const page = await browser.newPage(); + await page.setViewport({ width: 1280, height: 900 }); + await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'); + + await page.goto(trackingUrl, { + waitUntil: 'networkidle2', + timeout: 60000, + }); + + await sleep(4000); + + const payload = await page.evaluate(() => { + const textOf = (selectorList) => { + for (const selector of selectorList) { + const el = document.querySelector(selector); + const text = el && el.textContent ? el.textContent.trim() : ''; + if (text) return text; + } + return ''; + }; + + const allParagraphs = Array.from(document.querySelectorAll('p')) + .map((p) => (p.textContent || '').trim()) + .filter(Boolean); + + const status = textOf([ + '.text-4xl.font-bold.text-red-color-sidebar', + '.text-3xl.font-bold.text-red-color-sidebar' + ]); + + let description = textOf([ + 'p.text-md.font-normal.text-silver-title', + 'p.text-sm.font-normal.text-silver-title' + ]); + + if (!description) { + description = allParagraphs.find((text) => { + return !/^N° DE ORDEN:/i.test(text) + && !/^Desde el/i.test(text) + && /destino|recojo|entregado|origen|procesado|tránsito|transito/i.test(text); + }) || ''; + } + + const orderLabel = allParagraphs.find((text) => /^N° DE ORDEN:/i.test(text)) || ''; + const dateLabel = allParagraphs.find((text) => /^Desde el/i.test(text)) || ''; + const internalOrderNumber = orderLabel.replace(/^N° DE ORDEN:\s*/i, '').trim(); + const bodyText = document.body && document.body.innerText ? document.body.innerText.trim() : ''; + + return { + status, + description, + orderLabel, + dateLabel, + internalOrderNumber, + requiresLogin: /Inicia sesión para acceder/i.test(bodyText), + currentUrl: location.href, + currentPath: location.pathname, + }; + }); + + if (!payload.status || payload.currentPath === '/rastrea') { + console.log(JSON.stringify({ + success: false, + error: 'No se pudo encontrar la guía en el rastreo público de Shalom.', + tracking_url: trackingUrl, + })); + process.exit(2); + } + + console.log(JSON.stringify({ + success: true, + source: 'shalom_web', + status: payload.status, + description: payload.description, + internal_order_number: payload.internalOrderNumber || null, + external_order_number: orderNumber, + order_code: orderCode, + date_text: payload.dateLabel || null, + tracking_url: trackingUrl, + requires_login: !!payload.requiresLogin, + })); + } catch (error) { + console.log(JSON.stringify({ + success: false, + error: error && error.message ? error.message : 'Error al consultar Shalom.', + tracking_url: trackingUrl, + })); + process.exit(3); + } finally { + if (browser) { + try { + await browser.close(); + } catch (error) { + // Ignoramos errores al cerrar el navegador. + } + } + } +} + +main(); diff --git a/pedidos_en_transito.php b/pedidos_en_transito.php index 19629a35..b6f908b4 100644 --- a/pedidos_en_transito.php +++ b/pedidos_en_transito.php @@ -34,6 +34,28 @@ function getStatusStyle($status) { return "background-color: {$bgColor} !important; {$style}"; } +function getShalomStatusBadgeClass($status) { + $normalized = mb_strtoupper(trim((string) $status), 'UTF-8'); + + if ($normalized === '') { + return 'bg-warning text-dark'; + } + + if (str_contains($normalized, 'ENTREGADO') || str_contains($normalized, 'COMPLETADO') || str_contains($normalized, 'DESTINO')) { + return 'bg-success'; + } + + if (str_contains($normalized, 'TRANSITO') || str_contains($normalized, 'TRÁNSITO')) { + return 'bg-primary'; + } + + if (str_contains($normalized, 'REGISTRADO') || str_contains($normalized, 'ORIGEN')) { + return 'bg-warning text-dark'; + } + + return 'bg-secondary'; +} + $pdo = db(); $user_id = $_SESSION['user_id']; @@ -97,6 +119,7 @@ $whatsapp_template_db = $stmt_config->fetchColumn(); ?> @@ -165,9 +188,10 @@ include 'layout_header.php';
Limpiar - +
+

El sistema guarda el último estado consultado de Shalom y puedes refrescar la columna con este botón cuando lo necesites.

@@ -246,12 +270,15 @@ include 'layout_header.php'; } $whatsappUrl = "https://api.whatsapp.com/send?phone={$celular}&text={$whatsappMessageEncoded}"; + $trackingUrl = (!empty($pedido['codigo_rastreo']) && !empty($pedido['codigo_tracking'])) + ? 'https://shalom.com.pe/rastrea/' . rawurlencode((string) $pedido['codigo_rastreo']) . '/' . rawurlencode((string) $pedido['codigo_tracking']) + : 'https://shalom.com.pe/rastrea'; ?>
- - 🚚 + + 🚚 - 💬 + 💬
@@ -270,7 +297,22 @@ include 'layout_header.php'; Oculto'; ?> - VERIFICAR + + + +
+ + + Act. + +
+ + VERIFICAR + + @@ -308,7 +350,6 @@ include 'layout_header.php';