Autosave: 20260722-233438
This commit is contained in:
parent
88aaaa4cae
commit
82475a4d30
@ -512,6 +512,18 @@ h1, .h1 {
|
||||
background: linear-gradient(135deg, rgba(108, 117, 125, .12), rgba(108, 117, 125, .04));
|
||||
}
|
||||
|
||||
.cc-kpi-pill-total {
|
||||
background: linear-gradient(135deg, rgba(20, 184, 166, .18), rgba(13, 110, 253, .06));
|
||||
border-color: rgba(20, 184, 166, .18);
|
||||
}
|
||||
|
||||
.cc-kpi-meta {
|
||||
font-size: .73rem;
|
||||
line-height: 1.15;
|
||||
color: #64748b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cc-kpi-chart-card {
|
||||
border-radius: 1.2rem;
|
||||
overflow: hidden;
|
||||
|
||||
@ -251,6 +251,7 @@ $allowedViews = [
|
||||
'pendientes_hoy' => 'Bandeja principal',
|
||||
'nuevos_hoy' => 'Pedidos asignados hoy',
|
||||
'confirmados' => 'Confirmados',
|
||||
'recuperados' => 'Recuperados',
|
||||
'seguimiento' => 'Seguimiento',
|
||||
'promo_final' => 'Promo Final',
|
||||
'observados' => 'Observados',
|
||||
@ -290,6 +291,7 @@ $stats = [
|
||||
'pendientes_hoy' => 0,
|
||||
'nuevos_hoy' => 0,
|
||||
'confirmados' => 0,
|
||||
'recuperados' => 0,
|
||||
'seguimiento' => 0,
|
||||
'promo_final' => 0,
|
||||
'observados' => 0,
|
||||
@ -462,6 +464,9 @@ try {
|
||||
if (in_array($order['estado'], cc_test_confirmed_states(), true)) {
|
||||
$stats['confirmados']++;
|
||||
}
|
||||
if (cc_test_is_recovered_today($order, $todayStart)) {
|
||||
$stats['recuperados']++;
|
||||
}
|
||||
if ($order['estado'] === 'SE ENVIO NUMERO DE CUENTA' && !$order['es_promo_final']) {
|
||||
$stats['seguimiento']++;
|
||||
}
|
||||
@ -474,26 +479,33 @@ try {
|
||||
}
|
||||
unset($order);
|
||||
|
||||
$performanceDashboard = cc_test_build_performance_dashboard($orders, $assessors, 7);
|
||||
$performanceOrders = $orders;
|
||||
if ($selectedAssessorFilter !== '') {
|
||||
$performanceOrders = array_values(array_filter($orders, static function (array $order) use ($selectedAssessorFilter): bool {
|
||||
return ($order['matches_assessor_filter'] ?? false) === true;
|
||||
}));
|
||||
}
|
||||
|
||||
$performanceDashboard = cc_test_build_performance_dashboard($performanceOrders, $assessors, 7);
|
||||
$performanceTitle = $isAdmin
|
||||
? ($selectedAssessorFilterLabel !== '' ? 'KPI diario · ' . $selectedAssessorFilterLabel : 'KPI diario por asesora')
|
||||
: 'Mi KPI diario';
|
||||
$performanceSubtitle = $isAdmin
|
||||
? 'Confirmación = pedidos asignados hoy confirmados hoy. Recuperación = pedidos asignados antes de hoy confirmados hoy.'
|
||||
: 'Tus KPIs de hoy se calculan sobre tus pedidos asignados hoy. Confirmación = asignados hoy confirmados hoy. Recuperación = asignados antes de hoy confirmados hoy.';
|
||||
? '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.'
|
||||
: 'Tus KPIs de hoy se calculan sobre tus pedidos asignados hoy. Confirmación = asignados hoy confirmados hoy. Recuperación = asignados antes de hoy confirmados hoy. Rendimiento del día = confirmados totales (nuevos + recuperados) sobre asignados hoy.';
|
||||
$performanceDashboardHtml = cc_test_render_performance_dashboard($performanceDashboard, [
|
||||
'title' => $performanceTitle,
|
||||
'subtitle' => $performanceSubtitle,
|
||||
'chart1_title' => $isAdmin ? 'Distribución de estados' : 'Mi distribución de estados',
|
||||
'chart1_note' => 'Verde = confirmados de pedidos asignados hoy, amarillo = confirmados de pedidos asignados antes de hoy, azul = seguimiento abierto, gris = repetidos, rojo = cancelados. La lista lateral muestra el % de cada estado.',
|
||||
'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.',
|
||||
'chart2_title' => $isAdmin ? 'Evolución de los últimos 7 días' : 'Tu 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 en SE ENVIO NUMERO DE CUENTA que todavía no pasan a Promo Final.',
|
||||
'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.',
|
||||
]);
|
||||
|
||||
$panelSignature = cc_test_panel_orders_signature($orders);
|
||||
|
||||
$visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view, $selectedAssessorFilter): bool {
|
||||
$visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view, $selectedAssessorFilter, $todayStart): bool {
|
||||
if ($selectedAssessorFilter !== '' && !($order['matches_assessor_filter'] ?? false)) {
|
||||
return false;
|
||||
}
|
||||
@ -502,6 +514,7 @@ try {
|
||||
'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),
|
||||
'recuperados' => cc_test_is_recovered_today($order, $todayStart),
|
||||
'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),
|
||||
@ -528,6 +541,20 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
if ($view === 'recuperados') {
|
||||
$aRecovered = cc_test_dashboard_action_datetime($a);
|
||||
$bRecovered = cc_test_dashboard_action_datetime($b);
|
||||
if ($aRecovered && $bRecovered && $aRecovered != $bRecovered) {
|
||||
return $bRecovered <=> $aRecovered;
|
||||
}
|
||||
if ($aRecovered && !$bRecovered) {
|
||||
return -1;
|
||||
}
|
||||
if (!$aRecovered && $bRecovered) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($view === 'promo_final') {
|
||||
$aDays = (int) ($a['dias_seguimiento'] ?? 0);
|
||||
$bDays = (int) ($b['dias_seguimiento'] ?? 0);
|
||||
@ -841,6 +868,16 @@ require_once 'layout_header.php';
|
||||
</article>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-2">
|
||||
<a href="<?php echo htmlspecialchars(cc_test_build_url('call_center_pro.php', array_merge($callCenterParams, ['view' => 'recuperados']))); ?>" class="text-decoration-none">
|
||||
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'recuperados' ? 'bg-warning-subtle border border-warning' : 'bg-white'; ?>">
|
||||
<div class="card-body">
|
||||
<div class="small text-uppercase text-muted mb-2">Recuperados</div>
|
||||
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['recuperados']; ?></div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-2">
|
||||
<a href="<?php echo htmlspecialchars(cc_test_build_url('call_center_pro.php', array_merge($callCenterParams, ['view' => 'seguimiento']))); ?>" 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'; ?>">
|
||||
|
||||
@ -164,6 +164,7 @@ $allowedViews = [
|
||||
'pendientes_hoy' => 'Bandeja principal',
|
||||
'nuevos_hoy' => 'Nuevos de hoy',
|
||||
'confirmados' => 'Confirmados',
|
||||
'recuperados' => 'Recuperados',
|
||||
'seguimiento' => 'Seguimiento',
|
||||
'promo_final' => 'Promo Final',
|
||||
'observados' => 'Observados',
|
||||
@ -206,6 +207,7 @@ $stats = [
|
||||
'pendientes_hoy' => 0,
|
||||
'nuevos_hoy' => 0,
|
||||
'confirmados' => 0,
|
||||
'recuperados' => 0,
|
||||
'seguimiento' => 0,
|
||||
'promo_final' => 0,
|
||||
'observados' => 0,
|
||||
@ -663,6 +665,9 @@ try {
|
||||
if (in_array($order['estado'], cc_test_confirmed_states(), true)) {
|
||||
$stats['confirmados']++;
|
||||
}
|
||||
if (cc_test_is_recovered_today($order, $todayStart)) {
|
||||
$stats['recuperados']++;
|
||||
}
|
||||
if ($order['estado'] === 'SE ENVIO NUMERO DE CUENTA' && !$order['es_promo_final']) {
|
||||
$stats['seguimiento']++;
|
||||
}
|
||||
@ -678,12 +683,12 @@ try {
|
||||
$performanceDashboard = cc_test_build_performance_dashboard($orders, $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.',
|
||||
'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.',
|
||||
'chart1_title' => 'Distribución de estados',
|
||||
'chart1_note' => 'Verde = confirmados de pedidos asignados hoy, amarillo = confirmados de pedidos asignados antes de hoy, azul = seguimiento abierto, gris = repetidos, rojo = cancelados. La lista lateral muestra el % de cada estado.',
|
||||
'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.',
|
||||
'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 en SE ENVIO NUMERO DE CUENTA que todavía no pasan a Promo Final.',
|
||||
'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.',
|
||||
]);
|
||||
|
||||
$orderedAssessorKeys = array_values(array_filter(cc_test_allowed_module_user_keys(), static function (string $key) use ($assessors): bool {
|
||||
@ -753,11 +758,12 @@ try {
|
||||
];
|
||||
}
|
||||
|
||||
$visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view): bool {
|
||||
$visibleOrders = array_values(array_filter($orders, static function (array $order) use ($view, $todayStart): 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),
|
||||
'recuperados' => cc_test_is_recovered_today($order, $todayStart),
|
||||
'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),
|
||||
@ -781,6 +787,20 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
if ($view === 'recuperados') {
|
||||
$aRecovered = cc_test_dashboard_action_datetime($a);
|
||||
$bRecovered = cc_test_dashboard_action_datetime($b);
|
||||
if ($aRecovered && $bRecovered && $aRecovered != $bRecovered) {
|
||||
return $bRecovered <=> $aRecovered;
|
||||
}
|
||||
if ($aRecovered && !$bRecovered) {
|
||||
return -1;
|
||||
}
|
||||
if (!$aRecovered && $bRecovered) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($view === 'nuevos_hoy') {
|
||||
$aNew = cc_test_parse_datetime($a['first_seen_at'] ?? null);
|
||||
$bNew = cc_test_parse_datetime($b['first_seen_at'] ?? null);
|
||||
@ -1182,6 +1202,16 @@ require_once 'layout_header.php';
|
||||
</article>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-2">
|
||||
<a href="?view=recuperados&store=<?php echo htmlspecialchars($storeKey); ?>" class="text-decoration-none">
|
||||
<article class="card border-0 shadow-sm h-100 <?php echo $view === 'recuperados' ? 'bg-warning-subtle border border-warning' : 'bg-white'; ?>">
|
||||
<div class="card-body">
|
||||
<div class="small text-uppercase text-muted mb-2">Recuperados</div>
|
||||
<div class="display-6 fw-bold mb-0"><?php echo (int) $stats['recuperados']; ?></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'; ?>">
|
||||
|
||||
@ -660,6 +660,25 @@ function cc_test_dashboard_action_datetime(array $order): ?DateTimeImmutable
|
||||
return null;
|
||||
}
|
||||
|
||||
function cc_test_is_recovered_today(array $order, ?DateTimeImmutable $todayStart = null): bool
|
||||
{
|
||||
$estado = cc_test_normalize_state((string) ($order['estado'] ?? ''));
|
||||
if (!in_array($estado, cc_test_confirmed_states(), true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$todayStart = $todayStart ?? new DateTimeImmutable('today');
|
||||
$assignedDate = cc_test_followup_parse_datetime($order['assigned_at'] ?? null);
|
||||
$actionDate = cc_test_dashboard_action_datetime($order);
|
||||
|
||||
if (!$assignedDate || !$actionDate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $assignedDate->format('Y-m-d') < $todayStart->format('Y-m-d')
|
||||
&& $actionDate->format('Y-m-d') === $todayStart->format('Y-m-d');
|
||||
}
|
||||
|
||||
function cc_test_dashboard_bucket_key(array $order, array $assessors, bool $includeUnassigned = true): string
|
||||
{
|
||||
$assessorKey = trim((string) ($order['assessor_key'] ?? ''));
|
||||
@ -738,11 +757,19 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
'canceled_today' => 0,
|
||||
'repeated_today' => 0,
|
||||
'followup_open' => 0,
|
||||
'observados_today' => 0,
|
||||
'confirm_rate_today' => 0.0,
|
||||
'recovery_rate_today' => 0.0,
|
||||
'performance_today_rate' => 0.0,
|
||||
];
|
||||
|
||||
$hasUnassignedBucket = false;
|
||||
$followupStateCounts = [
|
||||
'POR LLAMAR' => 0,
|
||||
'DEVOLVER LLAMADA' => 0,
|
||||
'OBSERVADO' => 0,
|
||||
'SE ENVIO NUMERO DE CUENTA' => 0,
|
||||
];
|
||||
|
||||
foreach ($orders as $order) {
|
||||
$summary['scope_total']++;
|
||||
@ -766,8 +793,6 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
];
|
||||
}
|
||||
|
||||
$originDate = cc_test_dashboard_origin_datetime($order);
|
||||
$originKey = $originDate ? $originDate->format('Y-m-d') : null;
|
||||
$assignedDate = cc_test_followup_parse_datetime($order['assigned_at'] ?? null);
|
||||
$assignedKey = $assignedDate ? $assignedDate->format('Y-m-d') : null;
|
||||
$actionDate = cc_test_dashboard_action_datetime($order);
|
||||
@ -778,34 +803,46 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
$isConfirmed = in_array($estado, cc_test_confirmed_states(), true);
|
||||
$isCanceled = $estado === 'CANCELADO';
|
||||
$isRepeated = $estado === 'REPETIDO';
|
||||
$isFollowupOpen = $estado === 'SE ENVIO NUMERO DE CUENTA' && !$isPromoFinal;
|
||||
$isFollowupState = in_array($estado, cc_test_followup_tracking_states(), true);
|
||||
$isFollowupOpen = $isFollowupState && !$isPromoFinal;
|
||||
|
||||
if ($assignedKey === $todayKey) {
|
||||
$assignmentKey = $assignedKey;
|
||||
$isAssignedToday = $assignmentKey === $todayKey;
|
||||
|
||||
if ($isAssignedToday) {
|
||||
$bucketStats[$bucketKey]['assigned_today']++;
|
||||
$summary['assigned_today']++;
|
||||
|
||||
if (isset($trend[$assignedKey])) {
|
||||
$trend[$assignedKey]['assigned_today']++;
|
||||
if (isset($trend[$assignmentKey])) {
|
||||
$trend[$assignmentKey]['assigned_today']++;
|
||||
}
|
||||
|
||||
if ($isFollowupOpen) {
|
||||
$bucketStats[$bucketKey]['followup_open']++;
|
||||
$summary['followup_open']++;
|
||||
|
||||
if (isset($followupStateCounts[$estado])) {
|
||||
$followupStateCounts[$estado]++;
|
||||
}
|
||||
|
||||
if ($estado === 'OBSERVADO') {
|
||||
$summary['observados_today']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isFollowupOpen) {
|
||||
$bucketStats[$bucketKey]['followup_open']++;
|
||||
$summary['followup_open']++;
|
||||
}
|
||||
|
||||
$confirmedReferenceKey = $assignedKey ?? $originKey;
|
||||
$confirmedReferenceKey = $assignmentKey;
|
||||
|
||||
if ($isConfirmed && $actionKey === $todayKey) {
|
||||
if ($confirmedReferenceKey !== null && $confirmedReferenceKey < $todayKey) {
|
||||
$bucketStats[$bucketKey]['recovered']++;
|
||||
$summary['confirmed_today_recovered']++;
|
||||
} else {
|
||||
} elseif ($isAssignedToday) {
|
||||
$bucketStats[$bucketKey]['confirmed_new']++;
|
||||
$summary['confirmed_today_new']++;
|
||||
}
|
||||
|
||||
if (isset($trend[$actionKey])) {
|
||||
if ($isAssignedToday && isset($trend[$actionKey])) {
|
||||
if ($confirmedReferenceKey !== null && $confirmedReferenceKey < $actionKey) {
|
||||
$trend[$actionKey]['recovered']++;
|
||||
} else {
|
||||
@ -814,7 +851,7 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
}
|
||||
}
|
||||
|
||||
if ($isCanceled && $actionKey === $todayKey) {
|
||||
if ($isAssignedToday && $isCanceled && $actionKey === $todayKey) {
|
||||
$bucketStats[$bucketKey]['canceled']++;
|
||||
$summary['canceled_today']++;
|
||||
|
||||
@ -823,7 +860,7 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
}
|
||||
}
|
||||
|
||||
if ($isRepeated && $actionKey === $todayKey) {
|
||||
if ($isAssignedToday && $isRepeated && $actionKey === $todayKey) {
|
||||
$bucketStats[$bucketKey]['repeated']++;
|
||||
$summary['repeated_today']++;
|
||||
}
|
||||
@ -836,6 +873,9 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
$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)
|
||||
: 0.0;
|
||||
|
||||
$advisorLabels = [];
|
||||
$advisorAssigned = [];
|
||||
@ -898,28 +938,37 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
return [
|
||||
'summary' => $summary,
|
||||
'status_chart' => [
|
||||
'labels' => ['Confirmados nuevos', 'Recuperados', 'Seguimiento abierto', 'Repetidos', 'Cancelados'],
|
||||
'labels' => ['Confirmados nuevos', 'Recuperados', 'Por llamar', 'Devolver llamada', 'Observados', 'Se envió número de cuenta', 'Repetidos', 'Cancelados'],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => 'Estados',
|
||||
'data' => [
|
||||
(int) ($summary['confirmed_today_new'] ?? 0),
|
||||
(int) ($summary['confirmed_today_recovered'] ?? 0),
|
||||
(int) ($summary['followup_open'] ?? 0),
|
||||
(int) ($followupStateCounts['POR LLAMAR'] ?? 0),
|
||||
(int) ($followupStateCounts['DEVOLVER LLAMADA'] ?? 0),
|
||||
(int) ($followupStateCounts['OBSERVADO'] ?? 0),
|
||||
(int) ($followupStateCounts['SE ENVIO NUMERO DE CUENTA'] ?? 0),
|
||||
(int) ($summary['repeated_today'] ?? 0),
|
||||
(int) ($summary['canceled_today'] ?? 0),
|
||||
],
|
||||
'backgroundColor' => [
|
||||
'rgba(25, 135, 84, 0.9)',
|
||||
'rgba(255, 193, 7, 0.92)',
|
||||
'rgba(20, 184, 166, 0.84)',
|
||||
'rgba(13, 110, 253, 0.88)',
|
||||
'rgba(13, 202, 240, 0.86)',
|
||||
'rgba(255, 193, 7, 0.82)',
|
||||
'rgba(253, 126, 20, 0.84)',
|
||||
'rgba(108, 117, 125, 0.84)',
|
||||
'rgba(220, 53, 69, 0.9)',
|
||||
],
|
||||
'borderColor' => [
|
||||
'rgba(25, 135, 84, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(13, 148, 136, 1)',
|
||||
'rgba(13, 110, 253, 1)',
|
||||
'rgba(13, 202, 240, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(253, 126, 20, 1)',
|
||||
'rgba(108, 117, 125, 1)',
|
||||
'rgba(220, 53, 69, 1)',
|
||||
],
|
||||
@ -1025,12 +1074,12 @@ function cc_test_build_performance_dashboard(array $orders, array $assessors, in
|
||||
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.'));
|
||||
$chart1Title = trim((string) ($options['chart1_title'] ?? 'Distribución de estados'));
|
||||
$chart1Note = trim((string) ($options['chart1_note'] ?? 'Verde = confirmados de pedidos asignados hoy, amarillo = confirmados de pedidos asignados antes de hoy, azul = seguimiento abierto, gris = repetidos, rojo = cancelados. La lista lateral muestra el % de cada estado.'));
|
||||
$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.'));
|
||||
$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.'));
|
||||
$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 en SE ENVIO NUMERO DE CUENTA que todavía no pasan a Promo Final.'));
|
||||
$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.'));
|
||||
$sectionId = preg_replace('/[^A-Za-z0-9_-]+/', '', (string) ($options['section_id'] ?? 'ccPerformanceDashboard'));
|
||||
if ($sectionId === '') {
|
||||
$sectionId = 'ccPerformanceDashboard';
|
||||
@ -1038,27 +1087,38 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
|
||||
$summary = (array) ($dashboard['summary'] ?? []);
|
||||
$trendChart = (array) ($dashboard['trend_chart'] ?? []);
|
||||
$statusTotal = (int) ($summary['confirmed_today_new'] ?? 0)
|
||||
+ (int) ($summary['confirmed_today_recovered'] ?? 0)
|
||||
+ (int) ($summary['followup_open'] ?? 0)
|
||||
+ (int) ($summary['repeated_today'] ?? 0)
|
||||
+ (int) ($summary['canceled_today'] ?? 0);
|
||||
$statusChart = (array) ($dashboard['status_chart'] ?? []);
|
||||
$statusChartLabels = array_values((array) ($statusChart['labels'] ?? []));
|
||||
$statusChartDataset = (array) (($statusChart['datasets'][0] ?? []) ?: []);
|
||||
$statusChartValues = array_map(static function ($value) {
|
||||
return (int) $value;
|
||||
}, array_values((array) ($statusChartDataset['data'] ?? [])));
|
||||
$statusChartColors = is_array($statusChartDataset['backgroundColor'] ?? null)
|
||||
? array_values($statusChartDataset['backgroundColor'])
|
||||
: [];
|
||||
$statusTotal = array_sum($statusChartValues);
|
||||
$confirmedTodayNew = (int) ($summary['confirmed_today_new'] ?? 0);
|
||||
$confirmedTodayRecovered = (int) ($summary['confirmed_today_recovered'] ?? 0);
|
||||
$confirmedTodayTotal = (int) ($summary['confirmed_today_total'] ?? 0);
|
||||
$performanceTodayRate = (float) ($summary['performance_today_rate'] ?? 0);
|
||||
$performanceTodayMeta = sprintf(
|
||||
'%d confirmado%s = %d nuevo%s + %d recuperado%s',
|
||||
$confirmedTodayTotal,
|
||||
$confirmedTodayTotal === 1 ? '' : 's',
|
||||
$confirmedTodayNew,
|
||||
$confirmedTodayNew === 1 ? '' : 's',
|
||||
$confirmedTodayRecovered,
|
||||
$confirmedTodayRecovered === 1 ? '' : 's'
|
||||
);
|
||||
|
||||
$statusLegendItems = [];
|
||||
$statusLegendRows = [
|
||||
['label' => 'Confirmados nuevos', 'value' => (int) ($summary['confirmed_today_new'] ?? 0), 'color' => 'rgba(25, 135, 84, 0.9)'],
|
||||
['label' => 'Recuperados', 'value' => (int) ($summary['confirmed_today_recovered'] ?? 0), 'color' => 'rgba(255, 193, 7, 0.92)'],
|
||||
['label' => 'Seguimiento abierto', 'value' => (int) ($summary['followup_open'] ?? 0), 'color' => 'rgba(13, 110, 253, 0.88)'],
|
||||
['label' => 'Repetidos', 'value' => (int) ($summary['repeated_today'] ?? 0), 'color' => 'rgba(108, 117, 125, 0.84)'],
|
||||
['label' => 'Cancelados', 'value' => (int) ($summary['canceled_today'] ?? 0), 'color' => 'rgba(220, 53, 69, 0.9)'],
|
||||
];
|
||||
if ($statusTotal > 0) {
|
||||
foreach ($statusLegendRows as $row) {
|
||||
foreach ($statusChartValues as $index => $value) {
|
||||
$statusLegendItems[] = [
|
||||
'label' => $row['label'],
|
||||
'value' => (int) $row['value'],
|
||||
'percentage' => round(((float) $row['value'] / $statusTotal) * 100, 1),
|
||||
'color' => $row['color'],
|
||||
'label' => (string) ($statusChartLabels[$index] ?? ('Estado ' . ($index + 1))),
|
||||
'value' => (int) $value,
|
||||
'percentage' => round(((float) $value / $statusTotal) * 100, 1),
|
||||
'color' => (string) ($statusChartColors[$index] ?? 'rgba(108, 117, 125, 0.65)'),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
@ -1072,8 +1132,9 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
|
||||
$badges = [
|
||||
['label' => 'Asignados hoy', 'value' => (int) ($summary['assigned_today'] ?? 0), 'class' => 'cc-kpi-pill-primary'],
|
||||
['label' => 'Confirmados hoy', 'value' => (int) ($summary['confirmed_today_total'] ?? 0), 'class' => 'cc-kpi-pill-success'],
|
||||
['label' => 'Recuperados', 'value' => (int) ($summary['confirmed_today_recovered'] ?? 0), 'class' => 'cc-kpi-pill-warning'],
|
||||
['label' => 'Confirmados hoy', 'value' => $confirmedTodayTotal, 'class' => 'cc-kpi-pill-success'],
|
||||
['label' => 'Recuperados', 'value' => $confirmedTodayRecovered, 'class' => 'cc-kpi-pill-warning'],
|
||||
['label' => 'Rendimiento del día', 'value' => number_format($performanceTodayRate, 1) . '%', 'class' => 'cc-kpi-pill-total', 'meta' => $performanceTodayMeta],
|
||||
['label' => 'Seguimiento abierto', 'value' => (int) ($summary['followup_open'] ?? 0), 'class' => 'cc-kpi-pill-info'],
|
||||
['label' => 'Cancelados hoy', 'value' => (int) ($summary['canceled_today'] ?? 0), 'class' => 'cc-kpi-pill-danger'],
|
||||
['label' => '% confirmación', 'value' => number_format((float) ($summary['confirm_rate_today'] ?? 0), 1) . '%', 'class' => 'cc-kpi-pill-dark'],
|
||||
@ -1114,6 +1175,9 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
<div class="cc-kpi-pill <?php echo htmlspecialchars($badge['class']); ?>">
|
||||
<span class="cc-kpi-label"><?php echo htmlspecialchars((string) $badge['label']); ?></span>
|
||||
<span class="cc-kpi-value"><?php echo htmlspecialchars((string) $badge['value']); ?></span>
|
||||
<?php if (!empty($badge['meta'])): ?>
|
||||
<span class="cc-kpi-meta"><?php echo htmlspecialchars((string) $badge['meta']); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@ -1141,7 +1205,7 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
</div>
|
||||
<div class="col-12 col-xl-5">
|
||||
<div class="cc-kpi-status-legend h-100">
|
||||
<div class="small text-uppercase text-muted fw-semibold mb-2">Detalle por estado (%)</div>
|
||||
<div class="small text-uppercase text-muted fw-semibold mb-2">Detalle del KPI de hoy (%)</div>
|
||||
<?php foreach ($statusLegendItems as $item): ?>
|
||||
<div class="cc-kpi-status-item">
|
||||
<span class="cc-kpi-status-dot" style="background: <?php echo htmlspecialchars((string) $item['color']); ?>;"></span>
|
||||
@ -1211,8 +1275,11 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
? statusDataset.backgroundColor
|
||||
: [
|
||||
'rgba(25, 135, 84, 0.9)',
|
||||
'rgba(255, 193, 7, 0.92)',
|
||||
'rgba(20, 184, 166, 0.84)',
|
||||
'rgba(13, 110, 253, 0.88)',
|
||||
'rgba(13, 202, 240, 0.86)',
|
||||
'rgba(255, 193, 7, 0.82)',
|
||||
'rgba(253, 126, 20, 0.84)',
|
||||
'rgba(108, 117, 125, 0.84)',
|
||||
'rgba(220, 53, 69, 0.9)'
|
||||
];
|
||||
@ -1220,8 +1287,11 @@ function cc_test_render_performance_dashboard(array $dashboard, array $options =
|
||||
? statusDataset.borderColor
|
||||
: [
|
||||
'rgba(25, 135, 84, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(13, 148, 136, 1)',
|
||||
'rgba(13, 110, 253, 1)',
|
||||
'rgba(13, 202, 240, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(253, 126, 20, 1)',
|
||||
'rgba(108, 117, 125, 1)',
|
||||
'rgba(220, 53, 69, 1)'
|
||||
];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user