Autosave: 20260731-164557

This commit is contained in:
Flatlogic Bot 2026-07-31 16:44:21 +00:00
parent 3cff110ba0
commit d1def919d5
6 changed files with 164 additions and 56 deletions

View File

@ -179,18 +179,31 @@ function cc_test_find_assessor_key_by_user_id(?int $userId, array $assessors): ?
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, '#');
}
if (!empty($order['is_agregado'])) {
return 'AGREGADOS';
}
return 'Sin número';
}
function cc_test_promo_final_badge_info(array $order): ?array
{
if (empty($order['es_promo_final'])) {
return null;
}
return [
'label' => 'Promo Final',
'title' => 'Pedido movido a Promo Final',
'class' => 'bg-success-subtle text-success-emphasis border',
];
}
function cc_test_badge_class(string $estado): string
{
return match (cc_test_normalize_state($estado)) {
@ -422,7 +435,7 @@ $_SESSION[cc_test_callcenter_view_session_key()] = cc_test_normalize_context_key
$viewStatesNote = $isTuaniRecuperablesStore
? 'Estados disponibles: <strong>Carritos recuperables</strong>, <strong>Seguimiento</strong>, <strong>Observados</strong>, <strong>Confirmados</strong>, <strong>Recuperados</strong> y <strong>Todos</strong>. Esta bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en <strong>TUANI principal</strong>, se marca en gris como <strong>Pedido repetido en tienda</strong> solo en esta bandeja.'
: '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 3 para pedidos nuevos desde el 29/07/2026 y desde el Día 4 para pedidos anteriores; cuando haya sustento pendiente en ese nuevo flujo, la tarjeta de Asignados hoy sigue visible y el celular aparece con candado hasta completarlo. Además, esta bandeja principal incluye reparto intercalado diario: en modo automático reparte pedidos sin asignar entre asesoras activas; en modo manual el supervisor los mueve pedido por pedido. También puedes usar la vista <strong>Últimos 3 días hábiles</strong> para concentrar el seguimiento reciente. Cuando un pedido del nuevo flujo tiene sustento pendiente, su celular se muestra con candado en cualquier vista donde aparezca hasta completar ese paso; la llamada queda bloqueada hasta completarlo.';
: '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 3 para pedidos nuevos desde el 29/07/2026 y desde el Día 4 para pedidos anteriores; desde ese momento el número queda visible para llamar y gestionar, y el sustento solo se usa para mover el pedido a Promo Final. Además, esta bandeja principal incluye reparto intercalado diario: en modo automático reparte pedidos sin asignar entre asesoras activas; en modo manual el supervisor los mueve pedido por pedido. También puedes usar la vista <strong>Últimos 3 días hábiles</strong> para concentrar el seguimiento reciente.';
$errorMessage = null;
$noticeMessage = null;
@ -702,12 +715,8 @@ try {
$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['llamada_bloqueada_dia3'] = $followupDayInfo !== null
&& (int) ($followupDayInfo['day_number'] ?? 0) >= 3
&& !$order['promo_final_evidencia_cargada'];
$order['llamada_bloqueada_dia3_mensaje'] = $order['llamada_bloqueada_dia3']
? 'Celular oculto hasta completar el sustento de Día 3.'
: '';
$order['llamada_bloqueada_dia3'] = false;
$order['llamada_bloqueada_dia3_mensaje'] = '';
$order['pendiente_logistica_destino'] = cc_test_is_tuani_store_key($storeKey) ? cc_test_pending_logistica_destination($order) : null;
$order['pendiente_logistica'] = $order['pendiente_logistica_destino'] !== null;
@ -756,6 +765,8 @@ try {
}
unset($order);
$pendingPromoFinalCounts = cc_test_followup_pending_promo_final_counts($orders);
$orders = cc_test_mark_recoverables_duplicate_orders($pdo, $orders, $storeKey);
$performanceOrders = $orders;
@ -987,15 +998,19 @@ try {
$assessorInboxLockedOrders = [];
if (!$isAdmin && !$isTuaniRecuperablesStore) {
$assessorInboxLockedOrders = array_values(array_filter($orders, static function (array $order): bool {
return !empty($order['llamada_bloqueada_dia3']);
}));
$currentUserLockKey = $currentUserId > 0 ? 'user:' . $currentUserId : '';
if ($currentUserLockKey !== '') {
$assessorInboxLockedOrders = array_values(array_filter($orders, static function (array $order) use ($currentUserLockKey): bool {
return cc_test_followup_owner_lock_key($order) === $currentUserLockKey
&& !empty($order['promo_final_pendiente']);
}));
}
}
$assessorInboxLockedCount = count($assessorInboxLockedOrders);
$assessorInboxLocked = $assessorInboxLockedCount > 0;
$assessorInboxLockedView = $assessorInboxLocked && $view === 'nuevos_hoy';
$assessorInboxLockNotice = $assessorInboxLocked
? 'Tienes ' . $assessorInboxLockedCount . ' pedido' . ($assessorInboxLockedCount === 1 ? '' : 's') . ' con sustento pendiente para Promo Final. En esos casos, el celular aparece con candado y la llamada queda bloqueada hasta completar ese paso.'
? 'Tienes ' . $assessorInboxLockedCount . ' pedido' . ($assessorInboxLockedCount === 1 ? '' : 's') . ' pendiente' . ($assessorInboxLockedCount === 1 ? '' : 's') . ' de Promo Final. Mientras existan pendientes, los pedidos de Día 1 mantienen el número oculto; cuando los muevas todos a Promo Final, el celular volverá a mostrarse.'
: '';
$visibleOrdersTotalCount = count($visibleOrders);
@ -1360,7 +1375,7 @@ require_once 'layout_header.php';
<div class="small text-uppercase <?php echo htmlspecialchars($labelClass); ?> mb-2"><?php echo htmlspecialchars((string) ($viewCard['label'] ?? $viewKey)); ?></div>
<div class="display-6 fw-bold mb-0"><?php echo (int) ($stats[$viewCard['stat_key']] ?? 0); ?></div>
<?php if ($viewKey === 'nuevos_hoy' && $assessorInboxLocked): ?>
<div class="small fw-semibold text-warning mt-2"><i class="bi bi-lock-fill me-1"></i>Con candado en celulares</div>
<div class="small fw-semibold text-warning mt-2"><i class="bi bi-info-circle me-1"></i>Número oculto en Día 1 hasta completar Promo Final</div>
<?php endif; ?>
</div>
</article>
@ -1422,7 +1437,7 @@ require_once 'layout_header.php';
<?php endif; ?>
<span class="badge bg-light text-dark border"><?php echo (int) $visibleOrdersTotalCount; ?> pedidos únicos en esta bandeja</span>
<?php if ($assessorInboxLockedView): ?>
<span class="badge bg-warning-subtle text-warning-emphasis border">Candado en celulares por sustento de Día 3</span>
<span class="badge bg-warning-subtle text-warning-emphasis border">Pedidos con sustento pendiente para Promo Final</span>
<?php endif; ?>
<?php if ($view === 'todos'): ?>
<span class="badge bg-primary-subtle text-primary-emphasis border">Página <?php echo (int) $todosPage; ?> de <?php echo (int) $todosTotalPages; ?> · 200 por página</span>
@ -1434,7 +1449,7 @@ require_once 'layout_header.php';
<div class="p-3 pb-0">
<div class="alert alert-info border-info-subtle d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3 mb-0">
<div>
<div class="fw-semibold mb-1"><i class="bi bi-lock-fill me-1"></i>Celulares con candado por sustento de Día 3</div>
<div class="fw-semibold mb-1"><i class="bi bi-info-circle me-1"></i>Pedidos con sustento pendiente para Promo Final</div>
<div class="small mb-0"><?php echo htmlspecialchars($assessorInboxLockNotice); ?> Usa <strong>Últimos 3 días hábiles</strong> si necesitas completar ese sustento más rápido.</div>
</div>
<a href="<?php echo htmlspecialchars(cc_test_build_url('call_center_pro.php', array_merge($callCenterParams, ['view' => 'ultimos_3_dias']))); ?>" class="btn btn-outline-info btn-sm text-nowrap">Ir a Últimos 3 días</a>
@ -1476,6 +1491,7 @@ require_once 'layout_header.php';
$modalId = 'modalDriveTest' . $order['source_key'];
$badgeClass = cc_test_badge_class($order['estado']);
$followupDayInfo = $order['seguimiento_dia_info'] ?? null;
$promoFinalBadge = cc_test_promo_final_badge_info($order);
$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;
@ -1514,19 +1530,19 @@ require_once 'layout_header.php';
if ($isTuaniRecuperablesStore && !empty($order['pedido_repetido_en_tienda'])) {
$rowBackgroundStyle .= '--cc-row-bg:#CCCCCC;';
}
$phoneLocked = !empty($order['llamada_bloqueada_dia3']);
$phoneLocked = false;
$phoneLockMessage = (string) ($order['llamada_bloqueada_dia3_mensaje'] ?? '');
if ($phoneLocked && $phoneLockMessage === '') {
$phoneLockMessage = 'Celular oculto mientras completas los pendientes del Día 3.';
}
$phoneHiddenByDay1 = $followupDayInfo !== null
&& (int) ($followupDayInfo['day_number'] ?? 0) === 1;
$phoneHiddenByDay1 = cc_test_followup_day1_phone_hidden($order, $pendingPromoFinalCounts);
$phoneRowHiddenLabel = 'Número oculto';
$phoneRowHiddenTitle = 'Número oculto';
$phoneRowHiddenTitle = 'Número oculto hasta completar Promo Final';
ob_start();
?>
<tr class="cc-callcenter-row" data-source-key="<?php echo htmlspecialchars($order['source_key']); ?>" style="<?php echo htmlspecialchars($rowBackgroundStyle); ?>">
<td>
<div class="badge bg-light text-dark border mb-2 text-nowrap" title="ID del pedido"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
<?php if ($followupDayInfo !== null): ?>
<div class="cc-followup-day-badge <?php echo htmlspecialchars($followupDayInfo['badge_class']); ?>" title="<?php echo htmlspecialchars($followupDayInfo['description']); ?>" aria-label="<?php echo htmlspecialchars($followupDayInfo['display_label']); ?>">
<span class="cc-followup-day-badge-label">DÍA</span>
@ -1565,6 +1581,11 @@ require_once 'layout_header.php';
<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>
<?php if ($promoFinalBadge !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($promoFinalBadge['class']); ?>" title="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>" aria-label="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>">
<i class="bi bi-check2-circle me-1"></i><?php echo htmlspecialchars($promoFinalBadge['label']); ?>
</span>
<?php endif; ?>
<?php if (!empty($order['pedido_repetido_en_tienda'])): ?>
<span class="badge rounded-pill bg-secondary-subtle text-secondary-emphasis border"><?php echo htmlspecialchars((string) ($order['pedido_repetido_en_tienda_label'] ?? 'Pedido repetido en tienda')); ?></span>
<?php endif; ?>
@ -1664,6 +1685,7 @@ require_once 'layout_header.php';
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-locked="<?php echo $phoneLocked ? '1' : '0'; ?>"
data-phone-hidden-day1="<?php echo $phoneHiddenByDay1 ? '1' : '0'; ?>"
data-phone="<?php echo $phoneLocked ? '' : htmlspecialchars((string) ($order['celular'] ?? '')); ?>"
@ -1696,6 +1718,11 @@ require_once 'layout_header.php';
<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 ($promoFinalBadge !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($promoFinalBadge['class']); ?>" title="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>" aria-label="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>">
<i class="bi bi-check2-circle me-1"></i><?php echo htmlspecialchars($promoFinalBadge['label']); ?>
</span>
<?php endif; ?>
<?php if ($followupDayInfo !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($followupDayInfo['badge_class']); ?>"><?php echo htmlspecialchars($followupDayInfo['display_label']); ?></span>
<?php endif; ?>
@ -2789,7 +2816,7 @@ function showAirDroidHelper(details) {
if (clientNode) clientNode.textContent = clientName;
if (phoneNode) {
if (phoneHiddenByDay1) {
phoneNode.innerHTML = '<span class="badge bg-warning-subtle text-warning-emphasis border"><i class="bi bi-lock-fill me-1"></i>Número oculto</span>';
phoneNode.innerHTML = '<span class="badge bg-warning-subtle text-warning-emphasis border" title="Número oculto hasta completar Promo Final" aria-label="Número oculto hasta completar Promo Final"><i class="bi bi-lock-fill me-1"></i>Número oculto</span>';
} else {
phoneNode.textContent = phone !== '-' ? phone : 'Sin celular';
}
@ -2800,7 +2827,7 @@ function showAirDroidHelper(details) {
copyButton.dataset.phone = '';
copyButton.disabled = true;
copyButton.textContent = 'Número oculto';
copyButton.setAttribute('title', 'Número oculto en Día 1');
copyButton.setAttribute('title', 'Número oculto hasta completar Promo Final');
} else {
copyButton.dataset.phone = phone !== '-' ? phone : '';
copyButton.disabled = false;
@ -2824,12 +2851,8 @@ function registrarLlamada(event, trigger) {
const phone = normalizarNumeroTelefono(trigger?.dataset?.phone || '');
const orderLabel = trigger?.dataset?.orderLabel || '';
const clientName = trigger?.dataset?.clientName || '';
const phoneLocked = trigger?.dataset?.phoneLocked === '1';
const phoneLocked = false;
const phoneHiddenByDay1 = trigger?.dataset?.phoneHiddenDay1 === '1';
if (phoneLocked) {
alert('Este pedido tiene el celular bloqueado hasta completar el sustento de Día 3.');
return false;
}
if (!sourceKey) {
alert('No se encontró el pedido para registrar la llamada.');

View File

@ -101,18 +101,31 @@ function cc_test_build_url(string $path, array $params = []): string
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, '#');
}
if (!empty($order['is_agregado'])) {
return 'AGREGADOS';
}
return 'Sin número';
}
function cc_test_promo_final_badge_info(array $order): ?array
{
if (empty($order['es_promo_final'])) {
return null;
}
return [
'label' => 'Promo Final',
'title' => 'Pedido movido a Promo Final',
'class' => 'bg-success-subtle text-success-emphasis border',
];
}
function cc_test_badge_class(string $estado): string
{
return match (cc_test_normalize_state($estado)) {
@ -330,7 +343,7 @@ $_SESSION[cc_test_callcenter_view_session_key()] = cc_test_normalize_context_key
$viewStatesNote = $isTuaniRecuperablesStore
? 'Estados disponibles: <strong>Carritos recuperables</strong>, <strong>Seguimiento</strong>, <strong>Observados</strong>, <strong>Confirmados</strong>, <strong>Recuperados</strong> y <strong>Todos</strong>. Esta bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en <strong>TUANI principal</strong>, se marca en gris como <strong>Pedido repetido en tienda</strong> solo en esta bandeja.'
: '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 3 para pedidos nuevos desde el 29/07/2026 y desde el Día 4 para pedidos anteriores; exige imagen de sustento para mover el pedido. En las vistas <strong>Todos</strong> y <strong>Últimos 3 días hábiles</strong>, los pedidos del nuevo flujo con sustento pendiente se muestran con candado en el número hasta completar ese paso; la llamada sigue disponible desde el panel.';
: '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 3 para pedidos nuevos desde el 29/07/2026 y desde el Día 4 para pedidos anteriores; desde ese momento el número se mantiene visible para llamar y gestionar, y el sustento solo se usa para mover el pedido a Promo Final. En las vistas <strong>Todos</strong> y <strong>Últimos 3 días hábiles</strong>, la llamada y la gestión siguen disponibles desde el panel.';
$errorMessage = null;
$noticeMessage = null;
@ -897,12 +910,8 @@ try {
$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['llamada_bloqueada_dia3'] = $followupDayInfo !== null
&& (int) ($followupDayInfo['day_number'] ?? 0) >= 3
&& !$order['promo_final_evidencia_cargada'];
$order['llamada_bloqueada_dia3_mensaje'] = $order['llamada_bloqueada_dia3']
? 'Celular oculto hasta completar el sustento de Día 3.'
: '';
$order['llamada_bloqueada_dia3'] = false;
$order['llamada_bloqueada_dia3_mensaje'] = '';
$order['pendiente_logistica_destino'] = cc_test_is_tuani_store_key($storeKey) ? cc_test_pending_logistica_destination($order) : null;
$order['pendiente_logistica'] = $order['pendiente_logistica_destino'] !== null;
@ -957,6 +966,8 @@ try {
}
unset($order);
$pendingPromoFinalCounts = cc_test_followup_pending_promo_final_counts($orders);
$orders = cc_test_mark_recoverables_duplicate_orders($pdo, $orders, $storeKey);
$performanceOrders = $selectedAssessorFilter !== ''
@ -1616,7 +1627,7 @@ require_once 'layout_header.php';
</h2>
<div class="text-muted small">
Para: <strong><?php echo htmlspecialchars($storeLabel); ?></strong>.
Los pedidos cargados se muestran como <strong>AGREGADOS</strong> y no afectan la secuencia de Drive.
Los pedidos cargados conservan su número original y no afectan la secuencia de Drive.
</div>
<div class="mt-2">
<a href="download_agregados_pedidos_template.php" class="btn btn-outline-primary btn-sm">Descargar plantilla Excel</a>
@ -1931,8 +1942,8 @@ require_once 'layout_header.php';
$modalId = 'modalDriveTest' . $order['source_key'];
$badgeClass = cc_test_badge_class($order['estado']);
$followupDayInfo = $order['seguimiento_dia_info'] ?? null;
$phoneHiddenByDay1 = $followupDayInfo !== null
&& (int) ($followupDayInfo['day_number'] ?? 0) === 1;
$promoFinalBadge = cc_test_promo_final_badge_info($order);
$phoneHiddenByDay1 = cc_test_followup_day1_phone_hidden($order, $pendingPromoFinalCounts);
$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;
@ -1971,7 +1982,9 @@ require_once 'layout_header.php';
?>
<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')) . (!empty($order['pedido_repetido_en_tienda']) ? '--cc-row-bg:#CCCCCC;' : '')); ?>">
<td class="text-center">
<div class="badge bg-light text-dark border mb-2 text-nowrap" title="ID del pedido"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
<div class="d-flex justify-content-center">
<button
type="button"
class="btn btn-sm btn-outline-primary cc-quick-select-btn js-quick-select-btn"
@ -2061,13 +2074,13 @@ require_once 'layout_header.php';
</form>
<?php endif; ?>
<?php
$phoneLocked = !empty($order['llamada_bloqueada_dia3']);
$phoneLocked = false;
$phoneLockMessage = (string) ($order['llamada_bloqueada_dia3_mensaje'] ?? '');
if ($phoneLocked && $phoneLockMessage === '') {
$phoneLockMessage = 'Celular oculto mientras completas los pendientes del Día 3.';
}
$phoneRowHiddenLabel = 'Número oculto';
$phoneRowHiddenTitle = 'Número oculto';
$phoneRowHiddenTitle = 'Número oculto hasta completar Promo Final';
?>
<div class="d-flex flex-column gap-1 align-items-stretch cc-callcenter-actions<?php echo in_array($_SESSION['user_role'] ?? '', ['Administrador', 'admin'], true) ? ' mt-1' : ''; ?>"> <?php if (!empty($order['telefono_url'])): ?>
<button
@ -2103,7 +2116,14 @@ require_once 'layout_header.php';
<span class="cc-followup-day-badge-number"><?php echo htmlspecialchars($followupDayInfo['compact_label']); ?></span>
</div>
<?php endif; ?>
<div class="fw-bold fs-6"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
<div class="d-flex flex-wrap align-items-center gap-2 mb-1">
<div class="fw-bold fs-6 mb-0"><?php echo htmlspecialchars(cc_test_order_label($order)); ?></div>
<?php if ($promoFinalBadge !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($promoFinalBadge['class']); ?>" title="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>" aria-label="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>">
<i class="bi bi-check2-circle me-1"></i><?php echo htmlspecialchars($promoFinalBadge['label']); ?>
</span>
<?php endif; ?>
</div>
<div class="small text-muted">ID Drive: <?php echo htmlspecialchars(cc_test_display_value($order['import_id'] ?? null, 'Sin ID')); ?></div>
</td>
<td>
@ -2187,6 +2207,11 @@ require_once 'layout_header.php';
<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 ($promoFinalBadge !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($promoFinalBadge['class']); ?>" title="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>" aria-label="<?php echo htmlspecialchars($promoFinalBadge['title']); ?>">
<i class="bi bi-check2-circle me-1"></i><?php echo htmlspecialchars($promoFinalBadge['label']); ?>
</span>
<?php endif; ?>
<?php if ($followupDayInfo !== null): ?>
<span class="badge rounded-pill <?php echo htmlspecialchars($followupDayInfo['badge_class']); ?>"><?php echo htmlspecialchars($followupDayInfo['display_label']); ?></span>
<?php endif; ?>
@ -3326,7 +3351,7 @@ function showAirDroidHelper(details) {
if (clientNode) clientNode.textContent = clientName;
if (phoneNode) {
if (phoneHiddenByDay1) {
phoneNode.innerHTML = '<span class="badge bg-warning-subtle text-warning-emphasis border"><i class="bi bi-lock-fill me-1"></i>Número oculto</span>';
phoneNode.innerHTML = '<span class="badge bg-warning-subtle text-warning-emphasis border" title="Número oculto hasta completar Promo Final" aria-label="Número oculto hasta completar Promo Final"><i class="bi bi-lock-fill me-1"></i>Número oculto</span>';
} else {
phoneNode.textContent = phone !== '-' ? phone : 'Sin celular';
}
@ -3337,7 +3362,7 @@ function showAirDroidHelper(details) {
copyButton.dataset.phone = '';
copyButton.disabled = true;
copyButton.textContent = 'Número oculto';
copyButton.setAttribute('title', 'Número oculto en Día 1');
copyButton.setAttribute('title', 'Número oculto hasta completar Promo Final');
} else {
copyButton.dataset.phone = phone !== '-' ? phone : '';
copyButton.disabled = false;
@ -3361,12 +3386,8 @@ function registrarLlamada(event, trigger) {
const phone = normalizarNumeroTelefono(trigger?.dataset?.phone || '');
const orderLabel = trigger?.dataset?.orderLabel || '';
const clientName = trigger?.dataset?.clientName || '';
const phoneLocked = trigger?.dataset?.phoneLocked === '1';
const phoneLocked = false;
const phoneHiddenByDay1 = trigger?.dataset?.phoneHiddenDay1 === '1';
if (phoneLocked) {
alert('Este pedido tiene el celular bloqueado hasta completar el sustento de Día 3.');
return false;
}
if (!sourceKey) {
alert('No se encontró el pedido para registrar la llamada.');

View File

@ -1406,6 +1406,56 @@ function cc_test_followup_day_info(array $order): ?array
];
}
function cc_test_followup_owner_lock_key(array $order): string
{
$userId = (int) ($order['user_id'] ?? 0);
if ($userId > 0) {
return 'user:' . $userId;
}
$assessorKey = trim((string) ($order['assessor_key'] ?? ''));
if ($assessorKey !== '' && mb_strtolower($assessorKey) !== 'sin_asignar') {
return 'assessor:' . mb_strtolower($assessorKey);
}
return '';
}
function cc_test_followup_pending_promo_final_counts(array $orders): array
{
$counts = [];
foreach ($orders as $order) {
if (empty($order['promo_final_pendiente'])) {
continue;
}
$ownerKey = cc_test_followup_owner_lock_key($order);
if ($ownerKey === '') {
continue;
}
$counts[$ownerKey] = ($counts[$ownerKey] ?? 0) + 1;
}
return $counts;
}
function cc_test_followup_day1_phone_hidden(array $order, array $pendingPromoFinalCounts = []): bool
{
$followupDayInfo = $order['seguimiento_dia_info'] ?? null;
if (!is_array($followupDayInfo) || (int) ($followupDayInfo['day_number'] ?? 0) !== 1) {
return false;
}
$ownerKey = cc_test_followup_owner_lock_key($order);
if ($ownerKey === '') {
return false;
}
return !empty($pendingPromoFinalCounts[$ownerKey]);
}
function cc_test_dashboard_date_key(?string $value): ?string
{
$date = cc_test_followup_parse_datetime($value);

View File

@ -10,6 +10,9 @@ if (in_array($userRole, ['Administrador', 'admin'], true)) {
} elseif (strcasecmp(trim($userRole), 'Marketing') === 0) {
$homeUrl = 'marketing_produccion.php';
$homeLabel = 'Ir a Producción de Video';
} elseif (strcasecmp(trim($userRole), 'Asesor') === 0) {
$homeUrl = 'kanban.php';
$homeLabel = 'Ir al panel';
}
$callCenterParams = [];
foreach ([

View File

@ -375,8 +375,8 @@ $navItems = [
]
],
'modulo_pruebas_group' => [
'icon' => 'fa-flask',
'text' => 'Módulo de Pruebas',
'icon' => 'fa-phone',
'text' => 'Gestión de pedidos',
'roles' => ['Administrador', 'admin', 'Asesor'],
'submenu' => [
'call_center' => [
@ -453,7 +453,14 @@ $navItems = [
</button>
<div class="sidebar">
<?php
$homeUrl = in_array($userRole, ['Administrador', 'admin'], true) ? 'dashboard_principal.php' : ($isMarketingUser ? 'marketing_produccion.php' : 'pedidos.php');
$homeUrl = 'pedidos.php';
if (in_array($userRole, ['Administrador', 'admin'], true)) {
$homeUrl = 'dashboard_principal.php';
} elseif ($isMarketingUser) {
$homeUrl = 'marketing_produccion.php';
} elseif (strcasecmp(trim((string) $userRole), 'Asesor') === 0) {
$homeUrl = 'kanban.php';
}
?>
<a href="<?php echo $homeUrl; ?>" class="navbar-brand"><h3>FLOOWER ERP</h3></a>
<div class="menu-wrapper">

View File

@ -7,6 +7,8 @@ if (isset($_SESSION['user_id'])) {
header('Location: dashboard_principal.php');
} elseif (strcasecmp(trim($currentRole), 'Marketing') === 0) {
header('Location: marketing_produccion.php');
} elseif (strcasecmp(trim($currentRole), 'Asesor') === 0) {
header('Location: kanban.php');
} else {
header('Location: pedidos.php');
}
@ -67,6 +69,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
header('Location: dashboard_principal.php');
} elseif (strcasecmp(trim($userRole), 'Marketing') === 0) {
header('Location: marketing_produccion.php');
} elseif (strcasecmp(trim($userRole), 'Asesor') === 0) {
header('Location: kanban.php');
} else {
header('Location: pedidos.php');
}