Autosave: 20260610-161940
This commit is contained in:
parent
3f9d04425f
commit
7da0c2905a
@ -13,15 +13,23 @@ if (!isset($_SESSION['user_id']) || !in_array($_SESSION['user_role'], ['Administ
|
|||||||
$db = db();
|
$db = db();
|
||||||
|
|
||||||
// --- LÓGICA DE FILTROS ---
|
// --- LÓGICA DE FILTROS ---
|
||||||
$period = $_GET['period'] ?? '7';
|
$period = $_GET['period'] ?? 'today';
|
||||||
$start_date = $_GET['start_date'] ?? '';
|
$start_date = trim((string)($_GET['start_date'] ?? ''));
|
||||||
$end_date = $_GET['end_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 = "";
|
$date_condition = "";
|
||||||
$label_period = "";
|
$label_period = "";
|
||||||
|
|
||||||
if ($period === 'custom' && !empty($start_date) && !empty($end_date)) {
|
if ($period === 'custom' && $isValidDashboardDate($start_date) && $isValidDashboardDate($end_date)) {
|
||||||
$date_condition = "DATE(p.created_at) BETWEEN '$start_date' AND '$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));
|
$label_period = "Desde " . date('d/m/Y', strtotime($start_date)) . " hasta " . date('d/m/Y', strtotime($end_date));
|
||||||
} else {
|
} else {
|
||||||
switch ($period) {
|
switch ($period) {
|
||||||
@ -66,9 +74,9 @@ if ($period === 'custom' && !empty($start_date) && !empty($end_date)) {
|
|||||||
$label_period = "Último Año";
|
$label_period = "Último Año";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
|
$date_condition = "DATE(p.created_at) = CURDATE()";
|
||||||
$label_period = "Últimos 7 días";
|
$label_period = "Hoy";
|
||||||
$period = '7';
|
$period = 'today';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
db/migrations/077_add_pendiente_to_tipo_paquete_enum.sql
Normal file
3
db/migrations/077_add_pendiente_to_tipo_paquete_enum.sql
Normal file
@ -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.
|
||||||
4
db/migrations/078_clean_tipo_paquete_enum.sql
Normal file
4
db/migrations/078_clean_tipo_paquete_enum.sql
Normal file
@ -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;
|
||||||
@ -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;
|
||||||
136
includes/tipo_paquete.php
Normal file
136
includes/tipo_paquete.php
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!function_exists('tipoPaqueteValidValues')) {
|
||||||
|
function tipoPaqueteValidValues(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'RUTA',
|
||||||
|
'CONTRAENTREGA',
|
||||||
|
'NO CONTESTA, VOLVER A LLAMAR',
|
||||||
|
'PENDIENTE A RETORNO',
|
||||||
|
'COMPLETADO',
|
||||||
|
'PREPARADO',
|
||||||
|
'RETORNADO',
|
||||||
|
'ANULADO',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('tipoPaquetePrimarySelectorValues')) {
|
||||||
|
function tipoPaquetePrimarySelectorValues(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'PREPARADO',
|
||||||
|
'RUTA',
|
||||||
|
'ANULADO',
|
||||||
|
'PENDIENTE A RETORNO',
|
||||||
|
'RETORNADO',
|
||||||
|
'COMPLETADO',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('normalizeTipoPaqueteValue')) {
|
||||||
|
function normalizeTipoPaqueteValue($value): ?string
|
||||||
|
{
|
||||||
|
if ($value === null || is_array($value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = (string) $value;
|
||||||
|
$value = preg_replace('/[\x{00A0}\x{200B}-\x{200D}\x{FEFF}]+/u', ' ', $value);
|
||||||
|
$value = preg_replace('/[\x00-\x1F\x7F]+/u', ' ', $value);
|
||||||
|
$value = preg_replace('/\s+/u', ' ', trim($value));
|
||||||
|
|
||||||
|
if ($value === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = function_exists('mb_strtoupper') ? mb_strtoupper($value, 'UTF-8') : strtoupper($value);
|
||||||
|
$match = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $normalized);
|
||||||
|
if ($match === false || $match === null || $match === '') {
|
||||||
|
$match = $normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
$canonicalKey = preg_replace('/[^A-Z]+/', '', strtoupper($match));
|
||||||
|
$aliases = [
|
||||||
|
'RUTA' => '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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,9 @@ if (!isset($_SESSION['user_id'])) {
|
|||||||
|
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once 'includes/contraentrega_cobertura.php';
|
require_once 'includes/contraentrega_cobertura.php';
|
||||||
|
require_once 'includes/tipo_paquete.php';
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
ensureTipoPaqueteEnumDefinition($pdo);
|
||||||
|
|
||||||
$user_id = $_SESSION['user_id'];
|
$user_id = $_SESSION['user_id'];
|
||||||
$user_role = $_SESSION['user_role'] ?? 'Asesor';
|
$user_role = $_SESSION['user_role'] ?? 'Asesor';
|
||||||
@ -320,7 +322,7 @@ include 'layout_header.php';
|
|||||||
<option value="">Seleccionar</option>
|
<option value="">Seleccionar</option>
|
||||||
<?php
|
<?php
|
||||||
$current_paquete = $pedido['tipo_paquete'] ?? '';
|
$current_paquete = $pedido['tipo_paquete'] ?? '';
|
||||||
$paquetes = ['RUTA', 'EMPAQUETADO', 'ANULADO', 'PENDIENTE A RETORNO', 'RETORNADO'];
|
$paquetes = tipoPaquetePrimarySelectorValues();
|
||||||
foreach ($paquetes as $paquete) {
|
foreach ($paquetes as $paquete) {
|
||||||
$selected = ($current_paquete == $paquete) ? 'selected' : '';
|
$selected = ($current_paquete == $paquete) ? 'selected' : '';
|
||||||
echo "<option value='{$paquete}' {$selected}>" . htmlspecialchars($paquete) . "</option>";
|
echo "<option value='{$paquete}' {$selected}>" . htmlspecialchars($paquete) . "</option>";
|
||||||
@ -333,7 +335,7 @@ include 'layout_header.php';
|
|||||||
<select class="form-select" id="estado" name="estado" required>
|
<select class="form-select" id="estado" name="estado" required>
|
||||||
<?php
|
<?php
|
||||||
$current_status = $pedido['estado'] ?? 'RUTA_CONTRAENTREGA';
|
$current_status = $pedido['estado'] ?? 'RUTA_CONTRAENTREGA';
|
||||||
$statuses = ['RUTA_CONTRAENTREGA', 'NO CONTESTO, VOLVER A LLAMAR', 'CANCELADO', 'REPROGRAMADO', 'ENTREGA EXITOSA'];
|
$statuses = ['RUTA_CONTRAENTREGA', 'PENDIENTE', 'NO CONTESTO, VOLVER A LLAMAR', 'CANCELADO', 'REPROGRAMADO', 'ENTREGA EXITOSA'];
|
||||||
foreach ($statuses as $status) {
|
foreach ($statuses as $status) {
|
||||||
$selected = ($current_status == $status) ? 'selected' : '';
|
$selected = ($current_status == $status) ? 'selected' : '';
|
||||||
echo "<option value='{$status}' {$selected}>" . htmlspecialchars($status) . "</option>";
|
echo "<option value='{$status}' {$selected}>" . htmlspecialchars($status) . "</option>";
|
||||||
|
|||||||
@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
require_once __DIR__ . '/includes/tipo_paquete.php';
|
||||||
|
|
||||||
function getStatusStyle($status) {
|
function getStatusStyle($status) {
|
||||||
$style = 'color: white;'; // Default text color
|
$style = 'color: white;'; // Default text color
|
||||||
@ -64,7 +65,8 @@ function getPaqueteStyle($paquete) {
|
|||||||
if ($paquete === 'NO CONTESTA, VOLVER A LLAMAR') return 'background-color: #fd7e14; color: white;'; // Orange
|
if ($paquete === 'NO CONTESTA, VOLVER A LLAMAR') return 'background-color: #fd7e14; color: white;'; // Orange
|
||||||
if ($paquete === 'PENDIENTE A RETORNO') return 'background-color: #dc3545; color: white;'; // Red
|
if ($paquete === 'PENDIENTE A RETORNO') return 'background-color: #dc3545; color: white;'; // Red
|
||||||
if ($paquete === 'COMPLETADO') return 'background-color: #198754; color: white;'; // Success green
|
if ($paquete === 'COMPLETADO') return 'background-color: #198754; color: white;'; // Success green
|
||||||
if ($paquete === "EMPAQUETADO") return "background-color: #20c997; color: white;"; // Empaquetado
|
if ($paquete === 'PREPARADO') return 'background-color: #20c997; color: white;'; // Preparado
|
||||||
|
if ($paquete === 'EMPAQUETADO') return 'background-color: #20c997; color: white;'; // Legacy alias
|
||||||
if ($paquete === 'RETORNADO') return 'background-color: #dc3545; color: white;'; // Same red as PENDIENTE A RETORNO
|
if ($paquete === 'RETORNADO') return 'background-color: #dc3545; color: white;'; // Same red as PENDIENTE A RETORNO
|
||||||
if ($paquete === 'ANULADO') return 'background-color: #212529; color: white;'; // Dark
|
if ($paquete === 'ANULADO') return 'background-color: #212529; color: white;'; // Dark
|
||||||
return 'background-color: #6c757d; color: white;'; // Secondary grey
|
return 'background-color: #6c757d; color: white;'; // Secondary grey
|
||||||
@ -82,6 +84,7 @@ function getFechaEntregaStyle($fecha) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
ensureTipoPaqueteEnumDefinition($pdo);
|
||||||
|
|
||||||
$user_id = $_SESSION['user_id'];
|
$user_id = $_SESSION['user_id'];
|
||||||
$user_role = $_SESSION['user_role'] ?? 'Asesor';
|
$user_role = $_SESSION['user_role'] ?? 'Asesor';
|
||||||
@ -506,10 +509,38 @@ function getPaqueteStyleJS(paquete) {
|
|||||||
if (paquete === 'PENDIENTE A RETORNO') return 'background-color: #dc3545; color: white;';
|
if (paquete === 'PENDIENTE A RETORNO') return 'background-color: #dc3545; color: white;';
|
||||||
if (paquete === 'RETORNADO') return 'background-color: #dc3545; color: white;';
|
if (paquete === 'RETORNADO') return 'background-color: #dc3545; color: white;';
|
||||||
if (paquete === 'COMPLETADO') return 'background-color: #198754; color: white;';
|
if (paquete === 'COMPLETADO') return 'background-color: #198754; color: white;';
|
||||||
if (paquete === "EMPAQUETADO") return "background-color: #20c997; color: white;";
|
if (paquete === 'PREPARADO') return 'background-color: #20c997; color: white;';
|
||||||
|
if (paquete === 'EMPAQUETADO') return 'background-color: #20c997; color: white;';
|
||||||
return 'background-color: #6c757d; color: white;';
|
return 'background-color: #6c757d; color: white;';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeTipoPaqueteValueClient(value) {
|
||||||
|
if (!value) return '';
|
||||||
|
|
||||||
|
const cleaned = String(value)
|
||||||
|
.replace(/[\u00A0\u200B-\u200D\uFEFF]/g, ' ')
|
||||||
|
.replace(/[\x00-\x1F\x7F]/g, ' ')
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.toUpperCase();
|
||||||
|
|
||||||
|
const compact = cleaned.replace(/[^A-Z]+/g, '');
|
||||||
|
const aliases = {
|
||||||
|
RUTA: 'RUTA',
|
||||||
|
CONTRAENTREGA: 'CONTRAENTREGA',
|
||||||
|
NOCONTESTAVOLVERALLAMAR: 'NO CONTESTA, VOLVER A LLAMAR',
|
||||||
|
PENDIENTEARETORNO: 'PENDIENTE A RETORNO',
|
||||||
|
COMPLETADO: 'COMPLETADO',
|
||||||
|
EMPAQUETADO: 'PREPARADO',
|
||||||
|
PREPARADO: 'PREPARADO',
|
||||||
|
EMPAQUETARDO: 'PREPARADO',
|
||||||
|
RETORNADO: 'RETORNADO',
|
||||||
|
ANULADO: 'ANULADO'
|
||||||
|
};
|
||||||
|
|
||||||
|
return aliases[compact] || cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
function getStatusStyleJS(status) {
|
function getStatusStyleJS(status) {
|
||||||
let bgColor = '#0dcaf0';
|
let bgColor = '#0dcaf0';
|
||||||
let style = 'color: white;';
|
let style = 'color: white;';
|
||||||
@ -576,15 +607,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const select = document.createElement('select');
|
const select = document.createElement('select');
|
||||||
select.className = 'form-select form-select-sm';
|
select.className = 'form-select form-select-sm';
|
||||||
|
|
||||||
const options = [
|
const options = <?php echo json_encode(array_merge(
|
||||||
{val: '', text: 'Seleccionar'},
|
[['val' => '', 'text' => 'Seleccionar']],
|
||||||
{val: 'RUTA', text: 'RUTA'},
|
array_map(static function ($paquete) {
|
||||||
{val: 'ANULADO', text: 'ANULADO'},
|
return ['val' => $paquete, 'text' => $paquete];
|
||||||
{val: 'PENDIENTE A RETORNO', text: 'PENDIENTE A RETORNO'},
|
}, tipoPaquetePrimarySelectorValues())
|
||||||
{val: 'RETORNADO', text: 'RETORNADO'},
|
), JSON_UNESCAPED_UNICODE); ?>;
|
||||||
{val: "EMPAQUETADO", text: "EMPAQUETADO"},
|
|
||||||
{val: 'COMPLETADO', text: 'COMPLETADO'}
|
|
||||||
];
|
|
||||||
|
|
||||||
options.forEach(opt => {
|
options.forEach(opt => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
@ -602,7 +630,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
select.focus();
|
select.focus();
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
const newVal = select.value;
|
const newVal = normalizeTipoPaqueteValueClient(select.value);
|
||||||
|
|
||||||
// Optimistic update
|
// Optimistic update
|
||||||
cell.dataset.value = newVal;
|
cell.dataset.value = newVal;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ if (!isset($_SESSION['user_id'])) {
|
|||||||
|
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once __DIR__ . '/includes/contraentrega_cobertura.php';
|
require_once __DIR__ . '/includes/contraentrega_cobertura.php';
|
||||||
|
require_once __DIR__ . '/includes/tipo_paquete.php';
|
||||||
|
|
||||||
function redirectPedidoContraentregaWithError(string $message, $id = null, bool $embed = false): void
|
function redirectPedidoContraentregaWithError(string $message, $id = null, bool $embed = false): void
|
||||||
{
|
{
|
||||||
@ -46,6 +47,7 @@ function normalizeContraentregaCoordinates(string $value): ?string
|
|||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
ensureTipoPaqueteEnumDefinition($pdo);
|
||||||
|
|
||||||
$id = $_POST['id'] ?? null;
|
$id = $_POST['id'] ?? null;
|
||||||
$embed_mode = !empty($_POST['embed']) && $_POST['embed'] === '1';
|
$embed_mode = !empty($_POST['embed']) && $_POST['embed'] === '1';
|
||||||
@ -115,11 +117,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
// Normalizar Paquete: el selector "Seleccionar" llega como cadena vacía,
|
// Normalizar Paquete: el selector "Seleccionar" llega como cadena vacía,
|
||||||
// pero la columna ENUM permite NULL y no permite ''.
|
// pero la columna ENUM permite NULL y no permite ''.
|
||||||
$tipo_paquete = isset($_POST['tipo_paquete']) ? trim((string)$_POST['tipo_paquete']) : null;
|
$tipo_paquete = normalizeTipoPaqueteValue($_POST['tipo_paquete'] ?? null);
|
||||||
if ($tipo_paquete === '') {
|
$tipos_paquete_validos = tipoPaqueteValidValues();
|
||||||
$tipo_paquete = null;
|
|
||||||
}
|
|
||||||
$tipos_paquete_validos = ['RUTA', 'CONTRAENTREGA', 'NO CONTESTA, VOLVER A LLAMAR', 'PENDIENTE A RETORNO', 'COMPLETADO', 'EMPAQUETADO', 'RETORNADO', 'ANULADO'];
|
|
||||||
if ($tipo_paquete !== null && !in_array($tipo_paquete, $tipos_paquete_validos, true)) {
|
if ($tipo_paquete !== null && !in_array($tipo_paquete, $tipos_paquete_validos, true)) {
|
||||||
redirectPedidoContraentregaWithError('El paquete seleccionado no es válido. Seleccione una opción de la lista.', $id, $embed_mode);
|
redirectPedidoContraentregaWithError('El paquete seleccionado no es válido. Seleccione una opción de la lista.', $id, $embed_mode);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,60 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
require_once __DIR__ . '/includes/tipo_paquete.php';
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if (!function_exists('normalizeTipoPaqueteValue')) {
|
||||||
|
function normalizeTipoPaqueteValue($value)
|
||||||
|
{
|
||||||
|
if ($value === null || is_array($value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = (string) $value;
|
||||||
|
$value = preg_replace('/[\x{00A0}\x{200B}-\x{200D}\x{FEFF}]+/u', ' ', $value);
|
||||||
|
$value = preg_replace('/[\x00-\x1F\x7F]+/u', ' ', $value);
|
||||||
|
$value = preg_replace('/\s+/u', ' ', trim($value));
|
||||||
|
|
||||||
|
if ($value === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = function_exists('mb_strtoupper') ? mb_strtoupper($value, 'UTF-8') : strtoupper($value);
|
||||||
|
$match = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $normalized);
|
||||||
|
if ($match === false || $match === null || $match === '') {
|
||||||
|
$match = $normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
$canonicalKey = preg_replace('/[^A-Z]+/', '', strtoupper($match));
|
||||||
|
$aliases = [
|
||||||
|
'RUTA' => 'RUTA',
|
||||||
|
'CONTRAENTREGA' => 'CONTRAENTREGA',
|
||||||
|
'NOCONTESTAVOLVERALLAMAR' => 'NO CONTESTA, VOLVER A LLAMAR',
|
||||||
|
'PENDIENTEARETORNO' => 'PENDIENTE A RETORNO',
|
||||||
|
'COMPLETADO' => 'COMPLETADO',
|
||||||
|
'EMPAQUETADO' => 'PREPARADO',
|
||||||
|
'PREPARADO' => 'PREPARADO',
|
||||||
|
'EMPAQUETARDO' => 'PREPARADO',
|
||||||
|
'RETORNADO' => 'RETORNADO',
|
||||||
|
'ANULADO' => 'ANULADO',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $aliases[$canonicalKey] ?? $normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($_SESSION['user_id'])) {
|
if (!isset($_SESSION['user_id'])) {
|
||||||
echo json_encode(['success' => false, 'message' => 'No autorizado']);
|
echo json_encode(['success' => false, 'message' => 'No autorizado']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$pedido_id = $_POST['pedido_id'] ?? null;
|
$pedido_id_raw = $_POST['pedido_id'] ?? null;
|
||||||
$tipo_paquete = $_POST['tipo_paquete'] ?? null;
|
$pedido_id = (is_numeric($pedido_id_raw) && (int)$pedido_id_raw > 0) ? (int)$pedido_id_raw : null;
|
||||||
|
|
||||||
|
$tipo_paquete = normalizeTipoPaqueteValue($_POST['tipo_paquete'] ?? null);
|
||||||
|
|
||||||
if (!$pedido_id) {
|
if (!$pedido_id) {
|
||||||
echo json_encode(['success' => false, 'message' => 'ID de pedido faltante']);
|
echo json_encode(['success' => false, 'message' => 'ID de pedido faltante']);
|
||||||
@ -20,14 +63,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
ensureTipoPaqueteEnumDefinition($pdo);
|
||||||
|
|
||||||
if (empty($tipo_paquete)) {
|
if ($tipo_paquete === null) {
|
||||||
// Allow clearing the selection
|
// Allow clearing the selection
|
||||||
$stmt = $pdo->prepare("UPDATE pedidos SET tipo_paquete = NULL WHERE id = ?");
|
$stmt = $pdo->prepare("UPDATE pedidos SET tipo_paquete = NULL WHERE id = ?");
|
||||||
$result = $stmt->execute([$pedido_id]);
|
$result = $stmt->execute([$pedido_id]);
|
||||||
} else {
|
} else {
|
||||||
$valid_types = ['RUTA', 'ANULADO', 'PENDIENTE A RETORNO', 'RETORNADO', 'CONTRAENTREGA', 'NO CONTESTA, VOLVER A LLAMAR', 'COMPLETADO', 'EMPAQUETADO'];
|
$valid_types = tipoPaqueteValidValues();
|
||||||
if (!in_array($tipo_paquete, $valid_types)) {
|
if (!in_array($tipo_paquete, $valid_types, true)) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Tipo inválido']);
|
echo json_encode(['success' => false, 'message' => 'Tipo inválido']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user