2005 lines
137 KiB
PHP
2005 lines
137 KiB
PHP
<?php
|
|
session_start();
|
|
require_once 'db/config.php';
|
|
require_once 'includes/callcenter_test_helpers.php';
|
|
require_once 'includes/drive_test_orders.php';
|
|
require_once 'includes/contraentrega_cobertura.php';
|
|
|
|
$provinciasPorDepartamentoContraentrega = contraentregaProvinciasPorDepartamento();
|
|
$distritosPorProvinciaContraentrega = contraentregaDistritosPorProvincia();
|
|
$departamentosContraentrega = array_keys($provinciasPorDepartamentoContraentrega);
|
|
$sedesShalom = cc_test_fetch_shalom_sedes(db());
|
|
|
|
$pageTitle = 'Pedidos Asignados | Bandeja de la asesora';
|
|
$pageDescription = 'Bandeja para que cada asesora gestione sus pedidos asignados con la misma interfaz, estados, historial y acciones.';
|
|
|
|
if (!cc_test_current_user_can_access_module(db())) {
|
|
http_response_code(403);
|
|
require_once 'layout_header.php';
|
|
echo "<div class='container py-5'><div class='alert alert-danger mb-0'>Acceso denegado.</div></div>";
|
|
require_once 'layout_footer.php';
|
|
exit();
|
|
}
|
|
|
|
|
|
function cc_test_parse_datetime(?string $value): ?DateTimeImmutable
|
|
{
|
|
$value = trim((string) $value);
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return new DateTimeImmutable($value);
|
|
} catch (Throwable $exception) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function cc_test_format_datetime(?string $value, string $fallback = 'Sin programar'): string
|
|
{
|
|
$date = cc_test_parse_datetime($value);
|
|
return $date ? $date->format('d/m/Y h:i A') : $fallback;
|
|
}
|
|
|
|
function cc_test_format_datetime_input(?string $value): string
|
|
{
|
|
$date = cc_test_parse_datetime($value);
|
|
return $date ? $date->format('Y-m-d\TH:i') : '';
|
|
}
|
|
|
|
function cc_test_format_date(?string $value, string $fallback = 'Sin fecha'): string
|
|
{
|
|
$date = cc_test_parse_datetime($value);
|
|
return $date ? $date->format('d/m/Y') : $fallback;
|
|
}
|
|
|
|
function cc_test_format_date_input(?string $value): string
|
|
{
|
|
$date = cc_test_parse_datetime($value);
|
|
return $date ? $date->format('Y-m-d') : '';
|
|
}
|
|
|
|
function cc_test_format_price(?string $value): string
|
|
{
|
|
$value = trim((string) $value);
|
|
return $value !== '' ? 'S/ ' . $value : 'No registrado';
|
|
}
|
|
|
|
function cc_test_display_value(?string $value, string $fallback = 'No registrado'): string
|
|
{
|
|
$value = trim((string) $value);
|
|
return $value !== '' ? $value : $fallback;
|
|
}
|
|
|
|
function cc_test_order_label(array $order): string
|
|
{
|
|
if (!empty($order['is_agregado'])) {
|
|
return 'AGREGADOS';
|
|
}
|
|
|
|
$codigo = trim((string) ($order['codigo'] ?? ''));
|
|
if ($codigo !== '') {
|
|
return '#' . ltrim($codigo, '#');
|
|
}
|
|
|
|
return 'Sin número';
|
|
}
|
|
|
|
function cc_test_badge_class(string $estado): string
|
|
{
|
|
return match (cc_test_normalize_state($estado)) {
|
|
'POR LLAMAR', 'DEVOLVER LLAMADA' => 'bg-white text-dark border',
|
|
'OBSERVADO' => 'bg-warning-subtle text-warning-emphasis',
|
|
'SE ENVIO NUMERO DE CUENTA' => 'bg-success-subtle text-success-emphasis',
|
|
'CONFIRMADO CONTRAENTREGA' => 'cc-badge-orange',
|
|
'CONFIRMADO ENVIO' => 'bg-success text-white',
|
|
'CANCELADO' => 'bg-danger-subtle text-danger-emphasis',
|
|
'REPETIDO' => 'bg-secondary-subtle text-secondary-emphasis',
|
|
default => 'bg-white text-dark border',
|
|
};
|
|
}
|
|
|
|
|
|
function cc_test_order_time(array $order): int
|
|
{
|
|
foreach (['proxima_llamada_at', 'numero_cuenta_enviado_at', 'ultima_gestion_at', 'seguimiento_actualizado'] as $field) {
|
|
$date = cc_test_parse_datetime($order[$field] ?? null);
|
|
if ($date) {
|
|
return $date->getTimestamp();
|
|
}
|
|
}
|
|
|
|
// Fallback recency for Drive imports where import_id is not a datetime (e.g. "#35898").
|
|
return cc_test_import_time($order);
|
|
}
|
|
|
|
function cc_test_import_time(array $order): int
|
|
{
|
|
if (!empty($order['is_agregado'])) {
|
|
return (int) ($order['id'] ?? 0);
|
|
}
|
|
|
|
$importRaw = trim((string) ($order['import_id'] ?? ''));
|
|
if ($importRaw !== '') {
|
|
$date = cc_test_parse_datetime($importRaw);
|
|
if ($date) {
|
|
return $date->getTimestamp();
|
|
}
|
|
|
|
$digits = preg_replace('/\D+/', '', $importRaw);
|
|
if ($digits !== '') {
|
|
return (int) $digits;
|
|
}
|
|
}
|
|
|
|
$codigoRaw = trim((string) ($order['codigo'] ?? ''));
|
|
$digits = preg_replace('/\D+/', '', $codigoRaw);
|
|
return $digits !== '' ? (int) $digits : 0;
|
|
}
|
|
function cc_test_followup_semaforo(array $order): ?array
|
|
{
|
|
if (cc_test_normalize_state((string) ($order['estado'] ?? '')) !== 'SE ENVIO NUMERO DE CUENTA') {
|
|
return null;
|
|
}
|
|
|
|
return cc_test_account_followup_semaforo($order['numero_cuenta_enviado_at'] ?? null);
|
|
}
|
|
|
|
$view = $_GET['view'] ?? 'pendientes_hoy';
|
|
$allowedViews = [
|
|
'pendientes_hoy' => 'Bandeja principal',
|
|
'nuevos_hoy' => 'Nuevos de hoy',
|
|
'confirmados' => 'Confirmados',
|
|
'seguimiento' => 'Seguimiento',
|
|
'promo_final' => 'Promo Final',
|
|
'observados' => 'Observados',
|
|
'cerrados' => 'Cerrados / descartados',
|
|
'todos' => 'Todos los pedidos cargados',
|
|
];
|
|
if (!isset($allowedViews[$view])) {
|
|
$view = 'pendientes_hoy';
|
|
}
|
|
|
|
$storeKey = trim((string) ($_GET['store'] ?? 'flower'));
|
|
$storeKey = mb_strtolower($storeKey);
|
|
$availableStores = drive_test_available_stores();
|
|
if (!isset($availableStores[$storeKey])) {
|
|
$storeKey = 'flower';
|
|
}
|
|
$storeConfig = $availableStores[$storeKey];
|
|
$storeLabel = (string) ($storeConfig['label'] ?? strtoupper($storeKey));
|
|
$usesIncrementalSync = !empty($storeConfig['incremental_sync']);
|
|
|
|
$errorMessage = null;
|
|
$noticeMessage = null;
|
|
$assessors = [];
|
|
$orders = [];
|
|
$visibleOrders = [];
|
|
$modalsHtml = [];
|
|
$totalRows = 0;
|
|
$agregadosCount = 0;
|
|
$lastProcessedRow = null;
|
|
$startRow = (int) ($storeConfig['startRow'] ?? 5552);
|
|
$catalogoProductos = [];
|
|
$stats = [
|
|
'total' => 0,
|
|
'pendientes_hoy' => 0,
|
|
'nuevos_hoy' => 0,
|
|
'confirmados' => 0,
|
|
'seguimiento' => 0,
|
|
'promo_final' => 0,
|
|
'observados' => 0,
|
|
'cerrados' => 0,
|
|
];
|
|
|
|
try {
|
|
$pdo = db();
|
|
cc_test_ensure_tracking_table($pdo);
|
|
cc_test_ensure_historial_llamadas_table($pdo);
|
|
$assessors = cc_test_fetch_assessors($pdo);
|
|
|
|
try {
|
|
$stmtProductos = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre ASC");
|
|
$catalogoProductos = $stmtProductos->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (Throwable $exception) {
|
|
$catalogoProductos = [];
|
|
}
|
|
|
|
if ($usesIncrementalSync) {
|
|
$syncInfo = drive_test_sync_orders_incremental($pdo, $storeKey, 0);
|
|
$totalRows = (int) ($syncInfo['drive_rows_total'] ?? 0);
|
|
$lastProcessedRow = (int) ($syncInfo['last_processed_row'] ?? 0);
|
|
$startRow = (int) ($syncInfo['next_start_row'] ?? $startRow);
|
|
|
|
$orders = drive_test_fetch_orders_from_db($pdo, $storeKey);
|
|
|
|
$agregadosCount = 0;
|
|
foreach ($orders as $o) {
|
|
if (!empty($o['is_agregado'])) {
|
|
$agregadosCount++;
|
|
}
|
|
}
|
|
} else {
|
|
$preview = drive_test_fetch_orders(100, $startRow, $storeKey);
|
|
$totalRows = (int) ($preview['total_rows'] ?? 0);
|
|
$orders = $preview['orders'] ?? [];
|
|
|
|
$agregadosOrders = drive_test_fetch_orders_from_db($pdo, $storeKey, true);
|
|
$agregadosCount = count($agregadosOrders);
|
|
if (!empty($agregadosOrders)) {
|
|
$orders = array_merge($orders, $agregadosOrders);
|
|
}
|
|
}
|
|
|
|
$tracking = drive_test_fetch_tracking($pdo, array_column($orders, 'source_key'));
|
|
$orders = drive_test_merge_tracking($orders, $tracking);
|
|
$orders = array_values(array_filter($orders, static function (array $order): bool {
|
|
return empty($order['eliminado']);
|
|
}));
|
|
$orders = array_values(array_filter($orders, static function (array $order): bool {
|
|
return empty($order['eliminado']);
|
|
}));
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'assign_assessor') {
|
|
$sourceKey = trim((string) ($_POST['source_key'] ?? ''));
|
|
$targetValue = trim((string) ($_POST['target_assessor'] ?? ''));
|
|
if ($sourceKey === '' || !preg_match('/^[a-f0-9]{40}$/', $sourceKey)) {
|
|
throw new RuntimeException('Pedido de prueba inválido para asignar.');
|
|
}
|
|
|
|
$targetKey = trim(mb_strtoupper($targetValue));
|
|
$targetKey = preg_replace('/\s+/', ' ', $targetKey) ?? $targetKey;
|
|
$selectedAssessor = $targetKey !== '' ? ($assessors[$targetKey] ?? null) : null;
|
|
if ($targetKey !== '' && !$selectedAssessor) {
|
|
throw new RuntimeException('No se encontró la asesora seleccionada.');
|
|
}
|
|
|
|
$targetUserId = $selectedAssessor ? (int) $selectedAssessor['id'] : null;
|
|
|
|
$stmtCurrent = $pdo->prepare('SELECT user_id FROM callcenter_test_tracking WHERE source_key = ? LIMIT 1');
|
|
$stmtCurrent->execute([$sourceKey]);
|
|
$currentUserIdRaw = $stmtCurrent->fetchColumn();
|
|
$currentUserId = $currentUserIdRaw !== null ? ((int) $currentUserIdRaw > 0 ? (int) $currentUserIdRaw : null) : null;
|
|
|
|
// Si el pedido ya está asignado, evitamos que se reasigne a otra asesora (solo permitimos dejarlo sin asignar).
|
|
if ($currentUserId !== null && $targetUserId !== null && (int) $currentUserId !== (int) $targetUserId) {
|
|
$currentLabel = 'otra asesora';
|
|
foreach ($assessors as $assessorKey => $assessor) {
|
|
if ((int) ($assessor['id'] ?? 0) === (int) $currentUserId) {
|
|
$currentLabel = (string) ($assessor['label'] ?? $assessorKey);
|
|
break;
|
|
}
|
|
}
|
|
|
|
throw new RuntimeException('Este pedido ya está asignado a ' . $currentLabel . '. Para cambiarlo primero déjalo en "Sin asignar".');
|
|
}
|
|
|
|
cc_test_upsert_assignee($pdo, $sourceKey, $targetUserId);
|
|
$noticeMessage = $selectedAssessor
|
|
? 'Pedido asignado a ' . $selectedAssessor['label'] . '.'
|
|
: 'Pedido dejado sin asignar.';
|
|
|
|
$tracking = drive_test_fetch_tracking($pdo, array_column($orders, 'source_key'));
|
|
$orders = drive_test_merge_tracking($orders, $tracking);
|
|
}
|
|
|
|
$sourceKeys = array_column($orders, 'source_key');
|
|
$callCounts = [];
|
|
if (!empty($sourceKeys)) {
|
|
$placeholders = implode(',', array_fill(0, count($sourceKeys), '?'));
|
|
$stmtCalls = $pdo->prepare("SELECT pedido_id, COUNT(*) as total FROM historial_llamadas WHERE pedido_id IN ($placeholders) GROUP BY pedido_id");
|
|
$stmtCalls->execute($sourceKeys);
|
|
$callCounts = $stmtCalls->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
}
|
|
|
|
$role = (string) ($_SESSION['user_role'] ?? '');
|
|
$currentUserId = (int) ($_SESSION['user_id'] ?? 0);
|
|
if (!in_array($role, ['Administrador', 'admin'], true)) {
|
|
$orders = array_values(array_filter($orders, static function (array $order) use ($currentUserId): bool {
|
|
return (int) ($order['user_id'] ?? 0) === $currentUserId;
|
|
}));
|
|
}
|
|
|
|
$todayStart = new DateTimeImmutable('today');
|
|
$todayEnd = $todayStart->setTime(23, 59, 59);
|
|
$openStates = cc_test_open_states();
|
|
$closedStates = cc_test_closed_states();
|
|
|
|
foreach ($orders as &$order) {
|
|
$order['estado'] = cc_test_normalize_state((string) ($order['estado'] ?? ''));
|
|
$order['total_llamadas'] = (int) ($callCounts[$order['source_key']] ?? 0);
|
|
$importDate = cc_test_parse_datetime($order['import_id'] ?? null);
|
|
$proximaDate = cc_test_parse_datetime($order['proxima_llamada_at'] ?? null);
|
|
$followupDayInfo = cc_test_followup_day_info($order);
|
|
$order['seguimiento_dia_info'] = $followupDayInfo;
|
|
$order['dias_seguimiento'] = $followupDayInfo['day_number'] ?? null;
|
|
$order['promo_final_habilitado'] = !empty($followupDayInfo['is_promo_final']);
|
|
$order['promo_final_evidencia_cargada'] = trim((string) ($order['promo_final_evidencia_path'] ?? '')) !== '';
|
|
$order['es_promo_final'] = $order['promo_final_habilitado'] && $order['promo_final_evidencia_cargada'];
|
|
$order['promo_final_pendiente'] = $order['promo_final_habilitado'] && !$order['promo_final_evidencia_cargada'];
|
|
$order['pendiente_logistica_destino'] = $storeKey === 'otra_tienda'
|
|
? cc_test_pending_logistica_destination($order)
|
|
: null;
|
|
$order['pendiente_logistica'] = $order['pendiente_logistica_destino'] !== null;
|
|
|
|
$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);
|
|
|
|
$stats['total']++;
|
|
if ($order['es_nuevo_hoy']) {
|
|
$stats['nuevos_hoy']++;
|
|
}
|
|
if ($order['es_promo_final']) {
|
|
$stats['promo_final']++;
|
|
}
|
|
if ($order['es_pendiente_hoy']) {
|
|
$stats['pendientes_hoy']++;
|
|
}
|
|
if (in_array($order['estado'], cc_test_confirmed_states(), true)) {
|
|
$stats['confirmados']++;
|
|
}
|
|
if ($order['estado'] === 'SE ENVIO NUMERO DE CUENTA' && !$order['es_promo_final']) {
|
|
$stats['seguimiento']++;
|
|
}
|
|
if ($order['estado'] === 'OBSERVADO' && !$order['es_promo_final']) {
|
|
$stats['observados']++;
|
|
}
|
|
if ($order['es_cerrado']) {
|
|
$stats['cerrados']++;
|
|
}
|
|
}
|
|
unset($order);
|
|
|
|
$visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view): bool {
|
|
return match ($view) {
|
|
'pendientes_hoy' => (bool) ($order['es_pendiente_hoy'] ?? false),
|
|
'nuevos_hoy' => (bool) ($order['es_nuevo_hoy'] ?? false),
|
|
'confirmados' => in_array(($order['estado'] ?? ''), cc_test_confirmed_states(), true),
|
|
'seguimiento' => ($order['estado'] ?? '') === 'SE ENVIO NUMERO DE CUENTA' && !($order['es_promo_final'] ?? false),
|
|
'promo_final' => (bool) ($order['es_promo_final'] ?? false),
|
|
'observados' => ($order['estado'] ?? '') === 'OBSERVADO' && !($order['es_promo_final'] ?? false),
|
|
'cerrados' => (bool) ($order['es_cerrado'] ?? false),
|
|
default => true,
|
|
};
|
|
}));
|
|
|
|
usort($visibleOrders, static function (array $a, array $b) use ($view, $storeKey): int {
|
|
$aAgregado = !empty($a['is_agregado']);
|
|
$bAgregado = !empty($b['is_agregado']);
|
|
if ($aAgregado !== $bAgregado) {
|
|
return $aAgregado ? -1 : 1;
|
|
}
|
|
|
|
$aImport = cc_test_import_time($a);
|
|
$bImport = cc_test_import_time($b);
|
|
|
|
if ($view === 'promo_final') {
|
|
$aDays = (int) ($a['dias_seguimiento'] ?? 0);
|
|
$bDays = (int) ($b['dias_seguimiento'] ?? 0);
|
|
if ($aDays !== $bDays) {
|
|
return $bDays <=> $aDays;
|
|
}
|
|
if ($aImport !== $bImport) {
|
|
return $aImport <=> $bImport;
|
|
}
|
|
}
|
|
|
|
if ($view === "pendientes_hoy") {
|
|
$aPendientePromoFinal = !empty($a['promo_final_pendiente']);
|
|
$bPendientePromoFinal = !empty($b['promo_final_pendiente']);
|
|
if ($aPendientePromoFinal !== $bPendientePromoFinal) {
|
|
return $aPendientePromoFinal ? -1 : 1;
|
|
}
|
|
|
|
$aPendienteLogistica = !empty($a['pendiente_logistica']);
|
|
$bPendienteLogistica = !empty($b['pendiente_logistica']);
|
|
if ($aPendienteLogistica !== $bPendienteLogistica) {
|
|
return $aPendienteLogistica ? -1 : 1;
|
|
}
|
|
|
|
$aAssigned = cc_test_parse_datetime($a['assigned_at'] ?? null);
|
|
$bAssigned = cc_test_parse_datetime($b['assigned_at'] ?? null);
|
|
if ($aAssigned && $bAssigned && $aAssigned != $bAssigned) {
|
|
return $bAssigned <=> $aAssigned;
|
|
}
|
|
if ($aAssigned && !$bAssigned) {
|
|
return -1;
|
|
}
|
|
if (!$aAssigned && $bAssigned) {
|
|
return 1;
|
|
}
|
|
|
|
$aDue = cc_test_parse_datetime($a["proxima_llamada_at"] ?? null);
|
|
$bDue = cc_test_parse_datetime($b["proxima_llamada_at"] ?? null);
|
|
if ($aDue && $bDue && $aDue != $bDue) {
|
|
return $aDue <=> $bDue;
|
|
}
|
|
if ($aDue && !$bDue) {
|
|
return 1;
|
|
}
|
|
if (!$aDue && $bDue) {
|
|
return -1;
|
|
}
|
|
|
|
if ($storeKey === 'otra_tienda') {
|
|
$aSourceRow = (int) ($a['source_row'] ?? 0);
|
|
$bSourceRow = (int) ($b['source_row'] ?? 0);
|
|
if ($aSourceRow > 0 && $bSourceRow > 0 && $aSourceRow !== $bSourceRow) {
|
|
return $bSourceRow <=> $aSourceRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($aImport !== $bImport) {
|
|
return $bImport <=> $aImport;
|
|
}
|
|
|
|
return cc_test_order_time($b) <=> cc_test_order_time($a);
|
|
});
|
|
} catch (Throwable $exception) {
|
|
$errorMessage = $exception->getMessage();
|
|
}
|
|
|
|
require_once 'layout_header.php';
|
|
?>
|
|
|
|
<style>
|
|
.cc-callcenter-table tbody td {
|
|
padding-top: .5rem;
|
|
padding-bottom: .5rem;
|
|
}
|
|
|
|
.cc-callcenter-table .small {
|
|
line-height: 1.15;
|
|
}
|
|
|
|
.cc-callcenter-assign-form {
|
|
padding: .5rem !important;
|
|
}
|
|
|
|
.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%);
|
|
}
|
|
|
|
.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;
|
|
}
|
|
|
|
.cc-callcenter-color-dot {
|
|
width: .55rem;
|
|
height: .55rem;
|
|
border-radius: 999px;
|
|
background: var(--cc-assessor-accent, #adb5bd);
|
|
border: 1px solid rgba(0, 0, 0, .12);
|
|
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.cc-callcenter-assign-row {
|
|
display: flex;
|
|
flex-wrap: nowrap;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
}
|
|
|
|
.cc-callcenter-assign-row .form-select {
|
|
min-width: 11rem;
|
|
flex: 1 1 11rem;
|
|
}
|
|
|
|
.cc-callcenter-assign-submit {
|
|
flex: 0 0 auto;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.cc-callcenter-actions {
|
|
gap: .35rem !important;
|
|
}
|
|
|
|
.cc-callcenter-action-btn {
|
|
padding: .2rem .55rem;
|
|
line-height: 1.1;
|
|
font-size: .78rem;
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|
|
|
|
<main class="container-fluid py-4">
|
|
<section class="mb-4">
|
|
<div class="d-flex flex-column flex-xl-row justify-content-between align-items-xl-center gap-3">
|
|
<div>
|
|
<h1 class="h2 fw-bold mb-1"><i class="bi bi-headset text-primary"></i> Pedidos Asignados</h1>
|
|
<div class="d-flex flex-wrap gap-2 mt-3">
|
|
<?php if (in_array((string) ($_SESSION['user_role'] ?? ''), ['Administrador', 'admin'], true)): ?>
|
|
<a href="gestiones_callcenter.php?view=<?php echo urlencode($view); ?>&store=<?php echo htmlspecialchars($storeKey); ?>" class="btn btn-sm btn-outline-primary">Base de Datos Pedidos</a>
|
|
<?php endif; ?>
|
|
<a href="call_center_pro.php?view=<?php echo urlencode($view); ?>&store=<?php echo htmlspecialchars($storeKey); ?>" class="btn btn-sm btn-primary">Pedidos Asignados</a>
|
|
</div>
|
|
<ul class="nav nav-pills mt-3" role="tablist" aria-label="Selector de tienda">
|
|
<li class="nav-item">
|
|
<a class="nav-link <?php echo $storeKey === 'flower' ? 'active' : ''; ?>" href="?view=<?php echo htmlspecialchars($view); ?>&store=flower">Flower</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?php echo $storeKey === 'otra_tienda' ? 'active' : ''; ?>" href="?view=<?php echo htmlspecialchars($view); ?>&store=otra_tienda">TUANI</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-2">
|
|
<span class="badge rounded-pill text-bg-light border px-3 py-2">Drive detectado: <?php echo (int) $totalRows; ?> filas</span>
|
|
<span class="badge rounded-pill text-bg-light border px-3 py-2">Agregados: <?php echo (int) $agregadosCount; ?></span>
|
|
<span class="badge rounded-pill text-bg-light border px-3 py-2"><?php if ($usesIncrementalSync && $lastProcessedRow !== null): ?><?php echo htmlspecialchars(mb_strtoupper($storeLabel)); ?>: distribución desde fila <?php echo (int) ($storeConfig['startRow'] ?? $startRow); ?> · último procesado <?php echo (int) $lastProcessedRow; ?><?php else: ?>Extracción: desde fila <?php echo (int) $startRow; ?><?php endif; ?></span>
|
|
<span class="badge rounded-pill text-bg-light border px-3 py-2">Auto actualización: cada 10 min</span>
|
|
<a href="test_importar_drive.php?store=<?php echo htmlspecialchars($storeKey); ?>" class="btn btn-outline-primary btn-sm">Ver vista previa Drive</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<?php if ($noticeMessage !== null): ?>
|
|
<section class="alert alert-success" role="alert">
|
|
<?php echo htmlspecialchars($noticeMessage); ?>
|
|
</section>
|
|
<?php endif; ?>
|
|
<?php if ($errorMessage !== null): ?>
|
|
<section class="alert alert-danger" role="alert">
|
|
<strong>No se pudo cargar el panel.</strong><br>
|
|
<?php echo htmlspecialchars($errorMessage); ?>
|
|
</section>
|
|
<?php else: ?>
|
|
<section class="row g-3 mb-4">
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=pendientes_hoy&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'pendientes_hoy' ? 'bg-dark text-white' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase opacity-75 mb-2">Bandeja principal</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['pendientes_hoy']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=nuevos_hoy&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'nuevos_hoy' ? 'bg-primary-subtle border border-primary' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Nuevos de hoy</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['nuevos_hoy']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=confirmados&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'confirmados' ? 'bg-success-subtle border border-success' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Confirmados</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['confirmados']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=seguimiento&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'seguimiento' ? 'bg-primary-subtle border border-primary' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Seguimiento</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['seguimiento']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=promo_final&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'promo_final' ? 'bg-danger-subtle border border-danger' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Promo Final</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['promo_final']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=observados&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'observados' ? 'bg-warning-subtle border border-warning' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Observados</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['observados']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=cerrados&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'cerrados' ? 'bg-secondary-subtle border border-secondary' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Cerrados</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['cerrados']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-6 col-xl-2">
|
|
<a href="?view=todos&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
|
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'todos' ? 'bg-light border' : 'bg-white'; ?>">
|
|
<div class="card-body">
|
|
<div class="small text-uppercase text-muted mb-2">Todos</div>
|
|
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['total']; ?></div>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="card border-0 shadow-sm">
|
|
<div class="card-header bg-white py-3 d-flex flex-column flex-lg-row justify-content-between align-items-lg-center gap-2">
|
|
<div>
|
|
<h2 class="h5 fw-bold mb-1"><?php echo htmlspecialchars($allowedViews[$view]); ?></h2>
|
|
<p class="text-muted small mb-1">Estados disponibles: Por llamar, Devolver llamada, Observado, Se envió número de cuenta, Confirmado contraentrega, Confirmado envío, Cancelado y Repetido. <strong>Promo Final</strong> se habilita desde el Día 4 y exige imagen de sustento para mover el pedido.</p>
|
|
</div>
|
|
<span class="badge bg-light text-dark border"><?php echo count($visibleOrders); ?> pedidos en esta bandeja</span>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0 cc-callcenter-table">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>N° Pedido</th>
|
|
<th>Cliente</th>
|
|
<th>Ubicación editable</th>
|
|
<th>Pedido</th>
|
|
<th>Gestión</th>
|
|
<th class="text-center">Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($visibleOrders)): ?>
|
|
<tr>
|
|
<td colspan="6" class="text-center py-5 text-muted">
|
|
<i class="bi bi-inbox fs-2 d-block mb-2"></i>
|
|
No hay pedidos en esta bandeja por ahora.
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($visibleOrders as $order): ?>
|
|
<?php
|
|
$departamentoSeleccionado = trim((string) ($order['sede'] ?? ''));
|
|
$provinciaSeleccionada = trim((string) ($order['ciudad'] ?? ''));
|
|
$distritoSeleccionado = trim((string) ($order['distrito'] ?? ''));
|
|
$provinciasSeleccionadas = $provinciasPorDepartamentoContraentrega[$departamentoSeleccionado] ?? [];
|
|
$distritosSeleccionados = $distritosPorProvinciaContraentrega[$provinciaSeleccionada] ?? [];
|
|
$modalId = 'modalDriveTest' . $order['source_key'];
|
|
$badgeClass = cc_test_badge_class($order['estado']);
|
|
$followupDayInfo = $order['seguimiento_dia_info'] ?? null;
|
|
$semaforoCuenta = cc_test_followup_semaforo($order);
|
|
$historial = cc_test_fetch_historial(db(), $order['source_key']);
|
|
$logisticaPendienteLabel = !empty($order['pendiente_logistica']) ? cc_test_pending_logistica_label($order) : null;
|
|
$logisticaPendienteDetalle = match ($order['pendiente_logistica_destino'] ?? null) {
|
|
'ruta' => 'Falta subirlo a Ruta Contraentrega.',
|
|
'rotulado' => 'Falta subirlo a Pedidos Rotulados.',
|
|
default => '',
|
|
};
|
|
$subirLogisticaButtonLabel = 'Subir pedido';
|
|
$subirLogisticaNoteClass = 'small mt-2 text-muted';
|
|
$subirLogisticaNoteHtml = 'Selecciona <strong>CONFIRMADO CONTRAENTREGA</strong> o <strong>CONFIRMADO ENVIO</strong> para enviarlo a logística.';
|
|
if ($storeKey === 'otra_tienda') {
|
|
if ($order['estado'] === 'CONFIRMADO CONTRAENTREGA') {
|
|
if (!empty($order['ruta_contraentrega_pedido_id'])) {
|
|
$subirLogisticaButtonLabel = 'Actualizar en ruta';
|
|
$subirLogisticaNoteClass = 'small mt-2 text-success fw-semibold';
|
|
$subirLogisticaNoteHtml = 'En Ruta Contraentrega #' . (int) $order['ruta_contraentrega_pedido_id'] . '. Si cambias algo, usa este botón para actualizarlo.';
|
|
} else {
|
|
$subirLogisticaButtonLabel = 'Subir a ruta';
|
|
$subirLogisticaNoteClass = 'small mt-2 text-warning-emphasis';
|
|
$subirLogisticaNoteHtml = '<strong>PENDIENTE A SUBIR</strong>: este pedido ya está en <strong>CONFIRMADO CONTRAENTREGA</strong>. Súbelo a Ruta Contraentrega con este botón.';
|
|
}
|
|
} elseif ($order['estado'] === 'CONFIRMADO ENVIO') {
|
|
if (!empty($order['pedido_rotulado_pedido_id'])) {
|
|
$subirLogisticaButtonLabel = 'Actualizar rotulado';
|
|
$subirLogisticaNoteClass = 'small mt-2 text-success fw-semibold';
|
|
$subirLogisticaNoteHtml = 'En Pedidos Rotulados #' . (int) $order['pedido_rotulado_pedido_id'] . '. Si cambias algo, usa este botón para actualizarlo.';
|
|
} else {
|
|
$subirLogisticaButtonLabel = 'Subir a rotulados';
|
|
$subirLogisticaNoteClass = 'small mt-2 text-warning-emphasis';
|
|
$subirLogisticaNoteHtml = '<strong>PENDIENTE A SUBIR</strong>: este pedido ya está en <strong>CONFIRMADO ENVIO</strong>. Súbelo a Pedidos Rotulados con este botón.';
|
|
}
|
|
}
|
|
}
|
|
ob_start();
|
|
?>
|
|
<tr class="cc-callcenter-row" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>" style="<?php echo htmlspecialchars(cc_test_row_background_style((string) ($order['estado'] ?? 'POR LLAMAR'))); ?>">
|
|
<td>
|
|
<?php if ($followupDayInfo !== null): ?>
|
|
<div class="small text-uppercase fw-semibold <?php echo htmlspecialchars($followupDayInfo['text_class']); ?> mb-1"><?php echo htmlspecialchars($followupDayInfo['display_label']); ?></div>
|
|
<?php endif; ?>
|
|
<div class="fw-bold fs-6"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
|
|
<div class="small text-muted">ID Drive: <?php echo htmlspecialchars(cc_test_display_value($order['import_id'] ?? null, 'Sin ID')); ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="fw-semibold"><?php echo htmlspecialchars(cc_test_display_value($order['nombre'], 'Sin nombre')); ?></div>
|
|
<div class="small text-muted mb-1">Celular: <?php echo htmlspecialchars(cc_test_display_value($order['celular'], 'Sin número')); ?></div>
|
|
<div class="small text-muted">DNI: <?php echo htmlspecialchars(cc_test_display_value($order['dni'], 'Sin DNI')); ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="small"><strong>Dirección:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['direccion'])); ?></div>
|
|
<div class="small"><strong>Referencia:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['referencia'])); ?></div>
|
|
<div class="small"><strong>Departamento:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['sede'])); ?></div>
|
|
<div class="small"><strong>Provincia:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['ciudad'])); ?></div>
|
|
<div class="small"><strong>Distrito:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['distrito'])); ?></div>
|
|
<div class="small"><strong>Coordenadas:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['coordenadas'], 'Sin coordenadas')); ?></div>
|
|
<?php if (!empty(trim((string) ($order['distrito_drive'] ?? '')))): ?>
|
|
<div class="small"><strong>DISTRITO 1:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['distrito_drive'])); ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<div class="fw-semibold"><?php echo htmlspecialchars(cc_test_display_value($order['producto'], 'Sin producto')); ?></div>
|
|
<div class="small text-muted">Cantidad: <?php echo htmlspecialchars(cc_test_display_value($order['cantidad'])); ?> · <?php echo htmlspecialchars(cc_test_format_price($order['precio'])); ?></div>
|
|
<div class="small text-muted">Ingreso Drive: <?php echo htmlspecialchars(cc_test_format_datetime($order['import_id'] ?? null, 'Sin fecha en Drive')); ?></div>
|
|
<div class="small text-muted">Observación Drive: <?php echo htmlspecialchars(cc_test_display_value($order['observaciones'], 'Sin observaciones')); ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex flex-wrap gap-2 mb-2">
|
|
<span class="badge rounded-pill <?php echo htmlspecialchars($badgeClass); ?>"><?php echo htmlspecialchars(cc_test_state_label($order['estado'])); ?></span>
|
|
<span class="badge rounded-pill bg-light text-dark border"><span class="js-call-count-number" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>"><?php echo (int) $order['total_llamadas']; ?></span> llamadas</span>
|
|
<?php if (!empty($logisticaPendienteLabel)): ?>
|
|
<span class="badge rounded-pill bg-warning-subtle text-warning-emphasis border"><?php echo htmlspecialchars($logisticaPendienteLabel); ?></span>
|
|
<?php endif; ?>
|
|
<?php if ($semaforoCuenta !== null): ?>
|
|
<span class="badge rounded-pill <?php echo htmlspecialchars($semaforoCuenta['class']); ?>">Seguimiento <?php echo htmlspecialchars($semaforoCuenta['label']); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if (!empty($logisticaPendienteDetalle)): ?>
|
|
<div class="small text-warning-emphasis fw-semibold mb-1"><?php echo htmlspecialchars($logisticaPendienteDetalle); ?></div>
|
|
<?php endif; ?>
|
|
<?php if ($semaforoCuenta !== null): ?>
|
|
<div class="small text-muted mb-1">Número de cuenta enviado hace <?php echo (int) $semaforoCuenta['days']; ?> día<?php echo ((int) $semaforoCuenta['days'] === 1) ? '' : 's'; ?> · <?php echo htmlspecialchars($semaforoCuenta['range']); ?></div>
|
|
<?php endif; ?>
|
|
<?php if ($followupDayInfo !== null): ?>
|
|
<div class="small text-muted mb-1">Seguimiento: <?php echo htmlspecialchars($followupDayInfo['display_label']); ?> · desde <?php echo htmlspecialchars($followupDayInfo['started_at_label']); ?></div>
|
|
<?php if (!empty($followupDayInfo['notice_text'])): ?>
|
|
<div class="small <?php echo htmlspecialchars($followupDayInfo['row_notice_class']); ?> fw-semibold mb-1"><?php echo htmlspecialchars($followupDayInfo['notice_text']); ?></div>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
<div class="small text-muted">Próxima llamada: <?php echo htmlspecialchars(cc_test_format_datetime($order['proxima_llamada_at'] ?? null)); ?></div>
|
|
<?php if (!empty($order['fecha_entrega_programada'])): ?>
|
|
<div class="small text-muted">Entrega programada: <?php echo htmlspecialchars(cc_test_format_date($order['fecha_entrega_programada'] ?? null)); ?></div>
|
|
<?php endif; ?>
|
|
<?php if (!empty($order['ruta_contraentrega_pedido_id'])): ?>
|
|
<div class="small text-success">Subido a Ruta Contraentrega #<?php echo (int) $order['ruta_contraentrega_pedido_id']; ?><?php if (!empty($order['ruta_contraentrega_subido_at'])): ?> · <?php echo htmlspecialchars(cc_test_format_datetime($order['ruta_contraentrega_subido_at'] ?? null, '')); ?><?php endif; ?></div>
|
|
<?php endif; ?>
|
|
<?php if (!empty($order['pedido_rotulado_pedido_id'])): ?>
|
|
<div class="small text-primary">Subido a Pedidos Rotulados #<?php echo (int) $order['pedido_rotulado_pedido_id']; ?><?php if (!empty($order['pedido_rotulado_subido_at'])): ?> · <?php echo htmlspecialchars(cc_test_format_datetime($order['pedido_rotulado_subido_at'] ?? null, '')); ?><?php endif; ?></div>
|
|
<?php endif; ?>
|
|
<div class="small text-muted">Última gestión: <?php echo htmlspecialchars(cc_test_format_datetime($order['ultima_gestion_at'] ?? ($order['seguimiento_actualizado'] ?? null), 'Aún no gestionado')); ?></div>
|
|
<div class="small text-muted mt-1">Nota: <?php echo htmlspecialchars(cc_test_display_value($order['nota_seguimiento'], 'Sin nota interna')); ?></div>
|
|
</td>
|
|
<td class="text-center">
|
|
<div class="d-flex flex-column gap-1 align-items-stretch cc-callcenter-actions">
|
|
<?php if (in_array($_SESSION['user_role'] ?? '', ['Administrador', 'admin'], true)): ?>
|
|
<?php
|
|
$orderUserId = $order['user_id'] ?? null;
|
|
$orderUserIdNorm = $orderUserId !== null ? ((int) $orderUserId > 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
$assignFormClass = 'border rounded-3 p-1 text-start shadow-sm cc-callcenter-assign-form';
|
|
$assignFormStyle = '';
|
|
if ($unassigned) {
|
|
$assignFormClass .= ' bg-light';
|
|
} 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';
|
|
}
|
|
|
|
$selectedAssessorKeyForSelect = $unassigned ? '' : ($assignedAssessorKey !== null ? (string) $assignedAssessorKey : '');
|
|
|
|
$buttonLabel = $unassigned
|
|
? 'Asignar pedido'
|
|
: ($assignedAssessorKey !== null ? 'Guardar asignación' : 'Desasignar');
|
|
?>
|
|
|
|
<form method="post" class="<?php echo htmlspecialchars($assignFormClass); ?>"<?php echo $assignFormStyle !== '' ? ' style="' . htmlspecialchars($assignFormStyle, ENT_QUOTES) . '"' : ''; ?>>
|
|
<input type="hidden" name="action" value="assign_assessor">
|
|
<input type="hidden" name="source_key" value="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
|
|
<div class="d-flex justify-content-between align-items-center gap-2 mb-1">
|
|
<div class="small text-uppercase text-muted fw-semibold">Asignar a asesora</div>
|
|
<?php if ($unassigned): ?>
|
|
<span class="badge bg-light text-dark border">Sin asignar</span>
|
|
<?php elseif ($assignedAssessorKey !== null): ?>
|
|
<span class="badge border cc-callcenter-assessor-badge">
|
|
<span class="cc-callcenter-color-dot" aria-hidden="true"></span>
|
|
<?php echo htmlspecialchars((string) ($assessors[$assignedAssessorKey]['label'] ?? $assignedAssessorKey)); ?>
|
|
</span>
|
|
<?php else: ?>
|
|
<span class="badge bg-secondary-subtle text-secondary-emphasis border">Asignado</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="cc-callcenter-assign-row">
|
|
<select name="target_assessor" class="form-select form-select-sm">
|
|
<option value=""<?php echo ($selectedAssessorKeyForSelect === '') ? ' selected' : ''; ?>>Sin asignar</option>
|
|
|
|
<?php if ($unassigned): ?>
|
|
<?php foreach ($assessors as $assessorKey => $assessor): ?>
|
|
<option value="<?php echo htmlspecialchars($assessorKey); ?>"<?php echo ($selectedAssessorKeyForSelect === $assessorKey) ? ' selected' : ''; ?>><?php echo htmlspecialchars($assessor['label']); ?></option>
|
|
<?php endforeach; ?>
|
|
<?php elseif ($assignedAssessorKey !== null): ?>
|
|
<option value="<?php echo htmlspecialchars((string) $assignedAssessorKey); ?>" selected><?php echo htmlspecialchars((string) ($assessors[$assignedAssessorKey]['label'] ?? $assignedAssessorKey)); ?></option>
|
|
<?php endif; ?>
|
|
</select>
|
|
|
|
<button type="submit" class="btn btn-sm btn-primary cc-callcenter-assign-submit cc-callcenter-action-btn"><?php echo htmlspecialchars((string) $buttonLabel); ?></button>
|
|
</div>
|
|
</form>
|
|
<?php endif; ?>
|
|
<?php if (!empty($order['telefono_url'])): ?>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-primary cc-callcenter-action-btn"
|
|
data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>"
|
|
data-modal-id="<?php echo htmlspecialchars($modalId); ?>"
|
|
data-phone="<?php echo htmlspecialchars((string) ($order['celular'] ?? '')); ?>"
|
|
data-order-label="<?php echo htmlspecialchars(cc_test_order_label($order)); ?>"
|
|
data-client-name="<?php echo htmlspecialchars(cc_test_display_value($order['nombre'], 'Cliente sin nombre')); ?>"
|
|
onclick="return registrarLlamada(event, this)">
|
|
<i class="bi bi-telephone-outbound"></i> Llamar / Gestionar
|
|
</button>
|
|
<?php else: ?>
|
|
<button type="button" class="btn btn-sm btn-primary cc-callcenter-action-btn" disabled>Sin teléfono</button>
|
|
<?php endif; ?>
|
|
<?php if (!empty($order['whatsapp_url'])): ?>
|
|
<a href="<?php echo htmlspecialchars($order['whatsapp_url']); ?>" target="_blank" rel="noopener" class="btn btn-sm btn-outline-success cc-callcenter-action-btn">
|
|
<i class="bi bi-whatsapp"></i> WhatsApp
|
|
</a>
|
|
<?php endif; ?>
|
|
<button type="button" class="btn btn-sm btn-outline-dark cc-callcenter-action-btn" data-bs-toggle="modal" data-bs-target="#<?php echo htmlspecialchars($modalId); ?>">
|
|
<i class="bi bi-sliders"></i> Gestionar
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php $rowHtml = ob_get_clean(); echo $rowHtml; ?>
|
|
|
|
<?php ob_start(); ?>
|
|
<div class="modal fade" id="<?php echo htmlspecialchars($modalId); ?>" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header align-items-start gap-2">
|
|
<div class="flex-grow-1 min-w-0">
|
|
<div class="d-flex flex-wrap align-items-center gap-2 mb-1">
|
|
<div class="small text-primary fw-semibold mb-0"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
|
|
<?php if ($followupDayInfo !== null): ?>
|
|
<span class="badge rounded-pill <?php echo htmlspecialchars($followupDayInfo['badge_class']); ?>"><?php echo htmlspecialchars($followupDayInfo['display_label']); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2">
|
|
<h3 class="modal-title h5 mb-0"><?php echo htmlspecialchars(cc_test_display_value($order['nombre'], 'Cliente sin nombre')); ?></h3>
|
|
<?php if ($storeKey === 'otra_tienda'): ?>
|
|
<button type="button" class="btn btn-primary btn-sm px-3" id="subir-logistica-<?php echo htmlspecialchars($order['source_key']); ?>" data-route-pedido-id="<?php echo (int) ($order['ruta_contraentrega_pedido_id'] ?? 0); ?>" data-rotulado-pedido-id="<?php echo (int) ($order['pedido_rotulado_pedido_id'] ?? 0); ?>" onclick="guardarGestion('<?php echo htmlspecialchars($order['source_key']); ?>', this, { subirLogistica: true })"><?php echo htmlspecialchars($subirLogisticaButtonLabel); ?></button>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="small text-muted mt-1"><?php echo htmlspecialchars(cc_test_display_value($order['producto'], 'Sin producto')); ?> · <?php echo htmlspecialchars(cc_test_display_value($order['celular'], 'Sin celular')); ?></div>
|
|
<?php if ($followupDayInfo !== null): ?>
|
|
<div class="small mt-2 <?php echo htmlspecialchars(!empty($followupDayInfo['notice_text']) ? $followupDayInfo['text_class'] : 'text-muted'); ?><?php echo !empty($followupDayInfo['notice_text']) ? ' fw-semibold' : ''; ?>">
|
|
<?php echo htmlspecialchars(!empty($followupDayInfo['notice_text']) ? $followupDayInfo['notice_text'] : ('Seguimiento iniciado el ' . $followupDayInfo['started_at_label'] . '.')); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php $promoFinalProofPath = trim((string) ($order['promo_final_evidencia_path'] ?? '')); ?>
|
|
<?php $promoFinalMoveAvailable = !empty($order['promo_final_habilitado']) && in_array($order['estado'], cc_test_followup_tracking_states(), true); ?>
|
|
<?php if ($promoFinalMoveAvailable || $promoFinalProofPath !== ''): ?>
|
|
<div
|
|
class="mt-2 js-promo-final-controls"
|
|
id="promo-final-controls-<?php echo htmlspecialchars($order['source_key']); ?>"
|
|
data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>"
|
|
data-promo-final-candidate="<?php echo !empty($order['promo_final_habilitado']) ? '1' : '0'; ?>"
|
|
data-has-existing="<?php echo $promoFinalProofPath !== '' ? '1' : '0'; ?>"
|
|
>
|
|
<div class="d-flex flex-wrap gap-2 align-items-center">
|
|
<button type="button" class="btn btn-outline-danger btn-sm px-3 <?php echo ($promoFinalMoveAvailable && $promoFinalProofPath === '') ? '' : 'd-none'; ?>" id="mover-promo-final-<?php echo htmlspecialchars($order['source_key']); ?>" onclick="guardarGestion('<?php echo htmlspecialchars($order['source_key']); ?>', this, { moverPromoFinal: true })">Mover a Promo Final</button>
|
|
<?php if ($promoFinalProofPath !== ''): ?>
|
|
<a href="<?php echo htmlspecialchars($promoFinalProofPath); ?>" class="btn btn-outline-success btn-sm" target="_blank" rel="noopener">Ver sustento Promo Final</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="small mt-2 <?php echo $promoFinalProofPath !== '' ? 'text-success fw-semibold' : 'text-danger-emphasis'; ?>" id="mover-promo-final-note-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<?php if ($promoFinalProofPath !== ''): ?>
|
|
Promo Final con sustento cargado<?php if (!empty($order['promo_final_evidencia_subido_at'])): ?> · <?php echo htmlspecialchars(cc_test_format_datetime($order['promo_final_evidencia_subido_at'] ?? null, '')); ?><?php endif; ?>.
|
|
<?php else: ?>
|
|
Debes subir una imagen de sustento y luego usar este botón para moverlo a Promo Final.
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($storeKey === 'otra_tienda'): ?>
|
|
<div class="<?php echo htmlspecialchars($subirLogisticaNoteClass); ?>" id="subir-logistica-note-<?php echo htmlspecialchars($order['source_key']); ?>"><?php echo $subirLogisticaNoteHtml; ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<button type="button" class="btn-close mt-1" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="border border-primary-subtle rounded-4 bg-primary-subtle p-2 mb-3" id="airDroidModalCard-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2">
|
|
<div>
|
|
<div class="small text-muted mb-1">Llamar / Gestionar</div>
|
|
<h4 class="h6 fw-bold mb-2">Número listo para copiar</h4>
|
|
<div class="fs-4 fw-semibold lh-sm text-primary" id="airDroidPhoneNumber-<?php echo htmlspecialchars($order['source_key']); ?>"><?php echo htmlspecialchars(cc_test_display_value($order['celular'], 'Sin celular')); ?></div>
|
|
</div>
|
|
<div class="d-flex flex-column gap-2">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="airDroidCopyButton-<?php echo htmlspecialchars($order['source_key']); ?>" data-phone="<?php echo htmlspecialchars((string) ($order['celular'] ?? '')); ?>" onclick="copyPhoneToClipboard(this.dataset.phone); return false;">Copiar número</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="openAirDroidWeb()">Abrir AirDroid Web</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="border border-success-subtle rounded-4 bg-white p-3 mb-4 shadow-sm cc-readonly-block" aria-disabled="true" style="user-select:none; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none;">
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
<div>
|
|
<div class="small text-muted mb-1">Origen del cliente</div>
|
|
<h4 class="h6 fw-bold mb-0">Pedido del cliente</h4>
|
|
</div>
|
|
<span class="badge bg-success-subtle text-success-emphasis">Solo lectura / origen</span>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-12">
|
|
<label for="producto-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Producto</label>
|
|
<textarea class="form-control bg-light text-muted" id="producto-<?php echo htmlspecialchars($order['source_key']); ?>" readonly tabindex="-1" aria-readonly="true" spellcheck="false" rows="2" style="pointer-events:none; user-select:none; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; caret-color:transparent; resize:none; overflow-wrap:anywhere; white-space:pre-wrap; line-height:1.35;"><?php echo htmlspecialchars((string) ($order['producto'] ?? '')); ?></textarea>
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="cantidad-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Cantidad</label>
|
|
<input type="text" class="form-control bg-light text-muted" id="cantidad-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['cantidad'] ?? '')); ?>" placeholder="Cantidad" readonly tabindex="-1" aria-readonly="true" style="pointer-events:none; user-select:none; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; caret-color:transparent;">
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="precio-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Precio</label>
|
|
<input type="text" class="form-control bg-light text-muted" id="precio-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['precio'] ?? '')); ?>" placeholder="S/ 0.00" inputmode="decimal" readonly tabindex="-1" aria-readonly="true" style="pointer-events:none; user-select:none; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; caret-color:transparent;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border border-info-subtle rounded-4 bg-white p-3 mb-4 shadow-sm">
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
<div>
|
|
<div class="small text-muted mb-1">Se confirma después</div>
|
|
<h4 class="h6 fw-bold mb-0">Confirmación de pedido</h4>
|
|
</div>
|
|
<span class="badge bg-info-subtle text-info-emphasis">Producto del sistema, cantidad y precio</span>
|
|
</div>
|
|
<div class="row g-3 align-items-end">
|
|
<div class="col-12 col-lg-6">
|
|
<label for="confirmacion_producto-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Producto</label>
|
|
<select class="form-select w-100" id="confirmacion_producto-<?php echo htmlspecialchars($order['source_key']); ?>" title="Seleccione un producto del sistema">
|
|
<option value="">Seleccione un producto del sistema</option>
|
|
<?php foreach ($catalogoProductos as $catalogoProducto): ?>
|
|
<option value="<?php echo htmlspecialchars((string) ($catalogoProducto['nombre'] ?? '')); ?>" <?php echo ((string) ($order['confirmacion_producto'] ?? '') === (string) ($catalogoProducto['nombre'] ?? '')) ? 'selected' : ''; ?>><?php echo htmlspecialchars((string) ($catalogoProducto['nombre'] ?? '')); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="confirmacion_cantidad-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Cantidad</label>
|
|
<input type="text" class="form-control" id="confirmacion_cantidad-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['confirmacion_cantidad'] ?? '')); ?>" placeholder="Cantidad">
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="confirmacion_precio-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Precio</label>
|
|
<input type="text" class="form-control" id="confirmacion_precio-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['confirmacion_precio'] ?? '')); ?>" placeholder="S/ 0.00" inputmode="decimal">
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end mt-3">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm js-toggle-confirmacion-extra" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">Agregar producto adicional</button>
|
|
</div>
|
|
<div class="border rounded-3 bg-light p-3 mt-3 d-none js-confirmacion-extra-block" id="confirmacion_extra_block-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
<div class="fw-semibold">Producto adicional distinto</div>
|
|
<button type="button" class="btn btn-link text-danger text-decoration-none p-0 js-remove-confirmacion-extra" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">Quitar</button>
|
|
</div>
|
|
<div class="row g-3 align-items-end">
|
|
<div class="col-12 col-lg-6">
|
|
<label for="confirmacion_producto_extra-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Producto adicional</label>
|
|
<select class="form-select w-100" id="confirmacion_producto_extra-<?php echo htmlspecialchars($order['source_key']); ?>" title="Seleccione un producto adicional">
|
|
<option value="">Seleccione un producto adicional</option>
|
|
<?php foreach ($catalogoProductos as $catalogoProducto): ?>
|
|
<option value="<?php echo htmlspecialchars((string) ($catalogoProducto['nombre'] ?? '')); ?>" <?php echo ((string) ($order['confirmacion_producto_extra'] ?? '') === (string) ($catalogoProducto['nombre'] ?? '')) ? 'selected' : ''; ?>><?php echo htmlspecialchars((string) ($catalogoProducto['nombre'] ?? '')); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="confirmacion_cantidad_extra-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Cantidad</label>
|
|
<input type="text" class="form-control" id="confirmacion_cantidad_extra-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['confirmacion_cantidad_extra'] ?? '')); ?>" placeholder="Cantidad">
|
|
</div>
|
|
<div class="col-sm-6 col-lg-3">
|
|
<label for="confirmacion_precio_extra-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Precio</label>
|
|
<input type="text" class="form-control" id="confirmacion_precio_extra-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['confirmacion_precio_extra'] ?? '')); ?>" placeholder="S/ 0.00" inputmode="decimal">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-lg-3 col-md-6">
|
|
<div class="border rounded p-3 h-100 bg-light-subtle">
|
|
<div class="small text-muted">Estado actual</div>
|
|
<div class="fw-semibold"><?php echo htmlspecialchars(cc_test_state_label($order['estado'])); ?></div>
|
|
<?php if ($semaforoCuenta !== null): ?>
|
|
<div class="mt-2">
|
|
<span class="badge rounded-pill <?php echo htmlspecialchars($semaforoCuenta['class']); ?>">Seguimiento <?php echo htmlspecialchars($semaforoCuenta['label']); ?></span>
|
|
</div>
|
|
<div class="small text-muted mt-2">Enviado hace <?php echo (int) $semaforoCuenta['days']; ?> día<?php echo ((int) $semaforoCuenta['days'] === 1) ? '' : 's'; ?> · <?php echo htmlspecialchars($semaforoCuenta['description']); ?></div>
|
|
<?php else: ?>
|
|
<div class="small text-muted mt-2">El semáforo se activa cuando marques “Se envió número de cuenta”.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<div class="border rounded p-3 h-100 bg-light-subtle">
|
|
<div class="small text-muted">Total llamadas</div>
|
|
<div class="fw-semibold"><span class="js-call-count-number" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>"><?php echo (int) $order['total_llamadas']; ?></span></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<div class="border rounded p-3 h-100 bg-light-subtle">
|
|
<div class="small text-muted"><?php echo cc_test_requires_delivery_date($order['estado']) ? 'Entrega programada' : 'Próxima llamada'; ?></div>
|
|
<div class="fw-semibold"><?php echo htmlspecialchars(cc_test_requires_delivery_date($order['estado']) ? cc_test_format_date($order['fecha_entrega_programada'] ?? null) : cc_test_format_datetime($order['proxima_llamada_at'] ?? null)); ?></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<div class="border rounded p-3 h-100 bg-light-subtle">
|
|
<div class="small text-muted">Ingreso en Drive</div>
|
|
<div class="fw-semibold"><?php echo htmlspecialchars(cc_test_format_datetime($order['import_id'] ?? null, 'Sin fecha')); ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-7">
|
|
<h4 class="h6 fw-bold mb-3">Gestión comercial</h4>
|
|
<div class="row g-3">
|
|
<div class="col-md-4">
|
|
<label for="estado-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Estado</label>
|
|
<select class="form-select" id="estado-<?php echo htmlspecialchars($order['source_key']); ?>" onchange="toggleAgendaFields('<?php echo htmlspecialchars($order['source_key']); ?>')">
|
|
<?php foreach (cc_test_valid_states() as $estadoOption): ?>
|
|
<option value="<?php echo htmlspecialchars($estadoOption); ?>" <?php echo $order['estado'] === $estadoOption ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars(cc_test_state_label($estadoOption)); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4 js-next-call-group" id="next-call-group-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="proxima-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Próxima llamada</label>
|
|
<input type="datetime-local" class="form-control" id="proxima-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars(cc_test_format_datetime_input($order['proxima_llamada_at'] ?? null)); ?>">
|
|
</div>
|
|
<div class="col-md-4 js-delivery-group <?php echo cc_test_requires_delivery_date($order['estado']) ? '' : 'd-none'; ?>" id="delivery-group-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="fecha-entrega-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Fecha de entrega</label>
|
|
<input type="date" class="form-control" id="fecha-entrega-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars(cc_test_format_date_input($order['fecha_entrega_programada'] ?? null)); ?>">
|
|
<div class="form-text">Úsalo cuando el cliente quede en Confirmado fecha.</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<label for="nota-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">COLOCAR AQUI OBSERVACION DEL CLIENTE O (DEDICATORIA O GRABADO)</label>
|
|
<textarea class="form-control" id="nota-<?php echo htmlspecialchars($order['source_key']); ?>" rows="3" placeholder="Ej.: Solicita dedicatoria para hija María, Ej.: Desea antes de las 4PM"><?php echo htmlspecialchars($order['nota_seguimiento']); ?></textarea>
|
|
</div>
|
|
<?php $numeroCuentaSedeIdSeleccionado = trim((string) ($order['numero_cuenta_sede_id'] ?? '')); ?>
|
|
<?php $numeroCuentaDniSeleccionado = trim((string) ($order['numero_cuenta_dni'] ?? '')); ?>
|
|
<?php $mostrarCamposNumeroCuenta = cc_test_requires_account_number_fields($order['estado']); ?>
|
|
<div class="col-md-6 js-numero-cuenta-group <?php echo $mostrarCamposNumeroCuenta ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="numero_cuenta_sede_id-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">SEDE / ID</label>
|
|
<input type="text" class="form-control" id="numero_cuenta_sede_id-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars($numeroCuentaSedeIdSeleccionado); ?>" placeholder="Ej.: SJL / 1542">
|
|
<div class="form-text">Solo aparece en <strong>SE ENVIO NUMERO DE CUENTA</strong>.</div>
|
|
</div>
|
|
<div class="col-md-6 js-numero-cuenta-group <?php echo $mostrarCamposNumeroCuenta ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="numero_cuenta_dni-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">N° DNI</label>
|
|
<input type="text" class="form-control" id="numero_cuenta_dni-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars($numeroCuentaDniSeleccionado); ?>" placeholder="Ej.: 76543210">
|
|
</div>
|
|
<?php $promoFinalProofPath = trim((string) ($order['promo_final_evidencia_path'] ?? '')); ?>
|
|
<?php $canceladoProofPath = trim((string) ($order['cancelado_evidencia_path'] ?? '')); ?>
|
|
<?php $mostrarPromoFinalProof = !empty($order['promo_final_habilitado']) || $promoFinalProofPath !== ''; ?>
|
|
<?php $mostrarCanceladoProof = $order['estado'] === 'CANCELADO' || $canceladoProofPath !== ''; ?>
|
|
<div class="col-12 js-promo-final-proof-group <?php echo $mostrarPromoFinalProof ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>" data-promo-final-candidate="<?php echo !empty($order['promo_final_habilitado']) ? '1' : '0'; ?>" data-has-existing="<?php echo $promoFinalProofPath !== '' ? '1' : '0'; ?>">
|
|
<label for="promo_final_evidencia-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Imagen de sustento para Promo Final</label>
|
|
<input type="file" class="form-control" id="promo_final_evidencia-<?php echo htmlspecialchars($order['source_key']); ?>" accept=".jpg,.jpeg,.png,.webp">
|
|
<div class="form-text">Obligatoria al mover el pedido a <strong>Promo Final</strong> desde el Día 4. La supervisora podrá revisarla.</div>
|
|
<?php if ($promoFinalProofPath !== ''): ?>
|
|
<div class="small text-success mt-2">
|
|
Sustento actual: <a href="<?php echo htmlspecialchars($promoFinalProofPath); ?>" target="_blank" rel="noopener">ver imagen</a><?php if (!empty($order['promo_final_evidencia_subido_at'])): ?> · <?php echo htmlspecialchars(cc_test_format_datetime($order['promo_final_evidencia_subido_at'] ?? null, '')); ?><?php endif; ?>.
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="col-12 js-cancelado-proof-group <?php echo $mostrarCanceladoProof ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>" data-has-existing="<?php echo $canceladoProofPath !== '' ? '1' : '0'; ?>">
|
|
<label for="cancelado_evidencia-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Imagen de sustento para Cancelado</label>
|
|
<input type="file" class="form-control" id="cancelado_evidencia-<?php echo htmlspecialchars($order['source_key']); ?>" accept=".jpg,.jpeg,.png,.webp">
|
|
<div class="form-text">Obligatoria cuando el estado sea <strong>Cancelado</strong>. Así evitas cancelaciones sin motivo.</div>
|
|
<?php if ($canceladoProofPath !== ''): ?>
|
|
<div class="small text-success mt-2">
|
|
Sustento actual: <a href="<?php echo htmlspecialchars($canceladoProofPath); ?>" target="_blank" rel="noopener">ver imagen</a><?php if (!empty($order['cancelado_evidencia_subido_at'])): ?> · <?php echo htmlspecialchars(cc_test_format_datetime($order['cancelado_evidencia_subido_at'] ?? null, '')); ?><?php endif; ?>.
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<h4 class="h6 fw-bold mb-3">Datos editables del pedido</h4>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label for="direccion-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Dirección</label>
|
|
<textarea class="form-control" id="direccion-<?php echo htmlspecialchars($order['source_key']); ?>" rows="2"><?php echo htmlspecialchars((string) ($order['direccion'] ?? '')); ?></textarea>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="referencia-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Referencia</label>
|
|
<textarea class="form-control" id="referencia-<?php echo htmlspecialchars($order['source_key']); ?>" rows="2"><?php echo htmlspecialchars((string) ($order['referencia'] ?? '')); ?></textarea>
|
|
</div>
|
|
<?php $agenciaSeleccionada = cc_test_normalize_shipping_agency($order['agencia'] ?? '') ?? strtoupper(trim((string) ($order['agencia'] ?? ''))); ?>
|
|
<?php $sedeAgenciaSeleccionada = trim((string) ($order['sede_agencia'] ?? '')); ?>
|
|
<?php $montoAdelantadoSeleccionado = trim((string) ($order['monto_adelantado'] ?? '')); ?>
|
|
<?php $mostrarCamposEnvio = cc_test_requires_shipping_details($order['estado']); ?>
|
|
<div class="col-md-4">
|
|
<label for="sede-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Departamento</label>
|
|
<select class="form-select js-location-department" id="sede-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<option value="">Seleccione departamento</option>
|
|
<?php foreach ($departamentosContraentrega as $departamentoOption): ?>
|
|
<option value="<?php echo htmlspecialchars($departamentoOption); ?>" <?php echo $departamentoSeleccionado === $departamentoOption ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($departamentoOption); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php if ($departamentoSeleccionado !== '' && !in_array($departamentoSeleccionado, $departamentosContraentrega, true)): ?>
|
|
<option value="<?php echo htmlspecialchars($departamentoSeleccionado); ?>" selected>
|
|
<?php echo htmlspecialchars($departamentoSeleccionado); ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="ciudad-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Provincia</label>
|
|
<select class="form-select js-location-province" id="ciudad-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<option value="">Seleccione provincia</option>
|
|
<?php foreach ($provinciasSeleccionadas as $provinciaOption): ?>
|
|
<option value="<?php echo htmlspecialchars($provinciaOption); ?>" <?php echo $provinciaSeleccionada === $provinciaOption ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($provinciaOption); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php if ($provinciaSeleccionada !== '' && !in_array($provinciaSeleccionada, $provinciasSeleccionadas, true)): ?>
|
|
<option value="<?php echo htmlspecialchars($provinciaSeleccionada); ?>" selected>
|
|
<?php echo htmlspecialchars($provinciaSeleccionada); ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="distrito_select-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Distrito</label>
|
|
<select class="form-select js-location-district <?php echo empty($distritosSeleccionados) ? 'd-none' : ''; ?>" id="distrito_select-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<option value="">Seleccione primero provincia</option>
|
|
<?php foreach ($distritosSeleccionados as $distritoOption): ?>
|
|
<option value="<?php echo htmlspecialchars($distritoOption); ?>" <?php echo $distritoSeleccionado === $distritoOption ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($distritoOption); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php if ($distritoSeleccionado !== '' && !in_array($distritoSeleccionado, $distritosSeleccionados, true)): ?>
|
|
<option value="<?php echo htmlspecialchars($distritoSeleccionado); ?>" selected>
|
|
<?php echo htmlspecialchars($distritoSeleccionado); ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
<input type="text" class="form-control mt-2 js-location-district-manual <?php echo empty($distritosSeleccionados) ? '' : 'd-none'; ?>" id="distrito_manual-<?php echo htmlspecialchars($order['source_key']); ?>" placeholder="Escriba el distrito si aún no está en cobertura" value="<?php echo htmlspecialchars($distritoSeleccionado); ?>">
|
|
<input type="hidden" id="distrito-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars($distritoSeleccionado); ?>">
|
|
<div class="form-text">Si la provincia aún no tiene cobertura cargada, podrás escribir el distrito manualmente.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="coordenadas-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Coordenadas</label>
|
|
<input type="text" class="form-control" id="coordenadas-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['coordenadas'] ?? '')); ?>" inputmode="decimal" autocomplete="off" spellcheck="false" placeholder="-12.082029, -77.069024">
|
|
<div class="form-text">Obligatorias para <strong>Subir pedido</strong> a Ruta Contraentrega.</div>
|
|
</div>
|
|
<div class="col-md-4 js-envio-group <?php echo $mostrarCamposEnvio ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="agencia-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Agencia</label>
|
|
<select class="form-select" id="agencia-<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<option value="">Seleccione agencia</option>
|
|
<?php foreach (cc_test_shipping_agency_options() as $agenciaOption): ?>
|
|
<option value="<?php echo htmlspecialchars($agenciaOption); ?>" <?php echo $agenciaSeleccionada === $agenciaOption ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($agenciaOption); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php if ($agenciaSeleccionada !== '' && !in_array($agenciaSeleccionada, cc_test_shipping_agency_options(), true)): ?>
|
|
<option value="<?php echo htmlspecialchars($agenciaSeleccionada); ?>" selected>
|
|
<?php echo htmlspecialchars($agenciaSeleccionada); ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4 js-envio-group <?php echo $mostrarCamposEnvio ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="sede_agencia-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Sede de envío</label>
|
|
<input type="text" class="form-control" id="sede_agencia-<?php echo htmlspecialchars($order['source_key']); ?>" placeholder="Seleccione o escriba la sede de envío" value="<?php echo htmlspecialchars($sedeAgenciaSeleccionada); ?>" <?php echo ($agenciaSeleccionada === 'SHALOM' && !empty($sedesShalom)) ? 'list="cc-sedes-shalom-list"' : ''; ?>>
|
|
</div>
|
|
<div class="col-md-2 js-envio-group <?php echo $mostrarCamposEnvio ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="dni-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">DNI</label>
|
|
<input type="text" class="form-control" id="dni-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars((string) ($order['dni'] ?? '')); ?>">
|
|
<div class="form-text">Obligatorio para <strong>CONFIRMADO ENVIO</strong>.</div>
|
|
</div>
|
|
<div class="col-md-2 js-envio-group <?php echo $mostrarCamposEnvio ? '' : 'd-none'; ?>" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>">
|
|
<label for="monto_adelantado-<?php echo htmlspecialchars($order['source_key']); ?>" class="form-label">Monto de adelanto</label>
|
|
<input type="text" class="form-control" id="monto_adelantado-<?php echo htmlspecialchars($order['source_key']); ?>" value="<?php echo htmlspecialchars($montoAdelantadoSeleccionado); ?>" inputmode="decimal" placeholder="0.00">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-5">
|
|
<div class="mb-4 border rounded p-4 bg-light-subtle">
|
|
<div class="fw-semibold mb-3 fs-5">Origen vs edición</div>
|
|
<div class="mb-1"><strong>Dirección Drive:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['direccion_drive'] ?? null)); ?></div>
|
|
<div class="mb-1"><strong>Referencia Drive:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['referencia_drive'] ?? null)); ?></div>
|
|
<div class="mb-1"><strong>Distrito 1:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['distrito_drive'] ?? null)); ?></div>
|
|
<div class="mb-1"><strong>Distrito:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['distrito'] ?? null)); ?></div>
|
|
<div class="mb-1"><strong>Observación Drive:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['observaciones_drive'] ?? null)); ?></div>
|
|
<div><strong>Coordenadas Drive:</strong> <?php echo htmlspecialchars(cc_test_display_value($order['coordenadas_drive'] ?? null)); ?></div>
|
|
</div>
|
|
|
|
<h4 class="h6 fw-bold mb-3">Historial de llamadas</h4>
|
|
<?php if (empty($historial)): ?>
|
|
<div class="border rounded p-3 text-muted small">Aún no hay llamadas registradas para este cliente.</div>
|
|
<?php else: ?>
|
|
<div class="list-group list-group-flush border rounded overflow-hidden">
|
|
<?php foreach ($historial as $h): ?>
|
|
<div class="list-group-item small py-3">
|
|
<div class="d-flex justify-content-between gap-2">
|
|
<span class="fw-semibold"><?php echo htmlspecialchars($h['asesor'] ?? 'Asesor'); ?></span>
|
|
<span class="text-muted"><?php echo htmlspecialchars(date('d/m/Y H:i', strtotime($h['fecha_llamada']))); ?></span>
|
|
</div>
|
|
<div class="text-primary fw-semibold mt-1"><?php echo htmlspecialchars($h['resultado']); ?></div>
|
|
<?php if (!empty($h['observacion'])): ?>
|
|
<div class="text-muted mt-1"><?php echo htmlspecialchars($h['observacion']); ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer d-flex justify-content-between flex-wrap gap-2">
|
|
<div class="small text-muted">
|
|
<?php if ($storeKey === 'otra_tienda'): ?>
|
|
<strong>Guardar gestión</strong> solo guarda el historial. Para enviarlo a logística, usa el <strong>botón del encabezado</strong> junto al nombre del cliente.
|
|
<?php else: ?>
|
|
Los cambios se guardan en la base local del módulo de prueba.
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="d-flex gap-2 ms-auto flex-wrap">
|
|
<?php if (in_array($_SESSION['user_role'] ?? '', ['Administrador', 'admin'], true)): ?>
|
|
<button type="button" class="btn btn-outline-danger" onclick="eliminarPedido('<?php echo htmlspecialchars($order['source_key']); ?>', this)">Eliminar del panel</button>
|
|
<?php endif; ?>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
|
<button type="button" class="btn btn-primary" onclick="guardarGestion('<?php echo htmlspecialchars($order['source_key']); ?>', this)">Guardar gestión</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php $modalsHtml[] = ob_get_clean(); ?>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<?php if (!empty($modalsHtml)): ?>
|
|
<?php echo implode("
|
|
", $modalsHtml); ?>
|
|
<?php endif; ?>
|
|
|
|
<div class="position-fixed bottom-0 end-0 p-3" id="airDroidAssistPanel" style="z-index: 1080; max-width: 26rem; width: min(26rem, calc(100vw - 1.5rem));">
|
|
<div class="card border-primary shadow-lg d-none" id="airDroidAssistCard">
|
|
<div class="card-header bg-primary text-white d-flex align-items-start justify-content-between gap-3">
|
|
<div>
|
|
<div class="small opacity-75">Llamada preparada para AirDroid</div>
|
|
<h3 class="h5 mb-0">Número listo para copiar</h3>
|
|
</div>
|
|
<button type="button" class="btn-close btn-close-white" id="airDroidHideButton" aria-label="Ocultar"></button>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="rounded-4 border bg-light-subtle p-2">
|
|
<div class="small text-muted">Pedido</div>
|
|
<div class="fw-semibold" id="airDroidOrderLabel">-</div>
|
|
<div class="small text-muted mt-2">Cliente</div>
|
|
<div class="fw-semibold" id="airDroidClientName">-</div>
|
|
<div class="small text-muted mt-2">Número</div>
|
|
<div class="fs-5 fw-semibold lh-sm text-primary" id="airDroidPhoneNumber">-</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer d-flex flex-wrap justify-content-end gap-2">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="airDroidCopyButton">Copiar número</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="airDroidOpenButton">Abrir AirDroid Web</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if (!empty($sedesShalom)): ?>
|
|
<datalist id="cc-sedes-shalom-list">
|
|
<?php foreach ($sedesShalom as $sedeShalomOption): ?>
|
|
<option value="<?php echo htmlspecialchars($sedeShalomOption); ?>"></option>
|
|
<?php endforeach; ?>
|
|
</datalist>
|
|
<?php endif; ?>
|
|
</main>
|
|
|
|
<script>
|
|
const provinciasPorDepartamento = <?php echo json_encode($provinciasPorDepartamentoContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
|
const distritosPorProvincia = <?php echo json_encode($distritosPorProvinciaContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
|
|
|
function getLocationControls(sourceKey) {
|
|
return {
|
|
department: document.getElementById('sede-' + sourceKey),
|
|
province: document.getElementById('ciudad-' + sourceKey),
|
|
districtSelect: document.getElementById('distrito_select-' + sourceKey),
|
|
districtManual: document.getElementById('distrito_manual-' + sourceKey),
|
|
districtHidden: document.getElementById('distrito-' + sourceKey)
|
|
};
|
|
}
|
|
|
|
function syncDistrictHidden(sourceKey, value) {
|
|
const controls = getLocationControls(sourceKey);
|
|
if (controls.districtHidden) {
|
|
controls.districtHidden.value = value || '';
|
|
}
|
|
}
|
|
|
|
function renderDistrictOptions(sourceKey, preserveSelection = true) {
|
|
const controls = getLocationControls(sourceKey);
|
|
if (!controls.province || !controls.districtSelect || !controls.districtManual || !controls.districtHidden) {
|
|
return;
|
|
}
|
|
|
|
const province = controls.province.value || '';
|
|
const currentValue = preserveSelection ? (controls.districtHidden.value || controls.districtSelect.value || controls.districtManual.value || '') : '';
|
|
const districts = province ? (distritosPorProvincia[province] || []) : [];
|
|
|
|
controls.districtSelect.innerHTML = '';
|
|
|
|
const emptyOption = document.createElement('option');
|
|
emptyOption.value = '';
|
|
emptyOption.textContent = province ? (districts.length ? 'Seleccione distrito' : 'Sin cobertura registrada') : 'Seleccione primero provincia';
|
|
controls.districtSelect.appendChild(emptyOption);
|
|
|
|
if (!province) {
|
|
controls.districtSelect.classList.remove('d-none');
|
|
controls.districtSelect.disabled = true;
|
|
controls.districtManual.classList.add('d-none');
|
|
controls.districtManual.value = '';
|
|
syncDistrictHidden(sourceKey, '');
|
|
return;
|
|
}
|
|
|
|
if (districts.length > 0) {
|
|
districts.forEach(function(distrito) {
|
|
const option = document.createElement('option');
|
|
option.value = distrito;
|
|
option.textContent = distrito;
|
|
if (distrito === currentValue) {
|
|
option.selected = true;
|
|
}
|
|
controls.districtSelect.appendChild(option);
|
|
});
|
|
|
|
if (currentValue && !districts.includes(currentValue)) {
|
|
const legacyOption = document.createElement('option');
|
|
legacyOption.value = currentValue;
|
|
legacyOption.textContent = currentValue + ' (actual)';
|
|
legacyOption.selected = true;
|
|
controls.districtSelect.appendChild(legacyOption);
|
|
}
|
|
|
|
controls.districtSelect.classList.remove('d-none');
|
|
controls.districtSelect.disabled = false;
|
|
controls.districtManual.classList.add('d-none');
|
|
controls.districtManual.value = '';
|
|
controls.districtSelect.value = currentValue || controls.districtSelect.value || '';
|
|
syncDistrictHidden(sourceKey, controls.districtSelect.value);
|
|
return;
|
|
}
|
|
|
|
controls.districtSelect.classList.add('d-none');
|
|
controls.districtSelect.disabled = true;
|
|
controls.districtManual.classList.remove('d-none');
|
|
controls.districtManual.value = currentValue;
|
|
syncDistrictHidden(sourceKey, currentValue);
|
|
}
|
|
|
|
function renderProvinceOptions(sourceKey, preserveSelection = true) {
|
|
const controls = getLocationControls(sourceKey);
|
|
if (!controls.department || !controls.province) {
|
|
return;
|
|
}
|
|
|
|
const department = controls.department.value || '';
|
|
const currentValue = preserveSelection ? (controls.province.value || '') : '';
|
|
const provinces = department ? (provinciasPorDepartamento[department] || []) : [];
|
|
|
|
controls.province.innerHTML = '';
|
|
|
|
const emptyOption = document.createElement('option');
|
|
emptyOption.value = '';
|
|
emptyOption.textContent = department ? (provinces.length ? 'Seleccione provincia' : 'Sin cobertura registrada') : 'Seleccione primero departamento';
|
|
controls.province.appendChild(emptyOption);
|
|
|
|
provinces.forEach(function(provincia) {
|
|
const option = document.createElement('option');
|
|
option.value = provincia;
|
|
option.textContent = provincia;
|
|
if (provincia === currentValue) {
|
|
option.selected = true;
|
|
}
|
|
controls.province.appendChild(option);
|
|
});
|
|
|
|
if (currentValue && !provinces.includes(currentValue)) {
|
|
const legacyOption = document.createElement('option');
|
|
legacyOption.value = currentValue;
|
|
legacyOption.textContent = currentValue + ' (actual)';
|
|
legacyOption.selected = true;
|
|
controls.province.appendChild(legacyOption);
|
|
}
|
|
|
|
controls.province.disabled = !department && currentValue === '';
|
|
controls.province.value = currentValue || controls.province.value || '';
|
|
renderDistrictOptions(sourceKey, preserveSelection);
|
|
}
|
|
|
|
function updateShippingSedeList(sourceKey) {
|
|
const agenciaSelect = document.getElementById('agencia-' + sourceKey);
|
|
const sedeInput = document.getElementById('sede_agencia-' + sourceKey);
|
|
const sedesListId = 'cc-sedes-shalom-list';
|
|
|
|
if (!agenciaSelect || !sedeInput) {
|
|
return;
|
|
}
|
|
|
|
if (agenciaSelect.value === 'SHALOM' && document.getElementById(sedesListId)) {
|
|
sedeInput.setAttribute('list', sedesListId);
|
|
} else {
|
|
sedeInput.removeAttribute('list');
|
|
}
|
|
}
|
|
|
|
function updateLogisticaButton(sourceKey) {
|
|
const estado = document.getElementById('estado-' + sourceKey)?.value || '';
|
|
const button = document.getElementById('subir-logistica-' + sourceKey);
|
|
const note = document.getElementById('subir-logistica-note-' + sourceKey);
|
|
|
|
if (!button) {
|
|
return;
|
|
}
|
|
|
|
const routeId = parseInt(button.dataset.routePedidoId || '0', 10);
|
|
const rotuladoId = parseInt(button.dataset.rotuladoPedidoId || '0', 10);
|
|
|
|
if (estado === 'CONFIRMADO CONTRAENTREGA') {
|
|
button.disabled = false;
|
|
button.textContent = routeId > 0 ? 'Actualizar en ruta' : 'Subir a ruta';
|
|
if (note) {
|
|
note.className = 'small mt-2 ' + (routeId > 0 ? 'text-success fw-semibold' : 'text-warning-emphasis');
|
|
note.innerHTML = routeId > 0
|
|
? 'En Ruta Contraentrega #' + routeId + '. Si cambias algo, usa este botón para actualizarlo.'
|
|
: '<strong>PENDIENTE A SUBIR</strong>: este pedido ya está en <strong>CONFIRMADO CONTRAENTREGA</strong>. Súbelo a Ruta Contraentrega con este botón.';
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (estado === 'CONFIRMADO ENVIO') {
|
|
button.disabled = false;
|
|
button.textContent = rotuladoId > 0 ? 'Actualizar rotulado' : 'Subir a rotulados';
|
|
if (note) {
|
|
note.className = 'small mt-2 ' + (rotuladoId > 0 ? 'text-success fw-semibold' : 'text-warning-emphasis');
|
|
note.innerHTML = rotuladoId > 0
|
|
? 'En Pedidos Rotulados #' + rotuladoId + '. Si cambias algo, usa este botón para actualizarlo.'
|
|
: '<strong>PENDIENTE A SUBIR</strong>: este pedido ya está en <strong>CONFIRMADO ENVIO</strong>. Súbelo a Pedidos Rotulados con este botón.';
|
|
}
|
|
return;
|
|
}
|
|
|
|
button.disabled = true;
|
|
button.textContent = 'Subir pedido';
|
|
if (note) {
|
|
note.className = 'small mt-2 text-muted';
|
|
note.textContent = 'Selecciona CONFIRMADO CONTRAENTREGA o CONFIRMADO ENVIO para enviarlo a logística.';
|
|
}
|
|
}
|
|
|
|
function updatePromoFinalControls(sourceKey) {
|
|
const estado = document.getElementById('estado-' + sourceKey)?.value || '';
|
|
const followupStates = ['POR LLAMAR', 'DEVOLVER LLAMADA', 'OBSERVADO', 'SE ENVIO NUMERO DE CUENTA'];
|
|
|
|
document.querySelectorAll('.js-promo-final-controls[data-source-key="' + sourceKey + '"]').forEach(block => {
|
|
const isCandidate = block.dataset.promoFinalCandidate === '1';
|
|
const hasExisting = block.dataset.hasExisting === '1';
|
|
const canUsePromoFinal = isCandidate && followupStates.includes(estado);
|
|
block.classList.toggle('d-none', !hasExisting && !canUsePromoFinal);
|
|
|
|
const moveButton = block.querySelector('button[id^="mover-promo-final-"]');
|
|
if (moveButton) {
|
|
moveButton.classList.toggle('d-none', !canUsePromoFinal || hasExisting);
|
|
}
|
|
});
|
|
|
|
document.querySelectorAll('.js-promo-final-proof-group[data-source-key="' + sourceKey + '"]').forEach(group => {
|
|
const isCandidate = group.dataset.promoFinalCandidate === '1';
|
|
const hasExisting = group.dataset.hasExisting === '1';
|
|
const canUsePromoFinal = isCandidate && followupStates.includes(estado);
|
|
group.classList.toggle('d-none', !hasExisting && !canUsePromoFinal);
|
|
});
|
|
}
|
|
|
|
function updateCanceladoEvidenceControls(sourceKey) {
|
|
const estado = document.getElementById('estado-' + sourceKey)?.value || '';
|
|
document.querySelectorAll('.js-cancelado-proof-group[data-source-key="' + sourceKey + '"]').forEach(group => {
|
|
const hasExisting = group.dataset.hasExisting === '1';
|
|
group.classList.toggle('d-none', !hasExisting && estado !== 'CANCELADO');
|
|
});
|
|
}
|
|
|
|
function toggleAgendaFields(sourceKey) {
|
|
const estado = document.getElementById('estado-' + sourceKey)?.value || '';
|
|
const nextCallGroup = document.getElementById('next-call-group-' + sourceKey);
|
|
const deliveryGroup = document.getElementById('delivery-group-' + sourceKey);
|
|
const nextCallInput = document.getElementById('proxima-' + sourceKey);
|
|
const deliveryInput = document.getElementById('fecha-entrega-' + sourceKey);
|
|
const needsDeliveryDate = estado === 'CONFIRMADO CONTRAENTREGA';
|
|
const needsShippingDetails = estado === 'CONFIRMADO ENVIO';
|
|
const needsAccountNumberDetails = estado === 'SE ENVIO NUMERO DE CUENTA';
|
|
const needsNextCall = ['POR LLAMAR', 'DEVOLVER LLAMADA', 'OBSERVADO'].includes(estado);
|
|
|
|
if (nextCallGroup) {
|
|
nextCallGroup.classList.toggle('d-none', !needsNextCall);
|
|
}
|
|
if (deliveryGroup) {
|
|
deliveryGroup.classList.toggle('d-none', !needsDeliveryDate);
|
|
}
|
|
document.querySelectorAll('.js-envio-group[data-source-key="' + sourceKey + '"]').forEach(group => {
|
|
group.classList.toggle('d-none', !needsShippingDetails);
|
|
});
|
|
document.querySelectorAll('.js-numero-cuenta-group[data-source-key="' + sourceKey + '"]').forEach(group => {
|
|
group.classList.toggle('d-none', !needsAccountNumberDetails);
|
|
});
|
|
if (!needsNextCall && nextCallInput) {
|
|
nextCallInput.value = '';
|
|
}
|
|
if (!needsDeliveryDate && deliveryInput) {
|
|
deliveryInput.value = '';
|
|
}
|
|
|
|
updateShippingSedeList(sourceKey);
|
|
updateLogisticaButton(sourceKey);
|
|
updatePromoFinalControls(sourceKey);
|
|
updateCanceladoEvidenceControls(sourceKey);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.querySelectorAll('select[id^="estado-"]').forEach(select => {
|
|
toggleAgendaFields(select.id.replace('estado-', ''));
|
|
});
|
|
|
|
document.querySelectorAll('select[id^="agencia-"]').forEach(select => {
|
|
const sourceKey = select.id.replace('agencia-', '');
|
|
updateShippingSedeList(sourceKey);
|
|
select.addEventListener('change', () => {
|
|
updateShippingSedeList(sourceKey);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('select[id^="sede-"]').forEach(select => {
|
|
const sourceKey = select.id.replace('sede-', '');
|
|
renderProvinceOptions(sourceKey, true);
|
|
select.addEventListener('change', () => {
|
|
renderProvinceOptions(sourceKey, false);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('select[id^="ciudad-"]').forEach(select => {
|
|
const sourceKey = select.id.replace('ciudad-', '');
|
|
select.addEventListener('change', () => {
|
|
renderDistrictOptions(sourceKey, false);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('select[id^="distrito_select-"]').forEach(select => {
|
|
const sourceKey = select.id.replace('distrito_select-', '');
|
|
select.addEventListener('change', () => {
|
|
syncDistrictHidden(sourceKey, select.value);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('input[id^="distrito_manual-"]').forEach(input => {
|
|
const sourceKey = input.id.replace('distrito_manual-', '');
|
|
input.addEventListener('input', () => {
|
|
syncDistrictHidden(sourceKey, input.value);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('select[id^="confirmacion_producto-"]').forEach(select => {
|
|
const sourceKey = select.id.replace('confirmacion_producto-', '');
|
|
const syncTitle = () => {
|
|
const selectedOption = select.selectedOptions && select.selectedOptions[0] ? select.selectedOptions[0] : null;
|
|
const label = selectedOption && selectedOption.textContent ? selectedOption.textContent.trim() : (select.value || 'Sin producto seleccionado');
|
|
select.title = label;
|
|
};
|
|
syncTitle();
|
|
select.addEventListener('change', syncTitle);
|
|
});
|
|
|
|
document.querySelectorAll('.js-toggle-confirmacion-extra').forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const sourceKey = button.dataset.sourceKey || '';
|
|
const block = document.getElementById('confirmacion_extra_block-' + sourceKey);
|
|
if (!block) return;
|
|
block.classList.remove('d-none');
|
|
button.classList.add('d-none');
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.js-remove-confirmacion-extra').forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const sourceKey = button.dataset.sourceKey || '';
|
|
const block = document.getElementById('confirmacion_extra_block-' + sourceKey);
|
|
const toggle = document.querySelector('.js-toggle-confirmacion-extra[data-source-key="' + sourceKey + '"]');
|
|
if (block) {
|
|
block.classList.add('d-none');
|
|
const productoExtra = document.getElementById('confirmacion_producto_extra-' + sourceKey);
|
|
const cantidadExtra = document.getElementById('confirmacion_cantidad_extra-' + sourceKey);
|
|
const precioExtra = document.getElementById('confirmacion_precio_extra-' + sourceKey);
|
|
if (productoExtra) productoExtra.value = '';
|
|
if (cantidadExtra) cantidadExtra.value = '';
|
|
if (precioExtra) precioExtra.value = '';
|
|
}
|
|
if (toggle) {
|
|
toggle.classList.remove('d-none');
|
|
}
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.js-confirmacion-extra-block').forEach(block => {
|
|
const sourceKey = block.id.replace('confirmacion_extra_block-', '');
|
|
const productoExtra = document.getElementById('confirmacion_producto_extra-' + sourceKey);
|
|
const cantidadExtra = document.getElementById('confirmacion_cantidad_extra-' + sourceKey);
|
|
const precioExtra = document.getElementById('confirmacion_precio_extra-' + sourceKey);
|
|
const toggle = document.querySelector('.js-toggle-confirmacion-extra[data-source-key="' + sourceKey + '"]');
|
|
const hasValue = [productoExtra, cantidadExtra, precioExtra].some(input => (input?.value || '').trim() !== '');
|
|
if (hasValue) {
|
|
block.classList.remove('d-none');
|
|
if (toggle) toggle.classList.add('d-none');
|
|
}
|
|
});
|
|
});
|
|
|
|
function eliminarPedido(sourceKey, trigger) {
|
|
const confirmed = window.confirm('¿Seguro que deseas eliminar este pedido del panel? Se ocultará del Call Center y no borrará la fila original de Drive.');
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
const body = new FormData();
|
|
body.append('source_key', sourceKey);
|
|
body.append('eliminar_pedido', '1');
|
|
|
|
if (trigger) {
|
|
trigger.disabled = true;
|
|
}
|
|
|
|
fetch('update_callcenter_test_tracking.php', {
|
|
method: 'POST',
|
|
body: body
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) {
|
|
throw new Error(data.message || 'No se pudo eliminar el pedido del panel.');
|
|
}
|
|
alert(data.message || 'Pedido eliminado del panel correctamente.');
|
|
window.location.reload();
|
|
})
|
|
.catch(error => {
|
|
alert(error.message || 'Ocurrió un error al eliminar el pedido del panel.');
|
|
})
|
|
.finally(() => {
|
|
if (trigger) {
|
|
trigger.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
function guardarGestion(sourceKey, trigger, options = {}) {
|
|
const subirLogistica = options.subirLogistica === true || options.subirRuta === true;
|
|
const moverPromoFinal = options.moverPromoFinal === true;
|
|
const estado = document.getElementById('estado-' + sourceKey)?.value || 'POR LLAMAR';
|
|
const promoProofInput = document.getElementById('promo_final_evidencia-' + sourceKey);
|
|
const cancelProofInput = document.getElementById('cancelado_evidencia-' + sourceKey);
|
|
const promoProofGroup = document.querySelector('.js-promo-final-proof-group[data-source-key="' + sourceKey + '"]');
|
|
const cancelProofGroup = document.querySelector('.js-cancelado-proof-group[data-source-key="' + sourceKey + '"]');
|
|
const hasExistingPromoProof = promoProofGroup?.dataset.hasExisting === '1';
|
|
const hasExistingCancelProof = cancelProofGroup?.dataset.hasExisting === '1';
|
|
|
|
if (moverPromoFinal && !hasExistingPromoProof && (!promoProofInput?.files || promoProofInput.files.length === 0)) {
|
|
alert('Debes subir una imagen de sustento antes de mover el pedido a Promo Final.');
|
|
return;
|
|
}
|
|
|
|
if (estado === 'CANCELADO' && !hasExistingCancelProof && (!cancelProofInput?.files || cancelProofInput.files.length === 0)) {
|
|
alert('Debes subir una imagen de sustento para guardar el pedido en estado Cancelado.');
|
|
return;
|
|
}
|
|
|
|
const body = new FormData();
|
|
const fields = {
|
|
source_key: sourceKey,
|
|
estado: estado,
|
|
proxima_llamada_at: document.getElementById('proxima-' + sourceKey)?.value || '',
|
|
fecha_entrega_programada: document.getElementById('fecha-entrega-' + sourceKey)?.value || '',
|
|
nota_seguimiento: document.getElementById('nota-' + sourceKey)?.value || '',
|
|
direccion: document.getElementById('direccion-' + sourceKey)?.value || '',
|
|
referencia: document.getElementById('referencia-' + sourceKey)?.value || '',
|
|
agencia: document.getElementById('agencia-' + sourceKey)?.value || '',
|
|
sede_agencia: document.getElementById('sede_agencia-' + sourceKey)?.value || '',
|
|
sede: document.getElementById('sede-' + sourceKey)?.value || '',
|
|
ciudad: document.getElementById('ciudad-' + sourceKey)?.value || '',
|
|
distrito: document.getElementById('distrito-' + sourceKey)?.value || '',
|
|
coordenadas: document.getElementById('coordenadas-' + sourceKey)?.value || '',
|
|
dni: document.getElementById('dni-' + sourceKey)?.value || '',
|
|
numero_cuenta_sede_id: document.getElementById('numero_cuenta_sede_id-' + sourceKey)?.value || '',
|
|
numero_cuenta_dni: document.getElementById('numero_cuenta_dni-' + sourceKey)?.value || '',
|
|
monto_adelantado: document.getElementById('monto_adelantado-' + sourceKey)?.value || '',
|
|
observaciones: document.getElementById('observaciones-' + sourceKey)?.value || '',
|
|
producto: document.getElementById('producto-' + sourceKey)?.value || '',
|
|
cantidad: document.getElementById('cantidad-' + sourceKey)?.value || '',
|
|
precio: document.getElementById('precio-' + sourceKey)?.value || '',
|
|
confirmacion_producto: document.getElementById('confirmacion_producto-' + sourceKey)?.value || '',
|
|
confirmacion_cantidad: document.getElementById('confirmacion_cantidad-' + sourceKey)?.value || '',
|
|
confirmacion_precio: document.getElementById('confirmacion_precio-' + sourceKey)?.value || '',
|
|
confirmacion_producto_extra: document.getElementById('confirmacion_producto_extra-' + sourceKey)?.value || '',
|
|
confirmacion_cantidad_extra: document.getElementById('confirmacion_cantidad_extra-' + sourceKey)?.value || '',
|
|
confirmacion_precio_extra: document.getElementById('confirmacion_precio_extra-' + sourceKey)?.value || '',
|
|
subir_a_logistica: subirLogistica ? '1' : '0',
|
|
mover_a_promo_final: moverPromoFinal ? '1' : '0'
|
|
};
|
|
|
|
Object.entries(fields).forEach(([key, value]) => {
|
|
body.append(key, value);
|
|
});
|
|
|
|
if (moverPromoFinal && promoProofInput?.files?.[0]) {
|
|
body.append('promo_final_evidencia', promoProofInput.files[0]);
|
|
}
|
|
|
|
if (estado === 'CANCELADO' && cancelProofInput?.files?.[0]) {
|
|
body.append('cancelado_evidencia', cancelProofInput.files[0]);
|
|
}
|
|
|
|
if (trigger) {
|
|
trigger.disabled = true;
|
|
}
|
|
|
|
fetch('update_callcenter_test_tracking.php', {
|
|
method: 'POST',
|
|
body: body
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) {
|
|
throw new Error(data.message || 'No se pudo guardar la gestión');
|
|
}
|
|
if (subirLogistica || moverPromoFinal) {
|
|
alert(data.message || 'Gestión actualizada correctamente.');
|
|
}
|
|
window.location.reload();
|
|
})
|
|
.catch(error => {
|
|
alert(error.message || 'Ocurrió un error al guardar la gestión.');
|
|
})
|
|
.finally(() => {
|
|
if (trigger) {
|
|
trigger.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
function actualizarContadorLlamadas(sourceKey, total) {
|
|
document.querySelectorAll('.js-call-count-number[data-source-key="' + sourceKey + '"]').forEach(node => {
|
|
node.textContent = String(total);
|
|
});
|
|
}
|
|
|
|
function normalizarNumeroTelefono(value) {
|
|
return String(value || '').replace(/\D+/g, '');
|
|
}
|
|
|
|
function copyTextLegacy(text) {
|
|
const input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.value = text;
|
|
input.setAttribute('readonly', 'readonly');
|
|
input.style.position = 'fixed';
|
|
input.style.opacity = '0';
|
|
document.body.appendChild(input);
|
|
input.select();
|
|
input.setSelectionRange(0, input.value.length);
|
|
let copied = false;
|
|
|
|
try {
|
|
copied = document.execCommand('copy');
|
|
} catch (error) {
|
|
copied = false;
|
|
}
|
|
|
|
document.body.removeChild(input);
|
|
return copied;
|
|
}
|
|
|
|
function copyPhoneToClipboard(phone) {
|
|
if (!phone) {
|
|
return Promise.resolve(false);
|
|
}
|
|
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
return navigator.clipboard.writeText(phone)
|
|
.then(() => true)
|
|
.catch(() => copyTextLegacy(phone));
|
|
}
|
|
|
|
return Promise.resolve(copyTextLegacy(phone));
|
|
}
|
|
|
|
function openAirDroidWeb() {
|
|
return window.open('https://web.airdroid.com/', '_blank', 'noopener');
|
|
}
|
|
|
|
function showAirDroidHelper(details) {
|
|
const sourceKey = details.sourceKey || '';
|
|
const phone = details.phone || '-';
|
|
const orderLabel = details.orderLabel || 'Sin número';
|
|
const clientName = details.clientName || 'Cliente sin nombre';
|
|
const registered = !!details.registered;
|
|
const copied = !!details.copied;
|
|
const modalId = details.modalId || '';
|
|
|
|
if (modalId) {
|
|
const modalElement = document.getElementById(modalId);
|
|
if (modalElement && window.bootstrap && window.bootstrap.Modal) {
|
|
window.bootstrap.Modal.getOrCreateInstance(modalElement).show();
|
|
}
|
|
}
|
|
|
|
const orderNode = document.getElementById('airDroidOrderLabel-' + sourceKey);
|
|
const clientNode = document.getElementById('airDroidClientName-' + sourceKey);
|
|
const phoneNode = document.getElementById('airDroidPhoneNumber-' + sourceKey);
|
|
const copyButton = document.getElementById('airDroidCopyButton-' + sourceKey);
|
|
const openButton = document.getElementById('airDroidOpenButton-' + sourceKey);
|
|
|
|
if (orderNode) orderNode.textContent = orderLabel;
|
|
if (clientNode) clientNode.textContent = clientName;
|
|
if (phoneNode) phoneNode.textContent = phone;
|
|
|
|
if (copyButton) {
|
|
copyButton.dataset.phone = phone !== '-' ? phone : '';
|
|
}
|
|
|
|
if (openButton) {
|
|
openButton.onclick = function () {
|
|
openAirDroidWeb();
|
|
};
|
|
}
|
|
}
|
|
|
|
function registrarLlamada(event, trigger) {
|
|
if (event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
const sourceKey = trigger?.dataset?.sourceKey || '';
|
|
const modalId = trigger?.dataset?.modalId || '';
|
|
const phone = normalizarNumeroTelefono(trigger?.dataset?.phone || '');
|
|
const orderLabel = trigger?.dataset?.orderLabel || '';
|
|
const clientName = trigger?.dataset?.clientName || '';
|
|
|
|
if (!sourceKey) {
|
|
alert('No se encontró el pedido para registrar la llamada.');
|
|
return false;
|
|
}
|
|
|
|
if (modalId) {
|
|
const modalElement = document.getElementById(modalId);
|
|
if (modalElement && window.bootstrap && window.bootstrap.Modal) {
|
|
window.bootstrap.Modal.getOrCreateInstance(modalElement).show();
|
|
}
|
|
}
|
|
|
|
if (trigger) {
|
|
trigger.classList.add('disabled');
|
|
trigger.setAttribute('aria-disabled', 'true');
|
|
}
|
|
|
|
const copyPromise = copyPhoneToClipboard(phone).catch(() => false);
|
|
|
|
const body = new URLSearchParams({
|
|
pedido_id: sourceKey,
|
|
resultado: 'Llamada iniciada - AirDroid',
|
|
observacion: 'Clic en botón Llamar / AirDroid desde el panel'
|
|
});
|
|
|
|
const savePromise = fetch('save_llamada.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
body: body.toString(),
|
|
keepalive: true
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) {
|
|
throw new Error(data.error || 'No se pudo registrar la llamada');
|
|
}
|
|
|
|
if (typeof data.total_llamadas !== 'undefined') {
|
|
actualizarContadorLlamadas(sourceKey, Number(data.total_llamadas) || 0);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
Promise.allSettled([savePromise, copyPromise]).then(results => {
|
|
const registerResult = results[0];
|
|
const copyResult = results[1];
|
|
const registered = registerResult.status === 'fulfilled' && registerResult.value === true;
|
|
const copied = copyResult.status === 'fulfilled' && copyResult.value === true;
|
|
|
|
if (!registered) {
|
|
const error = registerResult.reason;
|
|
console.error('Error al registrar llamada:', error);
|
|
alert((error && error.message) || 'No se pudo registrar la llamada.');
|
|
}
|
|
|
|
showAirDroidHelper({
|
|
sourceKey,
|
|
modalId,
|
|
phone,
|
|
orderLabel,
|
|
clientName,
|
|
registered,
|
|
copied
|
|
});
|
|
}).finally(() => {
|
|
if (trigger) {
|
|
trigger.classList.remove('disabled');
|
|
trigger.removeAttribute('aria-disabled');
|
|
}
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
const airDroidCopyButton = document.getElementById('airDroidCopyButton');
|
|
if (airDroidCopyButton) {
|
|
airDroidCopyButton.addEventListener('click', function () {
|
|
const phone = this.dataset.phone || '';
|
|
copyPhoneToClipboard(phone).then(copied => {
|
|
if (!copied) {
|
|
alert('No se pudo copiar el número automáticamente.');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
window.setInterval(function () {
|
|
window.location.reload();
|
|
}, 600000);
|
|
</script>
|
|
|
|
<?php require_once 'layout_footer.php'; ?>
|