diff --git a/dashboard_principal.php b/dashboard_principal.php index d5770b29..973e39ac 100644 --- a/dashboard_principal.php +++ b/dashboard_principal.php @@ -13,15 +13,23 @@ if (!isset($_SESSION['user_id']) || !in_array($_SESSION['user_role'], ['Administ $db = db(); // --- LÓGICA DE FILTROS --- -$period = $_GET['period'] ?? '7'; -$start_date = $_GET['start_date'] ?? ''; -$end_date = $_GET['end_date'] ?? ''; +$period = $_GET['period'] ?? 'today'; +$start_date = trim((string)($_GET['start_date'] ?? '')); +$end_date = trim((string)($_GET['end_date'] ?? '')); +$isValidDashboardDate = static function (string $date): bool { + $parsed = DateTimeImmutable::createFromFormat('Y-m-d', $date); + return $parsed instanceof DateTimeImmutable && $parsed->format('Y-m-d') === $date; +}; $date_condition = ""; $label_period = ""; -if ($period === 'custom' && !empty($start_date) && !empty($end_date)) { - $date_condition = "DATE(p.created_at) BETWEEN '$start_date' AND '$end_date'"; +if ($period === 'custom' && $isValidDashboardDate($start_date) && $isValidDashboardDate($end_date)) { + if ($start_date > $end_date) { + [$start_date, $end_date] = [$end_date, $start_date]; + } + + $date_condition = "DATE(p.created_at) BETWEEN " . $db->quote($start_date) . " AND " . $db->quote($end_date); $label_period = "Desde " . date('d/m/Y', strtotime($start_date)) . " hasta " . date('d/m/Y', strtotime($end_date)); } else { switch ($period) { @@ -66,9 +74,9 @@ if ($period === 'custom' && !empty($start_date) && !empty($end_date)) { $label_period = "Último Año"; break; default: - $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)"; - $label_period = "Últimos 7 días"; - $period = '7'; + $date_condition = "DATE(p.created_at) = CURDATE()"; + $label_period = "Hoy"; + $period = 'today'; } } diff --git a/db/migrations/077_add_pendiente_to_tipo_paquete_enum.sql b/db/migrations/077_add_pendiente_to_tipo_paquete_enum.sql new file mode 100644 index 00000000..5e9038ea --- /dev/null +++ b/db/migrations/077_add_pendiente_to_tipo_paquete_enum.sql @@ -0,0 +1,3 @@ +-- Deprecated/no-op. +-- PENDIENTE belongs to pedidos.estado, not to pedidos.tipo_paquete. +-- The final package ENUM is enforced in 078_clean_tipo_paquete_enum.sql. diff --git a/db/migrations/078_clean_tipo_paquete_enum.sql b/db/migrations/078_clean_tipo_paquete_enum.sql new file mode 100644 index 00000000..5e8c6851 --- /dev/null +++ b/db/migrations/078_clean_tipo_paquete_enum.sql @@ -0,0 +1,4 @@ +-- Keep pedidos.tipo_paquete aligned with the package selector. +-- PENDIENTE belongs to pedidos.estado, not to tipo_paquete. +UPDATE pedidos SET tipo_paquete = NULL WHERE tipo_paquete = 'PENDIENTE'; +ALTER TABLE pedidos MODIFY COLUMN tipo_paquete ENUM('RUTA', 'CONTRAENTREGA', 'NO CONTESTA, VOLVER A LLAMAR', 'PENDIENTE A RETORNO', 'COMPLETADO', 'EMPAQUETADO', 'RETORNADO', 'ANULADO') DEFAULT NULL; diff --git a/db/migrations/079_rename_empaquetado_to_preparado_tipo_paquete.sql b/db/migrations/079_rename_empaquetado_to_preparado_tipo_paquete.sql new file mode 100644 index 00000000..fea972ed --- /dev/null +++ b/db/migrations/079_rename_empaquetado_to_preparado_tipo_paquete.sql @@ -0,0 +1,5 @@ +-- Rename package status EMPAQUETADO to PREPARADO in pedidos.tipo_paquete. +-- EMPAQUETADO is kept only as a temporary legacy value during migration so existing rows can be converted safely. +ALTER TABLE pedidos MODIFY COLUMN tipo_paquete ENUM('RUTA', 'CONTRAENTREGA', 'NO CONTESTA, VOLVER A LLAMAR', 'PENDIENTE A RETORNO', 'COMPLETADO', 'EMPAQUETADO', 'PREPARADO', 'RETORNADO', 'ANULADO') DEFAULT NULL; +UPDATE pedidos SET tipo_paquete = 'PREPARADO' WHERE tipo_paquete = 'EMPAQUETADO'; +ALTER TABLE pedidos MODIFY COLUMN tipo_paquete ENUM('RUTA', 'CONTRAENTREGA', 'NO CONTESTA, VOLVER A LLAMAR', 'PENDIENTE A RETORNO', 'COMPLETADO', 'PREPARADO', 'RETORNADO', 'ANULADO') DEFAULT NULL; diff --git a/includes/tipo_paquete.php b/includes/tipo_paquete.php new file mode 100644 index 00000000..1a6d4960 --- /dev/null +++ b/includes/tipo_paquete.php @@ -0,0 +1,136 @@ + 'RUTA', + 'CONTRAENTREGA' => 'CONTRAENTREGA', + 'NOCONTESTAVOLVERALLAMAR' => 'NO CONTESTA, VOLVER A LLAMAR', + 'PENDIENTEARETORNO' => 'PENDIENTE A RETORNO', + 'COMPLETADO' => 'COMPLETADO', + 'EMPAQUETADO' => 'PREPARADO', + 'PREPARADO' => 'PREPARADO', + 'EMPACADO' => 'PREPARADO', + 'EMPAQUETARDO' => 'PREPARADO', + 'RETORNADO' => 'RETORNADO', + 'ANULADO' => 'ANULADO', + ]; + + return $aliases[$canonicalKey] ?? $normalized; + } +} + +if (!function_exists('tipoPaqueteIsValid')) { + function tipoPaqueteIsValid(?string $value): bool + { + return $value === null || in_array($value, tipoPaqueteValidValues(), true); + } +} + +if (!function_exists('ensureTipoPaqueteEnumDefinition')) { + function ensureTipoPaqueteEnumDefinition(PDO $pdo, bool $force = false): void + { + static $checked = false; + + if ($checked && !$force) { + return; + } + + $stmt = $pdo->query("SHOW COLUMNS FROM pedidos LIKE 'tipo_paquete'"); + $column = $stmt ? $stmt->fetch(PDO::FETCH_ASSOC) : false; + if (!$column || empty($column['Type'])) { + $checked = true; + return; + } + + $currentType = (string) $column['Type']; + $validValues = tipoPaqueteValidValues(); + $missingRequiredValue = false; + + foreach ($validValues as $value) { + if (strpos($currentType, "'" . str_replace("'", "''", $value) . "'") === false) { + $missingRequiredValue = true; + break; + } + } + + $hasLegacyPendiente = strpos($currentType, "'PENDIENTE'") !== false; + $hasLegacyEmpaquetado = strpos($currentType, "'EMPAQUETADO'") !== false; + + if ($force || $missingRequiredValue || $hasLegacyPendiente || $hasLegacyEmpaquetado) { + $quotedValues = array_map(static function (string $value) use ($pdo): string { + return $pdo->quote($value); + }, $validValues); + $enumValuesSql = implode(', ', $quotedValues); + + $transitionValues = array_values(array_unique(array_merge( + $validValues, + ['EMPAQUETADO', 'PENDIENTE', 'NO CONTESTA', 'VOLVER A LLAMAR'] + ))); + $quotedTransitionValues = array_map(static function (string $value) use ($pdo): string { + return $pdo->quote($value); + }, $transitionValues); + $transitionValuesSql = implode(', ', $quotedTransitionValues); + + $pdo->exec("ALTER TABLE pedidos MODIFY COLUMN tipo_paquete ENUM($transitionValuesSql) DEFAULT NULL"); + $pdo->exec("UPDATE pedidos SET tipo_paquete = 'PREPARADO' WHERE tipo_paquete = 'EMPAQUETADO'"); + $pdo->exec("UPDATE pedidos SET tipo_paquete = 'NO CONTESTA, VOLVER A LLAMAR' WHERE tipo_paquete IN ('NO CONTESTA', 'VOLVER A LLAMAR')"); + $pdo->exec("UPDATE pedidos SET tipo_paquete = NULL WHERE tipo_paquete = 'PENDIENTE'"); + $pdo->exec("UPDATE pedidos SET tipo_paquete = NULL WHERE tipo_paquete IS NOT NULL AND tipo_paquete NOT IN ($enumValuesSql)"); + $pdo->exec("ALTER TABLE pedidos MODIFY COLUMN tipo_paquete ENUM($enumValuesSql) DEFAULT NULL"); + } + + $checked = true; + } +} diff --git a/pedidos_contraentrega.php b/pedidos_contraentrega.php index db3744cc..e197a67b 100644 --- a/pedidos_contraentrega.php +++ b/pedidos_contraentrega.php @@ -7,7 +7,9 @@ if (!isset($_SESSION['user_id'])) { require_once 'db/config.php'; require_once 'includes/contraentrega_cobertura.php'; +require_once 'includes/tipo_paquete.php'; $pdo = db(); +ensureTipoPaqueteEnumDefinition($pdo); $user_id = $_SESSION['user_id']; $user_role = $_SESSION['user_role'] ?? 'Asesor'; @@ -320,7 +322,7 @@ include 'layout_header.php'; " . htmlspecialchars($paquete) . ""; @@ -333,7 +335,7 @@ include 'layout_header.php';