using log4net; using Dapper; using Microsoft.Data.SqlClient; using OfficeOpenXml; using OfficeOpenXml.Export.ToDataTable; using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Net.Mail; using System.Text; using System.Threading.Tasks; namespace kmCustomReportsNET.ClassObj; internal class ClsDobbsEmail_T1439 : IDisposable { public string RptSaveToFolder { get; set; } = ClsConstants.KDrive + @"\Projects\Daily Report Archive"; public string Template1Path { get; set; } = ClsConstants.KDrive + @"\Projects\Daily Reports - Dobbs\T1439 Template 01.xlsx"; public string BusinessName { get; set; } = "DobbsTire"; public ClsConstants.enuReportIDs ReportID { get; internal set; } = ClsConstants.enuReportIDs.T1439; public bool DebugMode { get; set; } = false; #region "Private Variables" ILog appLog = LogManager.GetLogger(Program.AppName); DataSet? ds = null; List FilesToAttach = new(); string SubjectToUse = string.Empty; #endregion public void Dispose() { if (ds != null) ds.Dispose(); ds = null; FilesToAttach.Clear(); } public ClsDobbsEmail_T1439() { ExcelPackage.LicenseContext = LicenseContext.NonCommercial; } internal void Go() { if (ClsConstants.NeedToRun(ReportID.ToString())) { DateTimeOffset nxtRunTime; appLog.DebugFormat("{0} report is checking to see if we need to run...", ReportID.ToString()); using (var cn = new SqlConnection(kmCommonLibsCore.Constants.cnRDB)) { bool? ReportDueNow = false; ReportDueNow = DebugMode || cn.ExecuteScalar("Select Top 1 [NeedToSend] From [crpt].[Dobbs_EmailContestCalendar] Where [SendReport]=@Today", new { Today = DateTime.Today }); if (ReportDueNow.HasValue && ReportDueNow.Value) { cn.Open(); appLog.DebugFormat("{0} report is now running!", ReportID.ToString()); using (var cm = new SqlCommand("crpt.[Dobbs_T1439_EmailContests]", cn) { CommandType = CommandType.StoredProcedure, CommandTimeout = 120 }) using (var da = new SqlDataAdapter(cm)) { //cm.Parameters.Add("@DateThruOverride", SqlDbType.Date).Value = DateTime.Parse("Oct 7, 2025"); // override the date thru date for testing ds = new DataSet(); da.Fill(ds); } // if (ds != null && ds.Tables.Count > 2 && ds.Tables[0].Rows.Count == 1) { CreateWeeklyStandings(); CreateDetailSnapshots(); if (!DebugMode) { appLog.DebugFormat("{0} report is now sending out the email containing the report for this week.", ReportID.ToString()); SendEmails(); cn.Execute("Update [crpt].[Dobbs_EmailContestCalendar] Set [NeedToSend]=0 Where [SendReport]=@Today", new { Today = DateTime.Today }); } } // Run it at the next 7AM I can find, starting with tomorrow nxtRunTime = new DateTimeOffset(DateTime.Today.AddDays(1)); } else { // Run it at the next 7AM I can find nxtRunTime = new DateTimeOffset(DateTime.Today); appLog.DebugFormat("{0} report does not need to run.", ReportID.ToString()); } } while (nxtRunTime < DateTimeOffset.Now || nxtRunTime.Hour != 7) nxtRunTime = nxtRunTime.AddHours(1); ClsConstants.SetNextRun(ReportID.ToString(), nxtRunTime); appLog.DebugFormat("{0} report will next check at: {1:ddd d-MMM-yyyy h:mm tt zzz}", ReportID.ToString(), nxtRunTime); } } private void CreateWeeklyStandings() { DataRow drDates = ds.Tables[0].Rows[0]; string xlsFilename; int ctr = 0; SubjectToUse = string.Format("Email Capture Contest - Week {0} ({1:MMM d}-{2:MMM d}) Results", drDates["WeekNumber"], drDates["wkFrom"], drDates["wkTo"]); xlsFilename = Path.Combine(RptSaveToFolder, string.Format("Dobbs {0:yyyy-MM MMM} Week {1} Email Contest Results.xlsx", drDates["mthTo"], drDates["WeekNumber"])); if (File.Exists(xlsFilename)) { string f0 = xlsFilename; while (File.Exists(f0)) { f0 = Path.Combine(RptSaveToFolder, string.Format("Dobbs {0:yyyy-MM MMM} Week {1} Email Contest Results - OLD{2:000}.xlsx", drDates["mthTo"], drDates["WeekNumber"], ctr)); ctr += 1; } File.Move(xlsFilename, f0); } // Standings file first using (var fs = new FileStream(Template1Path, FileMode.Open)) using (var pkg = new ExcelPackage(fs)) { ExcelWorksheet? s = null; //pkg.Workbook.Worksheets[1]; int r = 4, rTot = ds.Tables[1].Rows.Count; if (pkg.Workbook.Worksheets.Count < 1) s = pkg.Workbook.Worksheets.Add("Sheet1"); else s = pkg.Workbook.Worksheets[0]; s.Name = string.Format("{0:MMM-yyyy} Week {1} Results", drDates["mthTo"], drDates["WeekNumber"]); //s.Cells[1, 1].Value = string.Format("Email Contest Results\n{0:ddd MMM d} through {1:ddd MMM d, yyyy}", drDates["wkFrom"], drDates["wkTo"]); s.Cells[1, 1].Value = string.Format("Email Contest Results through {1:ddd MMM d, yyyy}", drDates["wkFrom"], drDates["wkTo"]); s.Cells[3, 3].Value = string.Format("Week {0}\nNew Emails", drDates["WeekNumber"]); foreach (DataRow dr in ds.Tables[1].Rows) { s.Cells[r, 1].Value = dr["Division"].ToString(); s.Cells[r, 2].Value = Convert.ToInt32(dr["StoreNumber"]); s.Cells[r, 3].Value = Convert.ToInt32(dr["NewEmails"]); s.Cells[r, 4].Value = Convert.ToInt32(dr["TransactionsGreaterThanZero"]); s.Cells[r, 5].FormulaR1C1 = "=IF(RC[-1]=0,0,RC[-2]/RC[-1])"; // Borders around each cell using (var rng = s.Cells[r, 1, r, 5]) { rng.Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin); rng.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium; rng.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium; } for (int c = 1; c <= 3; c++) s.Cells[r, c].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; s.Cells[r, 5].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Medium); // Shading if (r >= (rTot - 3 + 4)) // +4 since that's where we started { s.Cells[r, 5].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; s.Cells[r, 5].Style.Fill.BackgroundColor.SetColor(Color.Red); } else { s.Cells[r, 5].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; s.Cells[r, 5].Style.Fill.BackgroundColor.SetColor(Color.Yellow); } r++; } // Totals using (var rng = s.Cells[r, 1, r, 5]) { rng.Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin); rng.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium; rng.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium; rng.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; rng.Style.Fill.BackgroundColor.SetColor(Color.LightGray); rng.Style.Font.Bold = true; } for (int c = 1; c <= 3; c++) s.Cells[r, c].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; s.Cells[r, 5].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Medium); // s.Cells[r, 1].Value = "Totals"; s.Cells[r, 3].FormulaR1C1 = "=SUM(R4C:R[-1]C)"; s.Cells[r, 4].FormulaR1C1 = "=SUM(R4C:R[-1]C)"; s.Cells[r, 5].FormulaR1C1 = "=IF(RC[-1]=0,0,RC[-2]/RC[-1])"; r++; pkg.SaveAs(xlsFilename); FilesToAttach.Add(xlsFilename); } } private void CreateDetailSnapshots() { DataRow drDates = ds.Tables[0].Rows[0]; string xlsFilename; int ctr = 0; List cols = new() { "dtRangeHumanized;Period;@","Division;Location;@", "TotalEmails;Total Emails;#,##0;R","NewEmails;New Emails;#,##0;R","OldEmails;Old Emails;#,##0;R", "Transactions;;#,##0;R","TransactionsGreaterThanZero;Invoices Greater than Zero;#,##0;R","Penetration;Penetration Rate;0.0%;R"}; xlsFilename = Path.Combine(RptSaveToFolder, string.Format("Dobbs {0:yyyy-MM MMM} Week {1} Email Contest Detail.xlsx", drDates["mthTo"], drDates["WeekNumber"])); if (File.Exists(xlsFilename)) { string f0 = xlsFilename; while (File.Exists(f0)) { f0 = Path.Combine(RptSaveToFolder, string.Format("Dobbs {0:yyyy-MM MMM} Week {1} Email Contest Detail - OLD{2:000}.xlsx", drDates["mthTo"], drDates["WeekNumber"], ctr)); ctr += 1; } File.Move(xlsFilename, f0); } using (var fs = new FileStream(xlsFilename, FileMode.Create, FileAccess.Write, FileShare.None)) using (var pkg = new ExcelPackage(fs)) { ExcelWorksheet? s = null; for (int tbNumber = 2; tbNumber < ds.Tables.Count; tbNumber++) { var dt = ds.Tables[tbNumber]; int r = 2, c; if (dt != null && dt.Rows.Count > 0) { if (pkg.Workbook.Worksheets.Count < (tbNumber - 1)) s = pkg.Workbook.Worksheets.Add("Sheet1"); else s = pkg.Workbook.Worksheets[0]; if (tbNumber == 2) s.Name = string.Format("Month of {0:MMM-yyyy}", drDates["mthTo"]); //dt.Rows[0]["dtRangeHumanized"]); else s.Name = string.Format("Week thru {0:ddd MMM d}", dt.Rows[0]["dtTo"]); c = 0; foreach (var col in cols) { var fld = col.Split(';'); c++; if (fld.Length > 2 && !string.IsNullOrWhiteSpace(fld[2])) s.Columns[c].Style.Numberformat.Format = fld[2]; if (fld.Length > 3 && fld[3] == "R") s.Columns[c].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Right; s.Cells[1, c].Style.Numberformat.Format = "@"; s.Cells[1, c].Style.Font.Bold = true; if (fld.Length > 1 && !string.IsNullOrWhiteSpace(fld[1])) s.Cells[1, c].Value = fld[1]; else s.Cells[1, c].Value = fld[0]; if (fld.Length > 3 && fld[3] == "R") s.Cells[1, c].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Right; } foreach (DataRow dr in dt.Rows) { c = 0; foreach (var col in cols) { var fld = col.Split(';'); s.Cells[r, ++c].Value = dr[fld[0]]; } //s.Cells[r, 8].FormulaR1C1 = "=IF(RC7=0,0,RC4/RC7)"; //s.Cells[r, 8].FormulaR1C1 = "=IF(RC6-RC5=0,0,RC4/(RC6-RC5))"; s.Cells[r, 8].FormulaR1C1 = "=IF(RC[-2]-RC[-3]=0,0,RC[-4]/(RC[-2]-RC[-3]))"; r++; } // Grand Totals r++; using (var rng = s.Cells[r, 1, r, 8]) rng.Style.Font.Bold = true; s.Cells[r, 2].Value = "Totals"; for (c = 3; c <= 7; c++) { s.Cells[r, c].FormulaR1C1 = "=SUM(R2C:R[-1]C)"; } //s.Cells[r, 8].FormulaR1C1 = "=IF(RC7=0,0,RC4/RC7)"; //s.Cells[r, 8].FormulaR1C1 = "=IF(RC6-RC5=0,0,RC4/(RC6-RC5))"; s.Cells[r, 8].FormulaR1C1 = "=IF(RC[-2]-RC[-3]=0,0,RC[-4]/(RC[-2]-RC[-3]))"; s.Cells.AutoFitColumns(); s.View.FreezePanes(2, 1); s.Select("A2"); } } pkg.Save();//As(xlsFilename); FilesToAttach.Add(xlsFilename); } } private void SendEmails() { using (var em = new kmCommonLibsCore.Emails() { SendMethod = kmCommonLibsCore.enuSendMethod.OnsiteServer, Subject = SubjectToUse }) { string imgBackground, imgDisclaimer; StringBuilder s0 = new(), s1 = new(); em.AddAddress(kmCommonLibsCore.enuAddressType.From, "data@keymotive.us", "KeyMotive Data Services"); imgBackground = em.EmbedImageFile(ClsConstants.KDrive + @"\Projects\Daily Reports - COMMON\Background-Compass.jpg"); imgDisclaimer = em.EmbedImageFile(ClsConstants.KDrive + @"\Projects\Daily Reports - COMMON\KM_Disclaimer_2.png"); s0.AppendFormat("\n", imgBackground); s0.AppendLine("Please find attached your custom business report. If you have any questions regarding this report, please reply to this message or contact your account manager.

"); s0.AppendLine("Thank you for the opportunity to service the analytical needs of your organization!
"); s0.AppendLine("KeyMotive Data Services



"); s0.AppendFormat("\"\"\n", imgDisclaimer); s1.AppendFormat("Please find attached your custom business report. If you have any questions regarding this report, please reply to this message or contact your account manager.\n\n"); s1.AppendLine("Thank you for the opportunity to service the analytical needs of your organization!"); s1.AppendLine("KeyMotive Data Services"); for (byte grp = 0; grp < 3; grp++) { string ToAudience = new[] { "", "CC", "BCC" }[grp]; string KeyName = string.Format("{0} MailTo{1} {2}", BusinessName, ToAudience, ReportID.ToString()); string k0 = ClsConstants.GetCustomerRegistryItem(KeyName); if (string.IsNullOrEmpty(k0)) { KeyName = string.Format("{0} MailTo{1}", BusinessName, ToAudience); k0 = ClsConstants.GetCustomerRegistryItem(KeyName); } if (!string.IsNullOrEmpty(k0)) { var lst = ConvertToEmailAddressList(k0); foreach (var itm in lst) { switch (grp) { case 1: em.AddAddress(kmCommonLibsCore.enuAddressType.CC, itm.EmailAddress, itm.DisplayName); break; case 2: em.AddAddress(kmCommonLibsCore.enuAddressType.BCC, itm.EmailAddress, itm.DisplayName); break; default: em.AddAddress(kmCommonLibsCore.enuAddressType.To, itm.EmailAddress, itm.DisplayName); break; } } } } foreach (var itm in FilesToAttach) em.AttachFile(itm); em.HtmlBody = s0.ToString(); em.TextBody = s1.ToString(); em.Send(); } } private List ConvertToEmailAddressList(string RawAddressString) { List rv = new(); if (!string.IsNullOrWhiteSpace(RawAddressString)) { string[] k1 = RawAddressString.Split(';'); foreach (var emx in k1) { var addr = new MailAddress(emx.Trim()); rv.Add(new MdlEmailAddress() { EmailAddress = addr.Address, DisplayName = addr.DisplayName }); } } return rv; } }