Autosave: 20260804-053238

This commit is contained in:
Flatlogic Bot 2026-08-04 05:30:57 +00:00
parent 12a6d00ac6
commit 9a2a8b59ef
4 changed files with 55 additions and 42 deletions

View File

@ -457,7 +457,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; 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.';
: '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 todos los pedidos; 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;
@ -800,20 +800,20 @@ try {
$performanceDashboard = cc_test_build_performance_dashboard_period($performanceOrders, $assessors, $kpiPeriodStart, $kpiPeriodEnd);
$performanceSubtitle = $isTuaniRecuperablesStore
? 'Los indicadores de esta bandeja se calculan sobre todos los pedidos visibles para cualquier asesora en el periodo seleccionado.'
? 'Los indicadores de esta bandeja se calculan sobre todos los pedidos visibles para cualquier asesora en el periodo seleccionado; los repetidos solo suman cantidad y no bajan el porcentaje.'
: ($isAdmin
? 'Confirmación = pedidos asignados en el periodo confirmados en el mismo periodo. Recuperación = pedidos asignados antes del periodo confirmados dentro del periodo. Rendimiento = confirmados totales (nuevos + recuperados) sobre asignados del periodo.'
: 'Tus KPIs del periodo seleccionado se calculan sobre tus pedidos asignados en ese rango. Confirmación = asignados del periodo confirmados en el mismo periodo. Recuperación = asignados antes del periodo confirmados dentro del periodo. Rendimiento = confirmados totales (nuevos + recuperados) sobre asignados del periodo.');
? 'Confirmación = pedidos asignados en el periodo confirmados en el mismo periodo, sin contar repetidos. Recuperación = pedidos asignados antes del periodo confirmados dentro del periodo. Rendimiento = confirmados totales (nuevos + recuperados) sobre asignados efectivos sin repetidos.'
: 'Tus KPIs del periodo seleccionado se calculan sobre tus pedidos asignados en ese rango. Confirmación = asignados del periodo confirmados en el mismo periodo, sin contar repetidos. Recuperación = asignados antes del periodo confirmados dentro del periodo. Rendimiento = confirmados totales (nuevos + recuperados) sobre asignados efectivos sin repetidos.');
if ($isTuaniRecuperablesStore) {
$performanceTitle = $kpiPeriodKey === 'today'
? 'KPI compartido de recuperación'
: 'KPI compartido de recuperación · ' . $kpiPeriodLabel;
$performanceChart1Title = 'Distribución de estados de la bandeja';
$performanceChart1Note = 'La dona separa los pedidos del periodo seleccionado por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos y cancelados.';
$performanceChart1Note = 'La dona separa los pedidos del periodo seleccionado por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos (solo cantidad) y cancelados.';
$performanceChart2Title = $kpiPeriodKey === 'today' ? 'Evolución de hoy' : 'Evolución de ' . $kpiPeriodTitleLabel;
$performanceChart2Note = 'La línea muestra cómo se mueve la bandeja compartida en el periodo seleccionado.';
$performanceFootnote = 'Los indicadores se calculan sobre todos los pedidos visibles de esta bandeja compartida.';
$performanceFootnote = 'Los indicadores se calculan sobre todos los pedidos visibles de esta bandeja compartida; los repetidos solo suman cantidad y no bajan el porcentaje.';
} else {
if ($isAdmin) {
$performanceTitle = $selectedAssessorFilterLabel !== ''
@ -823,7 +823,7 @@ try {
$performanceTitle = $kpiPeriodKey === 'today' ? 'Mi KPI diario' : 'Mi KPI de ' . $kpiPeriodTitleLabel;
}
$performanceChart1Title = $isAdmin ? 'Distribución de estados' : 'Mi distribución de estados';
$performanceChart1Note = 'La dona separa los pedidos del periodo seleccionado por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos y cancelados.';
$performanceChart1Note = 'La dona separa los pedidos del periodo seleccionado por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos (solo cantidad) y cancelados.';
$performanceChart2Title = $kpiPeriodKey === 'today'
? ($isAdmin ? 'Evolución de hoy' : 'Tu evolución de hoy')
: ($isAdmin ? 'Evolución de ' . $kpiPeriodTitleLabel : 'Tu evolución de ' . $kpiPeriodTitleLabel);
@ -2004,7 +2004,7 @@ require_once 'layout_header.php';
<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 <?php echo (int) ($followupDayInfo['promo_final_threshold_day'] ?? 4); ?>. La supervisora podrá revisarla.</div>
<div class="form-text">Obligatoria al mover el pedido a <strong>Promo Final</strong> desde el Día <?php echo (int) ($followupDayInfo['promo_final_threshold_day'] ?? 3); ?>. 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; ?>.

View File

@ -344,7 +344,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; 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.';
: '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 todos los pedidos; 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;
@ -980,9 +980,9 @@ try {
$performanceDashboard = cc_test_build_performance_dashboard($performanceOrders, $assessors, 7);
$performanceDashboardHtml = cc_test_render_performance_dashboard($performanceDashboard, [
'title' => 'KPI diario por asesora',
'subtitle' => 'Confirmación = pedidos asignados hoy confirmados hoy. Recuperación = pedidos asignados antes de hoy confirmados hoy. Rendimiento del día = confirmados totales (nuevos + recuperados) sobre asignados hoy.',
'subtitle' => 'Confirmación = pedidos asignados hoy confirmados hoy, sin contar repetidos. Recuperación = pedidos asignados antes de hoy confirmados hoy. Rendimiento del día = confirmados totales (nuevos + recuperados) sobre asignados efectivos sin repetidos.',
'chart1_title' => 'Distribución de estados',
'chart1_note' => 'La dona separa los pedidos de hoy por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos y cancelados.',
'chart1_note' => 'La dona separa los pedidos de hoy por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos (solo cantidad) y cancelados.',
'chart2_title' => 'Evolución de los últimos 7 días',
'chart2_note' => 'La línea de confirmados separa pedidos asignados hoy y pedidos asignados antes de hoy.',
'footnote' => 'Seguimiento abierto = pedidos asignados hoy en POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO y SE ENVIO NUMERO DE CUENTA que todavía no pasan a Promo Final.',
@ -2467,7 +2467,7 @@ require_once 'layout_header.php';
<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 <?php echo (int) ($followupDayInfo['promo_final_threshold_day'] ?? 4); ?>. La supervisora podrá revisarla.</div>
<div class="form-text">Obligatoria al mover el pedido a <strong>Promo Final</strong> desde el Día <?php echo (int) ($followupDayInfo['promo_final_threshold_day'] ?? 3); ?>. 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; ?>.

View File

@ -83,6 +83,7 @@ function cc_test_assessor_default_color_hex(string $assessorKey): string
'CARMEN' => '#FF00FF',
'MIRELLA' => '#EFBF04',
'LUCIBOT' => '#FD7E14',
'MARIA', 'MARÍA' => '#800080',
default => $palette[$paletteIndex],
};
}
@ -1353,13 +1354,7 @@ function cc_test_followup_is_from_promo_final_cutoff(array $order): bool
function cc_test_followup_promo_final_threshold_day(array $order): int
{
$startedAt = cc_test_followup_started_at($order);
if (!$startedAt instanceof DateTimeImmutable) {
return 4;
}
$cutoff = cc_test_followup_promo_final_cutoff();
return $startedAt->format('Y-m-d') >= $cutoff->format('Y-m-d') ? 3 : 4;
return 3;
}
function cc_test_followup_day_info(array $order): ?array
@ -1404,13 +1399,13 @@ function cc_test_followup_day_info(array $order): ?array
} elseif ($dayNumber === 2) {
$badgeClass = 'bg-info-subtle text-info-emphasis border';
$textClass = 'text-info-emphasis';
$description = 'Aún está dentro de los 3 días de seguimiento.';
$description = 'Aún está dentro de los primeros ' . $promoFinalThresholdDay . ' días de seguimiento.';
}
return [
'day_number' => $dayNumber,
'display_label' => $dayNumber >= 4 ? 'Día 4+' : 'Día ' . $dayNumber,
'compact_label' => $dayNumber >= 4 ? '4+' : (string) $dayNumber,
'display_label' => $dayNumber >= $promoFinalThresholdDay ? 'Día ' . $promoFinalThresholdDay . '+' : 'Día ' . $dayNumber,
'compact_label' => $dayNumber >= $promoFinalThresholdDay ? $promoFinalThresholdDay . '+' : (string) $dayNumber,
'badge_class' => $badgeClass,
'text_class' => $textClass,
'description' => $description,
@ -1679,6 +1674,7 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
$summary = [
'scope_total' => 0,
'assigned_today' => 0,
'assigned_effective_today' => 0,
'confirmed_today_new' => 0,
'confirmed_today_recovered' => 0,
'confirmed_today_total' => 0,
@ -1795,14 +1791,16 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
}
$summary['confirmed_today_total'] = $summary['confirmed_today_new'] + $summary['confirmed_today_recovered'];
$summary['confirm_rate_today'] = $summary['assigned_today'] > 0
? round(($summary['confirmed_today_new'] / $summary['assigned_today']) * 100, 1)
$summary['assigned_effective_today'] = max(0, (int) ($summary['assigned_today'] ?? 0) - (int) ($summary['repeated_today'] ?? 0));
$effectiveAssignedToday = (int) ($summary['assigned_effective_today'] ?? 0);
$summary['confirm_rate_today'] = $effectiveAssignedToday > 0
? round(($summary['confirmed_today_new'] / $effectiveAssignedToday) * 100, 1)
: 0.0;
$summary['recovery_rate_today'] = $summary['confirmed_today_total'] > 0
? round(($summary['confirmed_today_recovered'] / $summary['confirmed_today_total']) * 100, 1)
: 0.0;
$summary['performance_today_rate'] = $summary['assigned_today'] > 0
? round(($summary['confirmed_today_total'] / $summary['assigned_today']) * 100, 1)
$summary['performance_today_rate'] = $effectiveAssignedToday > 0
? round(($summary['confirmed_today_total'] / $effectiveAssignedToday) * 100, 1)
: 0.0;
$advisorLabels = [];
@ -2040,6 +2038,7 @@ function cc_test_build_performance_dashboard_period(array $orders, array $assess
$summary = [
'scope_total' => 0,
'assigned_today' => 0,
'assigned_effective_today' => 0,
'confirmed_today_new' => 0,
'confirmed_today_recovered' => 0,
'confirmed_today_total' => 0,
@ -2156,14 +2155,16 @@ function cc_test_build_performance_dashboard_period(array $orders, array $assess
}
$summary['confirmed_today_total'] = $summary['confirmed_today_new'] + $summary['confirmed_today_recovered'];
$summary['confirm_rate_today'] = $summary['assigned_today'] > 0
? round(($summary['confirmed_today_new'] / $summary['assigned_today']) * 100, 1)
$summary['assigned_effective_today'] = max(0, (int) ($summary['assigned_today'] ?? 0) - (int) ($summary['repeated_today'] ?? 0));
$effectiveAssignedToday = (int) ($summary['assigned_effective_today'] ?? 0);
$summary['confirm_rate_today'] = $effectiveAssignedToday > 0
? round(($summary['confirmed_today_new'] / $effectiveAssignedToday) * 100, 1)
: 0.0;
$summary['recovery_rate_today'] = $summary['confirmed_today_total'] > 0
? round(($summary['confirmed_today_recovered'] / $summary['confirmed_today_total']) * 100, 1)
: 0.0;
$summary['performance_today_rate'] = $summary['assigned_today'] > 0
? round(($summary['confirmed_today_total'] / $summary['assigned_today']) * 100, 1)
$summary['performance_today_rate'] = $effectiveAssignedToday > 0
? round(($summary['confirmed_today_total'] / $effectiveAssignedToday) * 100, 1)
: 0.0;
$advisorLabels = [];
@ -2363,9 +2364,9 @@ function cc_test_build_performance_dashboard_period(array $orders, array $assess
function cc_test_render_performance_dashboard(array $dashboard, array $options = []): string
{
$title = trim((string) ($options['title'] ?? 'KPI diario por asesora'));
$subtitle = trim((string) ($options['subtitle'] ?? 'Confirmación = pedidos asignados hoy confirmados hoy. Recuperación = pedidos asignados antes de hoy confirmados hoy. Rendimiento del día = confirmados totales (nuevos + recuperados) sobre asignados hoy.'));
$subtitle = trim((string) ($options['subtitle'] ?? 'Confirmación = pedidos asignados hoy confirmados hoy, sin contar repetidos. Recuperación = pedidos asignados antes de hoy confirmados hoy. Rendimiento del día = confirmados totales (nuevos + recuperados) sobre asignados efectivos sin repetidos.'));
$chart1Title = trim((string) ($options['chart1_title'] ?? 'Distribución de estados de hoy'));
$chart1Note = trim((string) ($options['chart1_note'] ?? 'La dona separa los pedidos de hoy por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos y cancelados.'));
$chart1Note = trim((string) ($options['chart1_note'] ?? 'La dona separa los pedidos de hoy por estado: confirmados nuevos, recuperados, POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO, SE ENVIO NUMERO DE CUENTA, repetidos (solo cantidad) y cancelados.'));
$chart2Title = trim((string) ($options['chart2_title'] ?? 'Evolución de los últimos 7 días'));
$chart2Note = trim((string) ($options['chart2_note'] ?? 'La línea de confirmados separa pedidos asignados hoy y pedidos asignados antes de hoy.'));
$footnote = trim((string) ($options['footnote'] ?? 'Seguimiento abierto = pedidos asignados hoy en POR LLAMAR, DEVOLVER LLAMADA, OBSERVADO y SE ENVIO NUMERO DE CUENTA que todavía no pasan a Promo Final.'));
@ -2388,13 +2389,22 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
? array_values($statusChartDataset['backgroundColor'])
: [];
$statusTotal = array_sum($statusChartValues);
$statusRepeatedTotal = 0;
foreach ($statusChartLabels as $index => $label) {
if (preg_match('/repetid/i', (string) $label) === 1) {
$statusRepeatedTotal += (int) ($statusChartValues[$index] ?? 0);
}
}
$statusPercentageTotal = max(0, $statusTotal - $statusRepeatedTotal);
$confirmedTodayNew = (int) ($summary['confirmed_today_new'] ?? 0);
$confirmedTodayRecovered = (int) ($summary['confirmed_today_recovered'] ?? 0);
$confirmedTodayTotal = (int) ($summary['confirmed_today_total'] ?? 0);
$effectiveAssignedToday = (int) ($summary['assigned_effective_today'] ?? max(0, (int) ($summary['assigned_today'] ?? 0) - (int) ($summary['repeated_today'] ?? 0)));
$performanceTodayRate = (float) ($summary['performance_today_rate'] ?? 0);
$performanceTodayMetaTitle = sprintf(
'%d confirmados = %d nuevos + %d recuperado%s',
'%d confirmados sobre %d asignados efectivos = %d nuevos + %d recuperado%s',
$confirmedTodayTotal,
$effectiveAssignedToday,
$confirmedTodayNew,
$confirmedTodayRecovered,
$confirmedTodayRecovered === 1 ? '' : 's'
@ -2404,10 +2414,13 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
$statusLegendItems = [];
if ($statusTotal > 0) {
foreach ($statusChartValues as $index => $value) {
$label = (string) ($statusChartLabels[$index] ?? ('Estado ' . ($index + 1)));
$isQuantityOnly = preg_match('/repetid/i', $label) === 1;
$statusLegendItems[] = [
'label' => (string) ($statusChartLabels[$index] ?? ('Estado ' . ($index + 1))),
'label' => $label,
'value' => (int) $value,
'percentage' => round(((float) $value / $statusTotal) * 100, 1),
'percentage' => $isQuantityOnly ? null : ($statusPercentageTotal > 0 ? round(((float) $value / $statusPercentageTotal) * 100, 1) : 0.0),
'is_quantity_only' => $isQuantityOnly,
'color' => (string) ($statusChartColors[$index] ?? 'rgba(108, 117, 125, 0.65)'),
];
}
@ -2509,7 +2522,7 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
<div class="cc-kpi-status-label"><?php echo htmlspecialchars((string) $item['label']); ?></div>
<div class="cc-kpi-status-count"><?php echo (int) $item['value']; ?> pedidos</div>
</div>
<div class="cc-kpi-status-percent"><?php echo htmlspecialchars(number_format((float) $item['percentage'], 1)); ?>%</div>
<div class="cc-kpi-status-percent"><?php echo !empty($item['is_quantity_only']) ? '—' : (htmlspecialchars(number_format((float) $item['percentage'], 1)) . '%'); ?></div>
</div>
<?php endforeach; ?>
</div>
@ -2567,6 +2580,7 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
return sum + value;
}, 0);
const statusHasData = statusTotal > 0;
const statusPercentageBase = <?php echo (int) $statusPercentageTotal; ?>;
const statusBackgroundColors = Array.isArray(statusDataset.backgroundColor) && statusDataset.backgroundColor.length === statusValues.length
? statusDataset.backgroundColor
: [
@ -2636,11 +2650,10 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
}
const label = context.label || '';
const value = typeof context.raw === 'number' ? context.raw : Number(context.raw || 0);
const data = Array.isArray(context.dataset.data) ? context.dataset.data : [];
const total = data.reduce(function (sum, item) {
return sum + (Number(item) || 0);
}, 0);
const percentage = total > 0 ? ((value / total) * 100).toFixed(1) : '0.0';
if (label.toLowerCase().includes('repetid')) {
return label + ': ' + value;
}
const percentage = statusPercentageBase > 0 ? ((value / statusPercentageBase) * 100).toFixed(1) : '0.0';
return label + ': ' + value + ' (' + percentage + '%)';
}
}

View File

@ -1076,7 +1076,7 @@ try {
'assigned_at' => $currentTracking['assigned_at'] ?? null,
]));
if (empty($promoFinalDayInfo['is_promo_final'])) {
$promoFinalThresholdDay = (int) ($promoFinalDayInfo['promo_final_threshold_day'] ?? 4);
$promoFinalThresholdDay = (int) ($promoFinalDayInfo['promo_final_threshold_day'] ?? 3);
throw new RuntimeException('Este pedido aún no puede pasar a Promo Final. Recién se habilita desde el Día ' . $promoFinalThresholdDay . '.');
}