using EFCDesk.Classes; using EFCDesk.Entidades; using Microsoft.VisualBasic.ApplicationServices; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Data; using System.Data.SQLite; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Drawing; using System.Globalization; using System.IO.Compression; using System.Linq; using System.Net; using System.Reflection; using System.Reflection.Emit; using System.Security.Policy; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Windows.Documents; using System.Windows.Forms; using System.Xml.Linq; using static System.Collections.Specialized.BitVector32; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Header; using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; using MethodInvoker = System.Windows.Forms.MethodInvoker; namespace EFCDesk.Forms { public partial class FormMain : Form { private sealed class ListViewTicksDescComparer : System.Collections.IComparer { private readonly int _col; public ListViewTicksDescComparer(int col) => _col = col; public int Compare(object? x, object? y) { // var a = x as ListViewItem; var b = y as ListViewItem; if (a == null || b == null) return 0; long ta = 0, tb = 0; long.TryParse(a.SubItems[_col].Text, out ta); long.TryParse(b.SubItems[_col].Text, out tb); // Descendente: primero el más reciente int cmp = tb.CompareTo(ta); if (cmp != 0) return cmp; // Desempate por nombre return string.Compare(a.Text, b.Text, StringComparison.OrdinalIgnoreCase); } } private bool _barridoEnEjecucion = false; private BackgroundWorker _backgroundWorker; private static SQLiteHelper sqliteHelper = new SQLiteHelper(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "historico.db")); private ConfiguracionExpediente config = ConfiguracionExpediente.ObtenerDesdeBaseDeDatos(sqliteHelper); private ConfiguracionJSON configJson = ConfiguracionJSON.LoadFromJson(); public bool accederAConfiguracion = true; private string DominioEFC = ""; //private string ApiPostDocuments = @"/api/v1/record/documents/"; //private string ApiGetPedimento = @"/api/v1/customs/pedimentos/?pedimento_app="; private string ApiPostDocuments = Helpers.ObtenerEndpointDocumentos(); private string ApiGetPedimento = Helpers.ObtenerEndpointPedimentos(); private ProcessLogger logger = new ProcessLogger(); private readonly Dictionary _mapaItems = new(); private readonly MonitorCarpetas _monitor; private bool PrimerInicioDeBarrido = true; private List _todosExpedientes = new(); public FormMain(MonitorCarpetas monitor) { InitializeComponent(); Rectangle workingArea = Screen.GetWorkingArea(this); this.Location = new Point(workingArea.Right - (Size.Width), workingArea.Bottom - (Size.Height)); _monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); // Suscribirse al evento de datos actualizados //_monitor.DatosActualizados += Monitor_DatosActualizados; // Suscripción al evento _monitor.DatosActualizados += Monitor_ArchivoAgregado; } // Este método se ejecuta cuando MonitorCarpetas dispara el evento private void Monitor_DatosActualizados(object? sender, EventArgs e) { // Como el evento puede venir de otro hilo, usamos Invoke para actualizar la UI if (InvokeRequired) { Invoke(new Action(ActualizarListaArchivos)); } else { ActualizarListaArchivos(); } } private async void Monitor_ArchivoAgregado(object? sender, DatosActualizadosEventArgs e) { //// Invocar en el hilo de UI //if (InvokeRequired) //{ // Invoke(new Action(() => ActualizarListView(e.CarpetaRaiz))); //} //else //{ // ActualizarListView(e.CarpetaRaiz); //} await ActualizarListViewConExpedienteAsync(e.CarpetaRaiz); } //private void ActualizarListView(string carpetaRaiz) //{ // listViewExpedientes.BeginUpdate(); // // Opcional: obtener info desde SQLite // var expediente = sqliteHelper.ObtenerCarpetas(carpetaRaiz); // if (expediente == null || expediente.Count == 0) return; // string clave = expediente[0].ArchivoZip; // // Si ya existe, quitarlo del ListView // if (_mapaItems.TryGetValue(clave, out var existente)) // { // listViewExpedientes.Items.Remove(existente); // _mapaItems.Remove(clave); // } // // ticks para ordenar (más alto = más reciente) // string ticks = DateTime.Now.Ticks.ToString(); // // Crear el nuevo item // var itemNuevo = new ListViewItem(expediente[0].ArchivoZip, 0); // itemNuevo.SubItems.Add(expediente[0].Estado + ": " + DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")); // // Guardamos la ruta en Tag para futuras referencias // itemNuevo.Tag = clave; // // Guardar en el diccionario // _mapaItems[clave] = itemNuevo; // // Insertar siempre en la primera posición // listViewExpedientes.Items.Insert(0, itemNuevo); // // Asegurar que quede visible el primero // listViewExpedientes.EnsureVisible(0); // // Resaltar temporalmente el item nuevo // //itemNuevo.BackColor = Color.Yellow; // listViewExpedientes.Columns[2].Width = 200; // labelTotalExpedientes.Visible = true; // // Actualizar total // labelTotalExpedientes.Text = "Total de expedientes: " + listViewExpedientes.Items.Count.ToString(); // listViewExpedientes.EndUpdate(); //} // Método que refresca los datos en la vista private void ActualizarListaArchivos() { try { LlenarListViewConExpedientes(); } catch (Exception ex) { Console.WriteLine($"Error actualizando UI: {ex.Message}"); } } private async Task ActualizarListViewConExpedienteAsync(string carpetaRaiz) { // 🔹 Ejecutar consulta en segundo plano var expedientes = await Task.Run(() => sqliteHelper.ObtenerCarpetas(carpetaRaiz)); if (expedientes == null || expedientes.Count == 0) return; // 🔹 Actualizar UI (siempre en el hilo principal) if (listViewExpedientes.InvokeRequired) { listViewExpedientes.Invoke(new Action(() => InsertarExpedienteEnListView(expedientes) )); } else { InsertarExpedienteEnListView(expedientes); } //await CargarExpedientesAsync(expedientes); } private void InsertarExpedienteEnListView(List<(string ArchivoZip, string Estado, string FechaCreacion)> Expedientes) { listViewExpedientes.BeginUpdate(); if (Expedientes == null || Expedientes.Count == 0) return; foreach (var expediente in Expedientes) { string clave = expediente.ArchivoZip; // Si ya existe, quitarlo del ListView if (_mapaItems.TryGetValue(clave, out var existente)) { var item = listViewExpedientes.Items .Cast() .FirstOrDefault(i => i.Tag as string == clave); if (item != null) { item.SubItems[1].Text = expediente.Estado; } //listViewExpedientes.Items.Remove(existente); //_mapaItems.Remove(clave); continue; } // ticks para ordenar (más alto = más reciente) //string ticks = DateTime.Now.Ticks.ToString(); DateTime fecha = DateTime.ParseExact(expediente.FechaCreacion, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); string ticks = fecha.Ticks.ToString(); // Crear el nuevo item var itemNuevo = new ListViewItem(expediente.ArchivoZip.Replace(".zip", ""), 0); itemNuevo.SubItems.Add(expediente.Estado); itemNuevo.SubItems.Add(expediente.FechaCreacion); itemNuevo.SubItems.Add(ticks); // SubItem oculto: ticks (para ordenar) // Guardamos la ruta en Tag para futuras referencias itemNuevo.Tag = clave; // Guardar en el diccionario _mapaItems[clave] = itemNuevo; //// Insertar siempre en la primera posición //listViewExpedientes.Items.Insert(0, itemNuevo); // Insertar en la lista listViewExpedientes.Items.Add(itemNuevo); //// Asegurar que quede visible el primero ////listViewExpedientes.EnsureVisible(0); // Resaltar temporalmente el item nuevo //itemNuevo.BackColor = Color.Yellow; } // Forzar orden listViewExpedientes.Sort(); int limite = 1000; // Mantener solo los últimos 1000 if (listViewExpedientes.Items.Count > limite) { for (int i = listViewExpedientes.Items.Count - 1; i >= limite; i--) { var claveViejo = listViewExpedientes.Items[i].Tag as string; if (claveViejo != null) { _mapaItems.Remove(claveViejo); // también lo sacamos del diccionario } listViewExpedientes.Items.RemoveAt(i); } } listViewExpedientes.Columns[2].Width = 200; labelTotalExpedientes.Visible = true; // Actualizar total labelTotalExpedientes.Text = "Total de expedientes: " + listViewExpedientes.Items.Count.ToString(); listViewExpedientes.EndUpdate(); } //private void StartBackgroundWorker() //{ // if (!_backgroundWorker.IsBusy) // { // _backgroundWorker.RunWorkerAsync(); // //MessageBox.Show("Monitoreo iniciado en segundo plano."); // } //} //public void RealizarEscaneoInicialYProcesar() //{ // if (string.IsNullOrWhiteSpace(config.FolderParaGenerarExpediente) || !Directory.Exists(config.FolderParaGenerarExpediente)) // { // Console.WriteLine("La ruta especificada no es válida."); // return; // } // accederAConfiguracion = false; // using (var connection = sqliteHelper.GetConnection()) // { // connection.Open(); // // Verificar si hay registros en la tabla ArchivosProcesados // string checkQuery = "SELECT COUNT(1) FROM ArchivosProcesados;"; // int registrosExistentes; // using (var command = new SQLiteCommand(checkQuery, connection)) // { // registrosExistentes = Convert.ToInt32(command.ExecuteScalar()); // } // // Si hay registros, no realizar el escaneo inicial // if (registrosExistentes > 0) // { // Console.WriteLine("Ya existen registros en la tabla ArchivosProcesados. Escaneo inicial no necesario."); // return; // } // else // { // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Iniciando escaneo...")); // } // using (var transaction = connection.BeginTransaction()) // { // try // { // var carpetasClientes = Directory.GetDirectories(config.FolderParaGenerarExpediente); // if (config.UsarEstructuraPedimentosWinsaai) // { // foreach (var carpetaCliente in carpetasClientes) // { // string nombreCliente = Path.GetFileName(carpetaCliente); // // Obtener todas las carpetas de pedimentos dentro de la carpeta del cliente // var carpetasPedimentos = Directory.GetDirectories(carpetaCliente); // foreach (var carpetaPedimento in carpetasPedimentos) // { // string nombreCarpetaPedimento = Path.GetFileName(carpetaPedimento); // // Crear un archivo ZIP para la carpeta del pedimento // string zipPath = Path.Combine(carpetaCliente, $"{nombreCarpetaPedimento}.zip"); // if (File.Exists(zipPath)) // { // File.Delete(zipPath); // } // ZipFile.CreateFromDirectory(carpetaPedimento, zipPath); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Comprimiendo archivo: " + carpetaPedimento)); // // Subir el archivo ZIP al FTP // SubirArchivoFTP(zipPath); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Subiendo archivo al servidor FTP: " + carpetaPedimento)); // RegistrarArchivoEnAPI(zipPath); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Registrando archivo en API: " + carpetaPedimento)); // // Obtener todos los archivos dentro de la carpeta de pedimento // var archivos = Directory.GetFiles(carpetaPedimento); // foreach (var archivo in archivos) // { // string nombreArchivo = Path.GetFileName(archivo); // // Insertar ArchivosProcesados // string insertArchivoProcesadoQuery = @" // INSERT OR IGNORE INTO ArchivosProcesados (NombreArchivo, RutaArchivo, Estado, FolderExpediente, ArchivoZip) // VALUES (@NombreArchivo, @RutaArchivo, 'Procesado',@FolderExpediente,@ArchivoZip);"; // using (var command = new SQLiteCommand(insertArchivoProcesadoQuery, connection)) // { // command.Parameters.AddWithValue("@NombreArchivo", nombreArchivo); // command.Parameters.AddWithValue("@RutaArchivo", archivo); // command.Parameters.AddWithValue("@FolderExpediente", carpetaCliente); // command.Parameters.AddWithValue("@ArchivoZip", $"{nombreCarpetaPedimento}.zip"); // command.ExecuteNonQuery(); // } // } // File.Delete(zipPath); // MoverArchivosAFolderDeRespaldo(carpetaPedimento); // LlenarListViewEscaneoInicial($"{nombreCarpetaPedimento}.zip"); // } // } // } // else // { // foreach (var carpetaCliente in carpetasClientes) // { // string nombreCarpetaPedimento = Path.GetFileName(carpetaCliente); // // Crear un archivo ZIP para la carpeta del pedimento // string zipPath = Path.Combine(Path.GetDirectoryName(carpetaCliente), $"{nombreCarpetaPedimento}.zip"); // if (File.Exists(zipPath)) // { // File.Delete(zipPath); // } // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Comprimiendo archivo: " + nombreCarpetaPedimento)); // ZipFile.CreateFromDirectory(carpetaCliente, zipPath); // // Subir el archivo ZIP al FTP // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Subiendo archivo al servidor FTP: " + nombreCarpetaPedimento)); // SubirArchivoFTP(zipPath); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Registrando archivo en API: " + nombreCarpetaPedimento)); // RegistrarArchivoEnAPI(zipPath); // // Obtener todas las carpetas de pedimentos dentro de la carpeta del cliente // var archivos = Directory.GetFiles(carpetaCliente); // foreach (var archivo in archivos) // { // string nombreArchivo = Path.GetFileName(archivo); // // Insertar ArchivosProcesados // string insertArchivoProcesadoQuery = @" // INSERT OR IGNORE INTO ArchivosProcesados (NombreArchivo, RutaArchivo, Estado, FolderExpediente, ArchivoZip) // VALUES (@NombreArchivo, @RutaArchivo, 'Procesado',@FolderExpediente,@ArchivoZip);"; // using (var command = new SQLiteCommand(insertArchivoProcesadoQuery, connection)) // { // command.Parameters.AddWithValue("@NombreArchivo", nombreArchivo); // command.Parameters.AddWithValue("@RutaArchivo", archivo); // command.Parameters.AddWithValue("@FolderExpediente", carpetaCliente); // command.Parameters.AddWithValue("@ArchivoZip", $"{nombreCarpetaPedimento}.zip"); // command.ExecuteNonQuery(); // } // } // File.Delete(zipPath); // MoverArchivosAFolderDeRespaldo(nombreCarpetaPedimento); // LlenarListViewEscaneoInicial($"{nombreCarpetaPedimento}.zip"); // } // } // transaction.Commit(); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Escaneo inicial y procesamiento completados con éxito.")); // } // catch (Exception ex) // { // transaction.Rollback(); // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); // //Console.WriteLine($"Error durante el escaneo inicial: {ex.Message}"); // } // } // } //} //public async Task RealizarEscaneoInicialYProcesar2() //{ // if (string.IsNullOrWhiteSpace(config.FolderParaGenerarExpediente) || !Directory.Exists(config.FolderParaGenerarExpediente)) // { // Console.WriteLine("La ruta especificada no es válida."); // return; // } // if (string.IsNullOrWhiteSpace(this.DominioEFC)) // { // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Dominio no configurado...")); // return; // } // if (string.IsNullOrEmpty(this.DominioEFC)) // { // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Dominio no configurado...")); // return; // } // accederAConfiguracion = false; // using (var connection = sqliteHelper.GetConnection()) // { // connection.Open(); // // Verificar si hay registros en la tabla ArchivosProcesados // string checkQuery = "SELECT COUNT(1) FROM ArchivosProcesados;"; // int registrosExistentes; // using (var command = new SQLiteCommand(checkQuery, connection)) // { // registrosExistentes = Convert.ToInt32(command.ExecuteScalar()); // } // // Si hay registros, no realizar el escaneo inicial // if (registrosExistentes > 0) // { // Console.WriteLine("Ya existen registros en la tabla ArchivosProcesados. Escaneo inicial no necesario."); // return; // } // else // { // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Iniciando escaneo...")); // } // using (var transaction = connection.BeginTransaction()) // { // try // { // var carpetasClientes = Directory.GetDirectories(config.FolderParaGenerarExpediente); // if (config.UsarEstructuraPedimentosWinsaai) // { // foreach (var carpetaCliente in carpetasClientes) // { // string nombreCliente = Path.GetFileName(carpetaCliente); // // Obtener todas las carpetas de pedimentos dentro de la carpeta del cliente // var carpetasPedimentos = Directory.GetDirectories(carpetaCliente); // foreach (var carpetaPedimento in carpetasPedimentos) // { // string nombreCarpetaPedimento = Path.GetFileName(carpetaPedimento); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Revisando formato de número de pedimento:" + carpetaPedimento)); // string pattern = @"^\d{2}-\d{2}-\d{4}-\d{7}$"; // bool esValido = System.Text.RegularExpressions.Regex.IsMatch(nombreCarpetaPedimento, pattern); // if (!esValido) // { // continue; // } // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Subiendo archivos a plataforma EFC de:" + carpetaPedimento)); // // Obtener todos los archivos dentro de la carpeta de pedimento // var archivos = Directory.GetFiles(carpetaPedimento); // bool respuesa = false; // foreach (var archivo in archivos) // { // if (Helpers.ObtenerTamanoEnBytes(archivo) <= 0) // { // continue; // } // string nombreArchivo = Path.GetFileName(archivo); // respuesa = await SubirArchivoApiAsync(nombreCarpetaPedimento, archivo); // if (respuesa) // { // // Insertar ArchivosProcesados // string insertArchivoProcesadoQuery = @" // INSERT OR IGNORE INTO ArchivosProcesados (NombreArchivo, RutaArchivo, Estado, FolderExpediente, ArchivoZip) // VALUES (@NombreArchivo, @RutaArchivo, 'Procesado',@FolderExpediente,@ArchivoZip);"; // using (var command = new SQLiteCommand(insertArchivoProcesadoQuery, connection)) // { // command.Parameters.AddWithValue("@NombreArchivo", nombreArchivo); // command.Parameters.AddWithValue("@RutaArchivo", archivo); // command.Parameters.AddWithValue("@FolderExpediente", carpetaCliente); // command.Parameters.AddWithValue("@ArchivoZip", $"{nombreCarpetaPedimento}"); // command.ExecuteNonQuery(); // } // } // } // if(respuesa) MoverArchivosAFolderDeRespaldo(carpetaPedimento); // LlenarListViewEscaneoInicial($"{nombreCarpetaPedimento}"); // } // } // } // else // { // foreach (var carpetaCliente in carpetasClientes) // { // string nombreCarpetaPedimento = Path.GetFileName(carpetaCliente); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Revisando formato de número de pedimento:" + nombreCarpetaPedimento)); // string pattern = @"^\d{2}-\d{2}-\d{4}-\d{7}$"; // bool esValido = System.Text.RegularExpressions.Regex.IsMatch(nombreCarpetaPedimento, pattern); // if (!esValido) // { // continue; // } // // Subir el archivo ZIP al FTP // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Subiendo archivos a plataforma EFC de: " + nombreCarpetaPedimento)); // // Obtener todas las carpetas de pedimentos dentro de la carpeta del cliente // var archivos = Directory.GetFiles(carpetaCliente); // bool respuesa = false; // foreach (var archivo in archivos) // { // if (Helpers.ObtenerTamanoEnBytes(archivo) <= 0) // { // continue; // } // string nombreArchivo = Path.GetFileName(archivo); // respuesa = await SubirArchivoApiAsync(nombreCarpetaPedimento,archivo); // if (respuesa) // { // // Insertar ArchivosProcesados // string insertArchivoProcesadoQuery = @" // INSERT OR IGNORE INTO ArchivosProcesados (NombreArchivo, RutaArchivo, Estado, FolderExpediente, ArchivoZip) // VALUES (@NombreArchivo, @RutaArchivo, 'Procesado',@FolderExpediente,@ArchivoZip);"; // using (var command = new SQLiteCommand(insertArchivoProcesadoQuery, connection)) // { // command.Parameters.AddWithValue("@NombreArchivo", nombreArchivo); // command.Parameters.AddWithValue("@RutaArchivo", archivo); // command.Parameters.AddWithValue("@FolderExpediente", carpetaCliente); // command.Parameters.AddWithValue("@ArchivoZip", $"{nombreCarpetaPedimento}"); // command.ExecuteNonQuery(); // } // } // } // if (respuesa) MoverArchivosAFolderDeRespaldo(nombreCarpetaPedimento); // LlenarListViewEscaneoInicial($"{nombreCarpetaPedimento}"); // } // } // transaction.Commit(); // labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Escaneo inicial y procesamiento completados con éxito.")); // } // catch (Exception ex) // { // transaction.Rollback(); // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); // //Console.WriteLine($"Error durante el escaneo inicial: {ex.Message}"); // } // } // } //} bool EsCarpeta(string path) { return (File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory; } private void SubirArchivoFTP(string filePath) { var configJSON = ConfiguracionJSON.LoadFromJson(); string folderRemoto = "ftp://" + config.ServidorFTP + "/" + configJSON.idUsuarioExp; string respuesta = ""; try { if (config.PuertoFTP != 21) { folderRemoto = "ftp://" + config.ServidorFTP + ":" + config.PuertoFTP + "/" + configJSON.idUsuarioExp; } } catch (Exception ex) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); } try { if (configJSON.ProxyFTPNinguno) { try { string usuario = configJSON.UsuarioProxyFTP; string contra = configJSON.PasswordProxyFTP; string servidorProxy = configJSON.ServidorProxyFTP; string uri = $"{folderRemoto}/{Path.GetFileName(filePath)}"; FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri); request.Method = WebRequestMethods.Ftp.UploadFile; // Configuración de credenciales del FTP request.Credentials = new NetworkCredential(usuario, contra); // Configuración del proxy WebProxy proxy = new WebProxy(servidorProxy); if (!string.IsNullOrEmpty(usuario) && !string.IsNullOrEmpty(contra)) { proxy.Credentials = new NetworkCredential(usuario, contra); } request.Proxy = proxy; // Leer el archivo y cargarlo al FTP byte[] fileContents = File.ReadAllBytes(filePath); request.ContentLength = fileContents.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(fileContents, 0, fileContents.Length); } using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) { labelStatus.Text = $"Archivo {filePath} subido con éxito. Estado: {response.StatusDescription}"; } } catch (Exception ex) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); } } else { FtpWebRequest reqFTP = null; Stream ftpStream = null; try { reqFTP = (FtpWebRequest)FtpWebRequest.Create(folderRemoto); reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory; if (!config.ModoPasivoFTP) { reqFTP.UsePassive = false; } else { reqFTP.UsePassive = true; } reqFTP.KeepAlive = false; reqFTP.Timeout = -1; reqFTP.UseBinary = true; reqFTP.Credentials = new NetworkCredential(config.UsuarioFTP, config.PasswordFTP); FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse(); ftpStream = response.GetResponseStream(); ftpStream.Close(); response.Close(); } catch (Exception ex) { //directory already exist I know that is weak but there is no way to check if a folder exist on ftp... string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); } FtpWebRequest request = (FtpWebRequest)WebRequest.Create(folderRemoto + @"/" + Path.GetFileName(filePath)); request.Method = WebRequestMethods.Ftp.UploadFile; if (!config.ModoPasivoFTP) { request.UsePassive = false; } else { request.UsePassive = true; } request.KeepAlive = false; request.Timeout = -1; request.UseBinary = true; request.Credentials = new NetworkCredential(config.UsuarioFTP, config.PasswordFTP); byte[] content = File.ReadAllBytes(filePath); request.ContentLength = content.Length; try { using (Stream stream = request.GetRequestStream()) { stream.Write(content, 0, content.Length); stream.Flush(); stream.Close(); } } catch (Exception exp1) { respuesta = exp1.ToString(); string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(exp1, sNombreClase, currentMethod); } } } catch (Exception e) { respuesta = e.ToString(); string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(e, sNombreClase, currentMethod); } } // private async Task SubirArchivoApiAsync(string pedimento, string filePath) // { // try // { // var config = ConfiguracionJSON.LoadFromJson(); // string Token = SecureDataHandler.ReadDataAsPlainText() ?? ""; // if (string.IsNullOrWhiteSpace(DominioEFC)) // { // logger.LogError("No se ha configurado el dominio", null); // return false; // } // if (!string.IsNullOrEmpty(Token)) // { // var apiClient = Globales.ApiClient; // string UrlGetPedimento = DominioEFC + ApiGetPedimento + pedimento; // string jsonResponse = await apiClient.GetAsync(url: UrlGetPedimento); // if (!apiClient.IsJson(jsonResponse)) // { // logger.LogError("Error en la respuesta de la peticion de pedimento al intentar subir el archivo al api:" + DominioEFC, new Exception("Error API")); // return false; // } // if (!apiClient.HasJsonData(jsonResponse)) // { // logger.LogError("No se obtuvo informacion del api:" + DominioEFC, null); // return false; // } // var pedimentos = apiClient.TryParseJson>(jsonResponse); // if (pedimentos != null) // { // // Obtener el primer pedimento de la lista // var primerPedimento = pedimentos.FirstOrDefault(); // string guiOrganizacion = primerPedimento.organizacion; // string guiPedimento = primerPedimento.id; // string UrlPostArchivo = DominioEFC + ApiPostDocuments; //string respuesta = await apiClient.PostMultipartAsync( // url: UrlPostArchivo, // filePath: filePath, // organizacion: guiOrganizacion, // pedimento: guiPedimento, // documentType: "9", // fuente: "1" // ); // if (!apiClient.IsJson(jsonResponse)) // { // return false; // } // if (!apiClient.HasJsonData(jsonResponse)) // { // return false; // } // var documentos = apiClient.TryParseJson>(jsonResponse); // if (documentos == null) // { // return false; // } // } // else // { // logger.LogInfo("No se encontro el pedimento"); // return false; // } // } // else // { // logger.LogError("Error en la configuracion del Id de Usuario:" + DominioEFC, new Exception("Error Id Usuario")); // return false; // } // } // catch (Exception ex) // { // logger.LogError("Error inesperado SubirArchivoApiAsync", ex); // return false; // } // return true; // } private void RegistrarArchivoEnAPI(string file) { try { string folder = file; string hash; //Lastmodified DateTime myDate1 = new DateTime(1970, 1, 9, 0, 0, 00); DateTime dt = File.GetLastWriteTime(folder); TimeSpan myDateResult; myDateResult = dt - myDate1; int seconds = 0; if (myDateResult.TotalSeconds > 0) { seconds = Convert.ToInt32(myDateResult.TotalSeconds); } using (var md5 = System.Security.Cryptography.MD5.Create()) { using (var stream = File.OpenRead(folder)) { hash = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "‌​").Replace("‌​| ", "").ToLower(); hash = Regex.Replace(hash, @"[^\u0000-\u007F]+", string.Empty); } } string cryptFile = General.CodificarBase64(Path.GetFileName(file)); string cryptUser = General.CodificarBase64(configJson.idUsuarioExp.ToString()); string cryptSeconds = General.CodificarBase64(seconds.ToString()); string cryptHash = General.CodificarBase64(hash); string cryptMac = General.CodificarBase64(configJson.MacAddress); string utilizarWinsaai = config.UsarEstructuraPedimentosWinsaai ? "si" : "no"; string utilizarBodega = config.UsarExpedienteLogistico ? "si" : "no"; string cryptWin = General.CodificarBase64(utilizarWinsaai); string cryptBodega = General.CodificarBase64(utilizarBodega); string cadena = cryptFile + "|" + cryptUser + "|" + cryptSeconds + "|" + cryptHash + "|" + cryptMac + "|" + cryptWin + "|" + cryptBodega; configJson.Consulta(configJson.DominioExp + "/api/insertFile/" + cadena); } catch (Exception ex) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); } } private HashSet carpetasRecientes = new HashSet(); //private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) //{ // FileSystemWatcher watcher = new FileSystemWatcher // { // Path = config.FolderParaGenerarExpediente, // IncludeSubdirectories = true, // Filter = "*.*", // Monitorear todos los archivos // NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.DirectoryName // }; // watcher.Created += (s, args) => // { // if (_backgroundWorker.CancellationPending) // { // e.Cancel = true; // watcher.EnableRaisingEvents = false; // return; // } // try // { // // Actualizar progreso // if (EsCarpeta(args.FullPath)) // { // _backgroundWorker.ReportProgress(0, $"Se detectó un folder nuevo: {args.FullPath}"); // lock (carpetasRecientes) // { // carpetasRecientes.Add(args.FullPath); // } // Task.Delay(2000).ContinueWith(_ => // { // lock (carpetasRecientes) // { // carpetasRecientes.Remove(args.FullPath); // } // // 📌 Llamamos a la función para procesar la carpeta // string carpetaContenedora = args.FullPath; // string nombreZip = Path.GetFileName(args.FullPath) + ".zip"; // string rutaZip = Path.Combine(Path.GetDirectoryName(args.FullPath), nombreZip); // var archivos = Directory.GetFiles(args.FullPath); // // Crear archivo ZIP manualmente y agregar archivos uno por uno // using (FileStream zipStream = new FileStream(rutaZip, FileMode.Create)) // using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create)) // { // foreach (var archivo in archivos) // { // string nombreArchivo = Path.GetFileName(archivo); // DateTime fechaSolo = DateTime.Now.Date; // // Registrar en SQLite // sqliteHelper.RegistrarArchivoProcesado(nombreArchivo, archivo, "Procesado", fechaSolo, Path.GetFileName(args.FullPath), nombreZip); // _backgroundWorker.ReportProgress(0, $"Registrando archivo: {nombreArchivo}"); // // Agregar archivo al ZIP // zip.CreateEntryFromFile(archivo, nombreArchivo); // _backgroundWorker.ReportProgress(0, $"Añadiendo archivo al ZIP: {nombreArchivo}"); // } // } // _backgroundWorker.ReportProgress(0, $"ZIP creado: {rutaZip}"); // // Subir archivo ZIP al servidor FTP // _backgroundWorker.ReportProgress(0, $"Subiendo archivo a servidor FTP: {rutaZip}"); // SubirArchivoFTP(rutaZip); // // Registrar archivo en la API // _backgroundWorker.ReportProgress(0, $"Registrando archivo en API: {rutaZip}"); // RegistrarArchivoEnAPI(rutaZip); // // Eliminar ZIP después de subirlo // File.Delete(rutaZip); // _backgroundWorker.ReportProgress(0, $"Archivo ZIP eliminado: {rutaZip}"); // _backgroundWorker.ReportProgress(0, $"Terminado"); // _backgroundWorker.ReportProgress(1, new { ArchivoZip = rutaZip, Estado = "Procesado" }); // }); // } // else // { // lock (carpetasRecientes) // { // // Si el archivo está dentro de una carpeta recién detectada, lo ignoramos // string carpetaPadre = Path.GetDirectoryName(args.FullPath); // if (carpetaPadre != null && carpetasRecientes.Contains(carpetaPadre)) // { // return; // } // } // _backgroundWorker.ReportProgress(0, $"Se detectó un archivo nuevo: {args.FullPath}"); // Task.Delay(2000).ContinueWith(_ => // { // string carpetaContenedora = Path.GetFileName(Path.GetDirectoryName(args.FullPath)); // // Ruta donde se creará el archivo ZIP // string rutaZip = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(args.FullPath)), carpetaContenedora + ".zip"); // // Comprimir el archivo en el ZIP // if (!File.Exists(rutaZip)) // { // // Si el ZIP no existe, crear uno nuevo y agregar el archivo // using (var zip = ZipFile.Open(rutaZip, ZipArchiveMode.Create)) // { // zip.CreateEntryFromFile(args.FullPath, Path.GetFileName(args.FullPath)); // } // } // else // { // // Si el ZIP ya existe, agregar el archivo al ZIP // using (var zip = ZipFile.Open(rutaZip, ZipArchiveMode.Update)) // { // zip.CreateEntryFromFile(args.FullPath, Path.GetFileName(args.FullPath)); // } // } // _backgroundWorker.ReportProgress(0, $"Archivo zip creado: {rutaZip}"); // SubirArchivoFTP(rutaZip); // _backgroundWorker.ReportProgress(0, $"Subiendo archivo a servidor FTP: {rutaZip}"); // RegistrarArchivoEnAPI(rutaZip); // _backgroundWorker.ReportProgress(0, $"Registrando archivo en API: {rutaZip}"); // File.Delete(rutaZip); // //int idCarpetaPedimento = sqliteHelper.ObtenerORegistrarIdCarpetaPedimento(carpetaContenedora); // DateTime fechaSolo = DateTime.Now.Date; // sqliteHelper.RegistrarArchivoProcesado(Path.GetFileName(args.FullPath), args.FullPath, "Procesado", fechaSolo, carpetaContenedora, carpetaContenedora + ".zip"); // _backgroundWorker.ReportProgress(0, $"Archivo ZIP eliminado: {rutaZip}"); // _backgroundWorker.ReportProgress(0, $"Terminado"); // }); // } // } // catch (Exception ex) // { // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); // } // }; // watcher.Created += (s, args) => // { // //ProcesarCambio(args.FullPath, zipFilePath, ftpUrl, username, password); // }; // // Iniciar monitoreo // watcher.EnableRaisingEvents = true; // // Mantener el BackgroundWorker activo // while (!_backgroundWorker.CancellationPending) // { // System.Threading.Thread.Sleep(100); // Reducir consumo de CPU // } // e.Cancel = true; //} //private void BackgroundWorker_DoWork2(object sender, DoWorkEventArgs e) //{ // FileSystemWatcher watcher = new FileSystemWatcher // { // Path = config.FolderParaGenerarExpediente, // IncludeSubdirectories = true, // Filter = "*.*", // NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.DirectoryName, // EnableRaisingEvents = true // }; // watcher.Created += (s, args) => // { // if (_backgroundWorker.CancellationPending) // { // e.Cancel = true; // watcher.EnableRaisingEvents = false; // return; // } // try // { // // Obtener carpeta raíz según aplicaWinsaii // var (carpetaRaiz, nombreRaiz) = Helpers.ObtenerCarpetaRaiz(args.FullPath); // string pattern = @"^\d{2}-\d{2}-\d{4}-\d{7}$"; // bool esValido = System.Text.RegularExpressions.Regex.IsMatch(nombreRaiz, pattern); // if (!esValido) // { // _backgroundWorker.ReportProgress(0, $"Formato de Expediente Incorrecto: {nombreRaiz}"); // return; // } // // Ignorar archivos que no estén dentro de la carpeta raíz // if (!Path.GetFullPath(args.FullPath).StartsWith(carpetaRaiz, StringComparison.OrdinalIgnoreCase)) // return; // // Evitar reprocesar la misma carpeta raíz // lock (carpetasRecientes) // { // if (carpetasRecientes.Contains(carpetaRaiz)) // return; // carpetasRecientes.Add(carpetaRaiz); // } // _backgroundWorker.ReportProgress(0, $"Procesando carpeta raíz: {carpetaRaiz}"); // Task.Delay(2000).ContinueWith(_ => // { // lock (carpetasRecientes) // { // carpetasRecientes.Remove(carpetaRaiz); // } // try // { // // Esperar a que todos los archivos estén listos // if (!Helpers.EsperarArchivosListos(carpetaRaiz, 30)) // { // _backgroundWorker.ReportProgress(0, $"Algunos archivos siguen en uso en {carpetaRaiz}, se omite ZIP temporalmente."); // return; // } // string nombreZip = nombreRaiz + ".zip"; // string rutaZip = Path.Combine(Path.GetDirectoryName(carpetaRaiz), nombreZip); // // Obtener todos los archivos de la carpeta raíz y subcarpetas // var archivos = Directory.GetFiles(carpetaRaiz, "*.*", SearchOption.AllDirectories); // if (archivos.Length == 0) // { // _backgroundWorker.ReportProgress(0, $"No hay archivos para procesar en: {carpetaRaiz}"); // return; // } // using (FileStream zipStream = new FileStream(rutaZip, FileMode.Create)) // using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create)) // { // foreach (var archivo in archivos) // { // string nombreArchivo = Path.GetFileName(archivo); // Solo el nombre, sin subcarpetas // DateTime fechaSolo = DateTime.Now.Date; // sqliteHelper.RegistrarArchivoProcesado( // nombreArchivo, // archivo, // "Procesado", // fechaSolo, // nombreRaiz, // nombreZip // ); // _backgroundWorker.ReportProgress(0, $"Añadiendo archivo al ZIP: {nombreArchivo}"); // zip.CreateEntryFromFile(archivo, nombreArchivo); // } // } // //_backgroundWorker.ReportProgress(0, $"ZIP creado: {rutaZip}"); // //SubirArchivoFTP(rutaZip); // //_backgroundWorker.ReportProgress(0, $"Subiendo a servidor FTP: {rutaZip}"); // //RegistrarArchivoEnAPI(rutaZip); // //_backgroundWorker.ReportProgress(0, $"Registrando archivo en API: {rutaZip}"); // //File.Delete(rutaZip); // _backgroundWorker.ReportProgress(0, $"ZIP eliminado: {rutaZip}"); // _backgroundWorker.ReportProgress(0, $"Procesamiento completado"); // _backgroundWorker.ReportProgress(1, new { ArchivoZip = rutaZip, Estado = "Procesado" }); // } // catch (Exception exZip) // { // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(exZip, sNombreClase, currentMethod); // } // }); // } // catch (Exception ex) // { // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); // } // }; // // Mantener el BackgroundWorker activo // while (!_backgroundWorker.CancellationPending) // { // Thread.Sleep(100); // } // e.Cancel = true; //} //private void BackgroundWorker_DoWork2(object sender, DoWorkEventArgs e) //{ // FileSystemWatcher watcher = new FileSystemWatcher // { // Path = config.FolderParaGenerarExpediente, // IncludeSubdirectories = true, // Filter = "*.*", // NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.DirectoryName // }; // watcher.Created += (s, args) => // { // if (_backgroundWorker.CancellationPending) // { // e.Cancel = true; // watcher.EnableRaisingEvents = false; // return; // } // try // { // // Determinar la carpeta raíz según aplicaWinsaii // var (carpetaRaiz, nombreRaiz) = Helpers.ObtenerCarpetaRaiz(args.FullPath); // // Evitar procesar la misma carpeta raíz varias veces // lock (carpetasRecientes) // { // if (carpetasRecientes.Contains(carpetaRaiz)) // return; // carpetasRecientes.Add(carpetaRaiz); // } // _backgroundWorker.ReportProgress(0, $"Procesando carpeta raíz: {carpetaRaiz}"); // Task.Delay(2000).ContinueWith(_ => // { // lock (carpetasRecientes) // { // carpetasRecientes.Remove(carpetaRaiz); // } // try // { // string nombreZip = nombreRaiz + ".zip"; // string rutaZip = Path.Combine(Path.GetDirectoryName(carpetaRaiz), nombreZip); // // Obtener todos los archivos de la carpeta raíz (recursivo) // var archivos = Directory.GetFiles(carpetaRaiz, "*.*", SearchOption.AllDirectories); // using (FileStream zipStream = new FileStream(rutaZip, FileMode.Create)) // using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create)) // { // foreach (var archivo in archivos) // { // string rutaRelativa = Path.GetRelativePath(carpetaRaiz, archivo); // DateTime fechaSolo = DateTime.Now.Date; // // Registrar en SQLite // sqliteHelper.RegistrarArchivoProcesado( // Path.GetFileName(archivo), // archivo, // "Procesado", // fechaSolo, // nombreRaiz, // nombreZip // ); // _backgroundWorker.ReportProgress(0, $"Añadiendo archivo al ZIP: {rutaRelativa}"); // zip.CreateEntryFromFile(archivo, rutaRelativa); // } // } // _backgroundWorker.ReportProgress(0, $"ZIP creado: {rutaZip}"); // //// Subir a FTP // //_backgroundWorker.ReportProgress(0, $"Subiendo a servidor FTP: {rutaZip}"); // //SubirArchivoFTP(rutaZip); // //// Registrar en API // //_backgroundWorker.ReportProgress(0, $"Registrando archivo en API: {rutaZip}"); // //RegistrarArchivoEnAPI(rutaZip); // // Eliminar ZIP temporal // File.Delete(rutaZip); // _backgroundWorker.ReportProgress(0, $"ZIP eliminado: {rutaZip}"); // _backgroundWorker.ReportProgress(0, $"Procesamiento completado"); // _backgroundWorker.ReportProgress(1, new { ArchivoZip = rutaZip, Estado = "Procesado" }); // } // catch (Exception exZip) // { // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(exZip, sNombreClase, currentMethod); // } // }); // } // catch (Exception ex) // { // string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; // string currentMethod = MethodBase.GetCurrentMethod().Name; // sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); // } // }; // watcher.EnableRaisingEvents = true; // while (!_backgroundWorker.CancellationPending) // { // Thread.Sleep(100); // Reducir consumo CPU // } // e.Cancel = true; //} private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { } private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == 0) { labelStatus.Text = e.UserState as string; } else if (e.ProgressPercentage == 1) { // Agregar el registro al ListView var datos = e.UserState as dynamic; AgregarRegistroAListViewExpediente(datos.ArchivoZip, datos.Estado); } } private void buttonConfiguracion_Click(object sender, EventArgs e) { if (accederAConfiguracion) { FormConfiguracionExpediente configuracion = new FormConfiguracionExpediente(); configuracion.ShowDialog(); } else { MessageBox.Show("Por el momento no es posible ingresar a la configuración, espere a que el proceso de escaneo haya terminado."); } } //private void LlenarListViewEscaneoInicial(string archivoZip) //{ // // Limpiar elementos existentes en el ListView // listViewExpedientes.Invoke((MethodInvoker)(() => // { // var item = new ListViewItem(archivoZip, 0); // item.SubItems.Add("Procesado"); // listViewExpedientes.Items.Add(item); // listViewExpedientes.Columns[2].Width = 0; // })); // //listViewExpedientes.Items.Clear(); //} private void AgregarRegistroAListViewExpediente(string archivoZip, string estado) { if (listViewExpedientes.InvokeRequired) // Verificar si necesitas invocar { // Usar Invoke para ejecutar en el hilo de la UI listViewExpedientes.Invoke(new Action(() => AgregarRegistroAListViewExpediente(archivoZip, estado))); } else { // Código seguro para el hilo de la UI var item = new ListViewItem(archivoZip, 0); item.SubItems.Add(estado); listViewExpedientes.Items.Add(item); labelTotalExpedientes.Text = "Total de expedientes: " + listViewExpedientes.Items.Count.ToString(); } } private void LlenarListViewConExpedientes() { // Obtener datos de la base de datos //var expedientes = sqliteHelper.ObtenerArchivosZIP(); var expedientes = sqliteHelper.ObtenerCarpetas(); // Limpiar elementos existentes en el ListView listViewExpedientes.Items.Clear(); // Agregar cada expediente al ListView foreach (var expediente in expedientes) { var item = new ListViewItem(expediente.ArchivoZip, 0); item.SubItems.Add(expediente.Estado); // Guardamos la ruta en Tag para futuras referencias item.Tag = expediente.ArchivoZip; //item.SubItems.Add(expediente.NombreArchivo); //item.SubItems.Add(expediente.FechaProcesado); listViewExpedientes.Items.Add(item); } listViewExpedientes.Columns[2].Width = 0; labelTotalExpedientes.Visible = true; labelTotalExpedientes.Text = "Total de expedientes: " + listViewExpedientes.Items.Count.ToString(); } private async void FormMain_Load(object sender, EventArgs e) { // Virual Mode //listViewExpedientes.VirtualMode = true; //listViewExpedientes.VirtualListSize = 0; // inicial //listViewExpedientes.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(ListViewExpedientes_RetrieveVirtualItem!); //listViewExpedientes.View = View.Tile; // Crear columnas para el ListView (esto se hace una sola vez) listViewExpedientes.Sorting = SortOrder.None; // MUY IMPORTANTE listViewExpedientes.Columns.Clear(); listViewExpedientes.Columns.Add("Expediente", 0, HorizontalAlignment.Left); listViewExpedientes.Columns.Add("Pedimento", 0, HorizontalAlignment.Left); listViewExpedientes.Columns.Add("Actualizado", 0, HorizontalAlignment.Left); // Columna oculta para fecha de inserción (ordenar por aquí) listViewExpedientes.Columns.Add("Ticks", 0, HorizontalAlignment.Left); // Activamos el comparador (la columna oculta es índice 3) //listViewExpedientes.ListViewItemSorter = new ListViewTicksDescComparer(3); //// 🔹 Modo Tile //listViewExpedientes.View = View.Tile; //listViewExpedientes.TileSize = new Size(400, 80); imageList1.Images.Add(((System.Drawing.Image)(Properties.Resources.appbar_folder))); imageList1.Images.Add(((System.Drawing.Image)(Properties.Resources.appbar_folder2))); listViewExpedientes.LargeImageList = imageList1; listViewExpedientes.SmallImageList = imageList1; System.Windows.Forms.ToolTip toolTip1 = new System.Windows.Forms.ToolTip(); // Set up the delays for the ToolTip. toolTip1.AutoPopDelay = 5000; toolTip1.InitialDelay = 1000; toolTip1.ReshowDelay = 500; // Force the ToolTip text to be displayed whether or not the form is active. toolTip1.ShowAlways = true; // Set up the ToolTip text for the Button and Checkbox. toolTip1.SetToolTip(this.buttonConfiguracion, "Accese a su configuración"); toolTip1.SetToolTip(this.buttonAbrirExpediente, "Abrir expediente.com"); toolTip1.SetToolTip(this.buttonAbrirFolder, "Abrir su folder de expedientes"); toolTip1.SetToolTip(this.buttonAbrirFolderMov, "Abrir folder donde se guardan expedientes"); labelUsuario.Text = "Usuario: " + configJson.UsuarioExp; labelTotalExpedientes.Visible = false; this.DominioEFC = Properties.Settings.Default.urlEFC as string; //if (PrimerInicioDeBarrido == true) //{ // PrimerInicioDeBarrido = false; // _barridoEnEjecucion = true; // labelStatus.Text = "Iniciado Escaneo..."; // // Antes de arrancar el monitoreo, limpia y reprocesa pendientes // await _monitor.ReprocesarArchivosPendientesAsync(); // _barridoEnEjecucion = false; // TimerBarrido.Start(); //} await _monitor.ReprocesarArchivosPendientesAsync(); accederAConfiguracion = true; labelStatus.Text = "Escaneo terminado"; } private void ListViewExpedientes_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) { if (e.ItemIndex < 0 || e.ItemIndex >= _todosExpedientes.Count) { e.Item = new ListViewItem("N/A"); return; } var exp = _todosExpedientes[e.ItemIndex]; var item = new ListViewItem(exp.Clave); // Expediente item.SubItems.Add(exp.Estado); item.SubItems.Add(exp.FechaCreacion); item.SubItems.Add(exp.Ticks); item.Tag = exp.Expediente; e.Item = item; } private async void InsertarExpedientes(List<(string ArchivoZip, string Estado, string FechaCreacion)> expedientes) { if (expedientes == null || expedientes.Count == 0) return; await CargarExpedientesAsync(expedientes); } private async Task CargarExpedientesAsync(List<(string ArchivoZip, string Estado, string FechaCreacion)> lista) { await Task.Run(() => { var nuevos = new List(); foreach (var expediente in lista) { DateTime fecha = DateTime.ParseExact(expediente.FechaCreacion, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); string ticks = fecha.Ticks.ToString(); var exp = new ExpedienteInfo { Expediente = expediente.ArchivoZip, Clave = expediente.ArchivoZip.Replace(".zip", ""), Estado = expediente.Estado, FechaCreacion = expediente.FechaCreacion, Ticks = ticks }; nuevos.Add(exp); if (nuevos.Count >= 1000) { lock (_todosExpedientes) { _todosExpedientes.InsertRange(0, nuevos); } nuevos.Clear(); this.Invoke(new Action(() => { listViewExpedientes.VirtualListSize = _todosExpedientes.Count; listViewExpedientes.Invalidate(); })); } } // Resto de expedientes if (nuevos.Count > 0) { lock (_todosExpedientes) { _todosExpedientes.InsertRange(0, nuevos); } this.Invoke(new Action(() => { listViewExpedientes.VirtualListSize = _todosExpedientes.Count; listViewExpedientes.Invalidate(); })); } }); } private void listViewExpedientes_SelectedIndexChanged(object sender, EventArgs e) { } private void panel2_Paint(object sender, PaintEventArgs e) { } private void buttonAbrirExpediente_Click(object sender, EventArgs e) { Process.Start(new ProcessStartInfo { FileName = Properties.Settings.Default.urlEFC.ToString(), UseShellExecute = true }); } private void buttonAbrirFolder_Click(object sender, EventArgs e) { try { if (!Directory.Exists(config.FolderParaGenerarExpediente)) { Directory.CreateDirectory(config.FolderParaGenerarExpediente); } Process.Start("explorer.exe", config.FolderParaGenerarExpediente); } catch (Exception ex) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(ex, sNombreClase, currentMethod); } } private void buttonAbrirFolderMov_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(config.FolderParaDepurarExpediente)) { MessageBox.Show("La ruta de depuración no se ha configurado."); return; } if (!Directory.Exists(config.FolderParaDepurarExpediente)) { Directory.CreateDirectory(config.FolderParaDepurarExpediente); } Process.Start("explorer.exe", config.FolderParaDepurarExpediente); } private void FormMain_Shown(object sender, EventArgs e) { //timerFTP.Start(); //Se apaga para no enviar peticion de ejecutar el procesamiento de expedientes this.WindowState = FormWindowState.Minimized; this.Hide(); mynotifyicon.Text = "Expediente electronico\nActualizado"; mynotifyicon.ShowBalloonTip(300); //await Task.Run(() => RealizarEscaneoInicialYProcesar2()); //if (PrimerInicioDeBarrido == true) //{ // PrimerInicioDeBarrido = false; // _barridoEnEjecucion = true; // // Antes de arrancar el monitoreo, limpia y reprocesa pendientes // await _monitor.ReprocesarArchivosPendientesAsync(); // _barridoEnEjecucion = false; // TimerBarrido.Start(); //} //accederAConfiguracion = true; //labelStatus.Text = "Escaneo terminado"; //// Configurar el BackgroundWorker //_backgroundWorker = new BackgroundWorker //{ // WorkerReportsProgress = true, // WorkerSupportsCancellation = true //}; //_backgroundWorker.DoWork += BackgroundWorker_DoWork2; //_backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; //_backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged; //// Iniciar el BackgroundWorker //StartBackgroundWorker(); //LlenarListViewConExpedientes(); labelTotalExpedientes.Text = "Total de expedientes: " + listViewExpedientes.Items.Count.ToString(); } public static string[] getFolderFile(string filename) { string[] partes = filename.Split('\\'); string folder = ""; string[] result = new string[2]; for (int i = 0; i < partes.Length; i++) { if (i == partes.Length - 1) { filename = partes[i]; } else { folder = folder + partes[i] + "\\"; } } result[0] = filename; result[1] = folder.TrimEnd('\\'); return result; } public bool IsDirectoryEmpty(string path) { return !Directory.EnumerateFileSystemEntries(path).Any(); } private void MoverArchivosAFolderDeRespaldo(string filename) { string type = ""; if (config.DepurarExpediente) { // get the file attributes for file or directory FileAttributes attr = File.GetAttributes(filename); //detect whether its a directory or file if ((attr & FileAttributes.Directory) == FileAttributes.Directory) type = "dir"; else type = "file"; string destination = config.FolderParaDepurarExpediente; string folder = config.FolderParaGenerarExpediente; string archivo = filename.Replace(folder, ""); string[] parts = getFolderFile(archivo); if (parts.Length > 1) { destination = destination + parts[1]; archivo = parts[0]; } if (!Directory.Exists(destination)) { Directory.CreateDirectory(destination); } if (type == "dir") { if (Directory.Exists(filename)) { try { // Previous command was: Directory.Move(source, newLocation); DirectoryInfo dir = new DirectoryInfo(filename); dir.MoveTo(destination + "\\" + archivo); } catch (Exception e) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(e, sNombreClase, currentMethod); } } } else { if (File.Exists(filename)) { try { // Previous command was: Directory.Move(source, newLocation); FileInfo file = new FileInfo(filename); file.MoveTo(destination + "\\" + archivo); } catch (Exception e) { string sNombreClase = MethodBase.GetCurrentMethod()?.DeclaringType?.Name; string currentMethod = MethodBase.GetCurrentMethod().Name; sqliteHelper.AgregarRegistroErrorLog(e, sNombreClase, currentMethod); } } } string[] pa = getFolderFile(filename); if (IsDirectoryEmpty(pa[1]) && pa[1] != folder) { Directory.Delete(pa[1]); } } } private void listViewExpedientes_MouseClick(object sender, MouseEventArgs e) { if (listViewExpedientes.SelectedItems.Count > 0) { //string idSeleccionado = listViewExpedientes.SelectedItems[0].Text; ListViewItem seleccionado = listViewExpedientes.SelectedItems[0]; string idSeleccionado = (string)(seleccionado.Tag == null ? "" : seleccionado.Tag); listViewArchivosProcesados.Columns.Clear(); listViewArchivosProcesados.Columns.Add("Archivo", 200, HorizontalAlignment.Left); listViewArchivosProcesados.Columns.Add("Estatus", 200, HorizontalAlignment.Left); listViewArchivosProcesados.Columns.Add("Fecha", 0, HorizontalAlignment.Left); if (idSeleccionado == "") return; // Obtener datos de la base de datos var archivosProcesados = sqliteHelper.ObtenerArchivosProcesados(idSeleccionado); // Limpiar elementos existentes en el ListView listViewArchivosProcesados.Items.Clear(); // Agregar cada expediente al ListView foreach (var archivoProcesado in archivosProcesados) { var item = new ListViewItem(archivoProcesado.Archivo, 0); item.SubItems.Add(archivoProcesado.Estado); item.SubItems.Add(archivoProcesado.Fecha.ToString()); //item.SubItems.Add(expediente.FechaProcesado); listViewArchivosProcesados.Items.Add(item); } listViewArchivosProcesados.Columns[2].Width = 0; //CargarListaRelacionada(idSeleccionado); } } //private void mynotifyicon_MouseDoubleClick(object sender, MouseEventArgs e) //{ // if (!Directory.Exists(config.FolderParaGenerarExpediente)) // { // Directory.CreateDirectory(config.FolderParaGenerarExpediente); // } // Process.Start(config.FolderParaGenerarExpediente); //} private void cerrarExpedienteElectronicoToolStripMenuItem_Click(object sender, EventArgs e) { mynotifyicon.Visible = false; Application.Exit(); } private void mynotifyicon_Click(object sender, EventArgs e) { MouseEventArgs me = (MouseEventArgs)e; if (me.Button == MouseButtons.Left) { if (FormWindowState.Minimized == this.WindowState) { this.Show(); this.WindowState = FormWindowState.Normal; } else if (FormWindowState.Normal == this.WindowState) { this.Hide(); this.WindowState = FormWindowState.Minimized; } } } private void button4_Click(object sender, EventArgs e) { } private void buttonErrorLog_Click(object sender, EventArgs e) { FormErrorLog formErrorLog = new FormErrorLog(); formErrorLog.ShowDialog(); } private void label1_Click(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { FormAvanceAPI formAvanceAPI = new FormAvanceAPI(); formAvanceAPI.Show(); } private async void ProcesoManual_Click(object sender, EventArgs e) { if (_barridoEnEjecucion) return; _barridoEnEjecucion = true; try { labelStatus.Text = "Iniciando Escaneo..."; // ⚡ Si tu método ya es async/await interno, NO necesitas Task.Run await _monitor.EscaneoManual(); // Si quieres forzar que vaya al fondo y no bloquee nunca: // await Task.Run(() => _monitor.EjecutarBarridoAsync()); } catch (Exception ex) { Console.WriteLine("Error en el barrido: " + ex.Message); } finally { labelStatus.Text = "Escaneo terminado"; _barridoEnEjecucion = false; } } private void btn_VisorExpedientes_Click(object sender, EventArgs e) { var form = Application.OpenForms.OfType().FirstOrDefault(); if (form != null) { form.BringToFront(); form.WindowState = FormWindowState.Normal; } else { FormExpedientes winExpedientes = new FormExpedientes(); winExpedientes.Show(); } } } }