using ClosedXML.Excel; using System.Data; using System.Data.OleDb; namespace AiQ_GUI { internal class StatsExcel { private const string exportPath = @"G:\Shared drives\MAV Production GUI's\AiQ\GUI's\AiQ_Test_Stats.xlsx"; public void ExportDatabaseToExcel() { try { MainForm.Instance.AddToActionsList("=== ExportDatabaseToExcel START ==="); using OleDbConnection conn = new(Access.connString); conn.Open(); MainForm.Instance.AddToActionsList("Connected to Access database."); DateTime now = DateTime.Now; // Read LastStatsRun from UniversalData (if any) DateTime? lastStatsRun = null; try { using (OleDbCommand cmdPeriod = new OleDbCommand("SELECT LastStatsRun FROM UniversalData", conn)) { object res = cmdPeriod.ExecuteScalar(); if (res != null && res != DBNull.Value) lastStatsRun = (DateTime)res; } MainForm.Instance.AddToActionsList($"Fetched LastStatsRun: {(lastStatsRun.HasValue ? lastStatsRun.Value.ToString("yyyy-MM-dd HH:mm:ss") : "none")}"); } catch (Exception periodEx) { MainForm.Instance.AddToActionsList($"Warning: could not read LastStatsRun. Details: {periodEx.Message}"); } // ==================== MAIN STATS EXPORT ==================== string selectColumns = @" ModelNumber, [Total Tests Run], [Pre Tests Passed], [Pre Tests Failed], [Final Tests Passed], [Final Tests Failed], [RMA Total Tests Run], [RMA Pre Tests Passed], [RMA Pre Tests Failed], [RMA Final Tests Passed], [RMA Final Tests Failed], [Diagnostic Failure], [Failed To Set Model Or Serial Number], [Camera Not In Test Tube], [Could Not Zoom Modules To 8000], [Could Not Zoom Modules To Full Wide], [Please Get RMA Number From Operations Team Before Continuing], [Please Get A Valid Vaxtor Product Key Before Continuing], [Visual Test Fail - Sleeve Not Aligned], [Visual Test Fail - Not All Front Screws Fitted], [Visual Test Fail - Not All Rear Screws Fitted], [Visual Test Fail - Unit rattles]"; string query = $@" SELECT {selectColumns} FROM AiQ"; OleDbDataAdapter adapter = new(query, conn); DataTable dataTable = new(); adapter.Fill(dataTable); if (dataTable.Rows.Count == 0) { MainForm.Instance.AddToActionsList("No data found in AiQ table."); return; } string monthName = now.ToString("MMMM"); string sheetName = $"{monthName} Stats"; MainForm.Instance.AddToActionsList($"Adding sheet: {sheetName}"); XLWorkbook workbook; if (File.Exists(exportPath)) { workbook = new XLWorkbook(exportPath); MainForm.Instance.AddToActionsList("Opened existing workbook."); } else { workbook = new XLWorkbook(); MainForm.Instance.AddToActionsList("Created new workbook (file not found)."); } if (workbook.Worksheets.Contains(sheetName)) { workbook.Worksheet(sheetName).Delete(); MainForm.Instance.AddToActionsList($"Deleted old sheet: {sheetName}"); } IXLWorksheet ws = workbook.Worksheets.Add(sheetName); ws.Cell(1, 1).InsertTable(dataTable, "AiQ_Stats", true); ws.Columns().AdjustToContents(); // Write Data Period label and computed period string to the right of the table int infoCol = dataTable.Columns.Count + 2; ws.Cell(1, infoCol).Value = "Data Period"; string periodText; if (lastStatsRun.HasValue) { periodText = $"{lastStatsRun.Value:yyyy-MM-dd HH:mm:ss} - {now:yyyy-MM-dd HH:mm:ss}"; } else { periodText = $"Up to {now:yyyy-MM-dd HH:mm:ss}"; } ws.Cell(2, infoCol).Value = periodText; // ==================== DIAGS STATS EXPORT (CURRENT MONTH ONLY) ==================== MainForm.Instance.AddToActionsList("Exporting DiagsStats for current month..."); DateTime monthStart = new(now.Year, now.Month, 1); DateTime nextMonth = monthStart.AddMonths(1); string diagsQuery = @" SELECT [Date], [Model], [Red Diags Labels], [RhTxBxActions Contents], [IsRma], [RMA] FROM DiagsStats WHERE [Date] >= ? AND [Date] < ?"; using (OleDbCommand diagsCmd = new OleDbCommand(diagsQuery, conn)) { diagsCmd.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = monthStart }); diagsCmd.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = nextMonth }); using (OleDbDataAdapter diagsAdapter = new OleDbDataAdapter(diagsCmd)) { DataTable diagsTable = new(); diagsAdapter.Fill(diagsTable); if (diagsTable.Rows.Count > 0) { int startRow = (ws.LastRowUsed()?.RowNumber() ?? 0) + 3; ws.Cell(startRow, 1).Value = "Diags Stats (Current Month)"; ws.Cell(startRow, 1).Style.Font.Bold = true; ws.Cell(startRow, 1).Style.Font.FontSize = 12; ws.Cell(startRow + 1, 1).InsertTable(diagsTable, "Diags_Stats", true); ws.Columns().AdjustToContents(); MainForm.Instance.AddToActionsList($"Added DiagsStats ({diagsTable.Rows.Count} rows) starting at row {startRow}."); } } } // ==================== SAVE MAIN SHEET ==================== workbook.SaveAs(exportPath); MainForm.Instance.AddToActionsList($"Added {sheetName} to workbook: {exportPath}"); workbook.Dispose(); // ==================== BACKUP TABLE (ALWAYS, BEFORE RESET) ==================== string ts = now.ToString("yyyyMMdd_HHmmss"); string backupTableName = $"Ztats_{ts}"; if (backupTableName.Length > 64) backupTableName = backupTableName.Substring(0, 64); string backupSql = $@" SELECT {selectColumns} INTO [{backupTableName}] FROM AiQ"; try { using (OleDbCommand cmdBackup = new(backupSql, conn)) { cmdBackup.ExecuteNonQuery(); } MainForm.Instance.AddToActionsList($"Created backup table: [{backupTableName}]"); } catch (Exception backupEx) { MainForm.Instance.AddToActionsList($"ERROR creating backup table [{backupTableName}]. Aborting reset to protect data. Details: {backupEx.Message}"); MainForm.Instance.AddToActionsList("=== ExportDatabaseToExcel END (backup failed, no reset) ==="); return; } using (OleDbTransaction tx = conn.BeginTransaction()) { try { string resetSql = @" UPDATE AiQ SET [Total Tests Run] = 0, [Pre Tests Passed] = 0, [Pre Tests Failed] = 0, [Final Tests Passed] = 0, [Final Tests Failed] = 0, [RMA Total Tests Run] = 0, [RMA Pre Tests Passed] = 0, [RMA Pre Tests Failed] = 0, [RMA Final Tests Passed] = 0, [RMA Final Tests Failed] = 0, [Diagnostic Failure] = 0, [Failed To Set Model Or Serial Number] = 0, [Camera Not In Test Tube] = 0, [Could Not Zoom Modules To 8000] = 0, [Could Not Zoom Modules To Full Wide] = 0, [Please Get RMA Number From Operations Team Before Continuing] = 0, [Please Get A Valid Vaxtor Product Key Before Continuing] = 0, [Visual Test Fail - Sleeve Not Aligned] = 0, [Visual Test Fail - Not All Front Screws Fitted] = 0, [Visual Test Fail - Not All Rear Screws Fitted] = 0, [Visual Test Fail - Unit rattles] = 0;"; using (OleDbCommand cmdReset = new(resetSql, conn, tx)) { int affected = cmdReset.ExecuteNonQuery(); MainForm.Instance.AddToActionsList($"Zeroed counters on AiQ rows: {affected} row(s)."); } int updatedRows; using (OleDbCommand cmdUpd = new("UPDATE UniversalData SET LastStatsRun = ?", conn, tx)) { cmdUpd.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = now }); updatedRows = cmdUpd.ExecuteNonQuery(); } if (updatedRows == 0) { using OleDbCommand cmdIns = new("INSERT INTO UniversalData (LastStatsRun) VALUES (?)", conn, tx); cmdIns.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = now }); cmdIns.ExecuteNonQuery(); MainForm.Instance.AddToActionsList("Inserted LastStatsRun row."); } else { MainForm.Instance.AddToActionsList("Updated LastStatsRun successfully."); } tx.Commit(); MainForm.Instance.AddToActionsList("Reset committed."); } catch (Exception resetEx) { tx.Rollback(); MainForm.Instance.AddToActionsList($"ERROR during reset, rolled back. Details: {resetEx.Message}"); } conn.Close(); } MainForm.Instance.AddToActionsList("=== ExportDatabaseToExcel END ==="); } catch (Exception ex) { MainForm.Instance.AddToActionsList($"ERROR exporting stats: {ex.Message}"); MainForm.Instance.AddToActionsList($"Stack Trace: {ex.StackTrace}"); } } } }