prepare("SHOW COLUMNS FROM `{$table}` LIKE ?"); $stmt->execute([$column]); if (!$stmt->fetch()) { $pdo->exec("ALTER TABLE `{$table}` ADD COLUMN `{$column}` {$definition}"); } $cache[$key] = true; } function cc_test_ensure_tracking_table(PDO $pdo): void { static $checked = false; if ($checked) { return; } $pdo->exec("CREATE TABLE IF NOT EXISTS `callcenter_test_tracking` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `source_key` CHAR(40) NOT NULL, `estado` VARCHAR(40) NOT NULL DEFAULT 'POR LLAMAR', `nota_seguimiento` TEXT NULL, `user_id` INT NULL, `direccion` TEXT NULL, `referencia` TEXT NULL, `sede` VARCHAR(120) NULL, `ciudad` VARCHAR(120) NULL, `distrito` VARCHAR(120) NULL, `dni` VARCHAR(40) NULL, `observaciones` TEXT NULL, `proxima_llamada_at` DATETIME NULL, `fecha_entrega_programada` DATE NULL, `numero_cuenta_enviado_at` DATETIME NULL, `ultima_gestion_at` DATETIME NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uniq_callcenter_test_tracking_source_key` (`source_key`), KEY `idx_callcenter_test_tracking_estado` (`estado`), KEY `idx_callcenter_test_tracking_proxima` (`proxima_llamada_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'direccion', 'TEXT NULL AFTER `user_id`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'referencia', 'TEXT NULL AFTER `direccion`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'sede', 'VARCHAR(120) NULL AFTER `referencia`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'ciudad', 'VARCHAR(120) NULL AFTER `sede`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'distrito', 'VARCHAR(120) NULL AFTER `ciudad`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'dni', 'VARCHAR(40) NULL AFTER `distrito`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'observaciones', 'TEXT NULL AFTER `dni`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'proxima_llamada_at', 'DATETIME NULL AFTER `observaciones`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'fecha_entrega_programada', 'DATE NULL AFTER `proxima_llamada_at`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'numero_cuenta_enviado_at', 'DATETIME NULL AFTER `fecha_entrega_programada`'); cc_test_ensure_column($pdo, 'callcenter_test_tracking', 'ultima_gestion_at', 'DATETIME NULL AFTER `numero_cuenta_enviado_at`'); $checked = true; } function cc_test_ensure_historial_llamadas_table(PDO $pdo): void { static $checked = false; if ($checked) { return; } $pdo->exec("CREATE TABLE IF NOT EXISTS `historial_llamadas` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `pedido_id` VARCHAR(80) NOT NULL, `asesor_id` INT UNSIGNED NOT NULL, `resultado` VARCHAR(120) NOT NULL, `observacion` TEXT NULL, `fecha_llamada` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX `idx_historial_llamadas_pedido` (`pedido_id`), INDEX `idx_historial_llamadas_asesor` (`asesor_id`), INDEX `idx_historial_llamadas_fecha` (`fecha_llamada`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); $checked = true; } function cc_test_normalize_state(string $estado): string { $estado = trim($estado); return match ($estado) { 'CONFIRMADO CONTRAENTREGA FECHA', 'CONFIRMADO FECHA', 'CONTRAENTREGA CONFIRMADO' => 'CONFIRMADO CONTRAENTREGA', 'ENVIO REPETIDO' => 'REPETIDO', default => $estado, }; } function cc_test_valid_states(): array { return [ 'POR LLAMAR', 'DEVOLVER LLAMADA', 'OBSERVADO', 'SE ENVIO NUMERO DE CUENTA', 'CONFIRMADO CONTRAENTREGA', 'CONFIRMADO ENVIO', 'CANCELADO', 'REPETIDO', ]; } function cc_test_open_states(): array { return ['POR LLAMAR', 'DEVOLVER LLAMADA', 'OBSERVADO', 'SE ENVIO NUMERO DE CUENTA']; } function cc_test_confirmed_states(): array { return ['CONFIRMADO CONTRAENTREGA', 'CONFIRMADO ENVIO']; } function cc_test_closed_states(): array { return ['CANCELADO', 'REPETIDO']; } function cc_test_requires_delivery_date(string $estado): bool { return cc_test_normalize_state($estado) === 'CONFIRMADO CONTRAENTREGA'; } function cc_test_account_followup_semaforo(?string $value): ?array { $date = cc_test_parse_datetime($value); if (!$date) { return null; } $now = new DateTimeImmutable('now'); $days = (int) $date->diff($now)->format('%a'); if ($date > $now) { $days = 0; } if ($days <= 1) { return [ 'class' => 'bg-success-subtle text-success-emphasis', 'label' => 'Verde', 'range' => '0–1 días', 'days' => $days, 'description' => 'Aún está en ventana de seguimiento amable.', ]; } if ($days === 2) { return [ 'class' => 'bg-warning-subtle text-warning-emphasis', 'label' => 'Amarillo', 'range' => '2 días', 'days' => $days, 'description' => 'Ya conviene insistir con llamada o WhatsApp.', ]; } return [ 'class' => 'bg-danger-subtle text-danger-emphasis', 'label' => 'Rojo', 'range' => '3+ días', 'days' => $days, 'description' => 'Necesita seguimiento urgente para no perder el pedido.', ]; } function cc_test_state_label(string $estado): string { return match (cc_test_normalize_state($estado)) { 'SE ENVIO NUMERO DE CUENTA' => 'SE ENVIÓ NÚMERO DE CUENTA', 'CONFIRMADO CONTRAENTREGA' => 'CONFIRMADO CONTRAENTREGA', 'CONFIRMADO ENVIO' => 'CONFIRMADO ENVIO', 'REPETIDO' => 'REPETIDO', default => $estado, }; } function cc_test_table_exists(PDO $pdo, string $tableName): bool { static $cache = []; if (array_key_exists($tableName, $cache)) { return $cache[$tableName]; } $stmt = $pdo->prepare('SHOW TABLES LIKE ?'); $stmt->execute([$tableName]); $cache[$tableName] = (bool) $stmt->fetchColumn(); return $cache[$tableName]; } function cc_test_fetch_historial(PDO $pdo, string $pedidoId): array { if (cc_test_table_exists($pdo, 'usuarios')) { $stmt = $pdo->prepare("SELECT h.*, u.nombre as asesor FROM historial_llamadas h LEFT JOIN usuarios u ON h.asesor_id = u.id WHERE h.pedido_id = ? ORDER BY h.fecha_llamada DESC"); $stmt->execute([$pedidoId]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } $stmt = $pdo->prepare("SELECT h.*, NULL as asesor FROM historial_llamadas h WHERE h.pedido_id = ? ORDER BY h.fecha_llamada DESC"); $stmt->execute([$pedidoId]); return $stmt->fetchAll(PDO::FETCH_ASSOC); }