This commit is contained in:
RDeck 2025-10-17 06:03:43 -04:00
parent e6d962259f
commit fb1243a519
5 changed files with 228 additions and 24 deletions

View File

@ -1,8 +1,11 @@
using System; using Microsoft.Data.SqlClient;
using Dapper;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace kmCustomReportsNET.ClassObj; namespace kmCustomReportsNET.ClassObj;
@ -22,4 +25,63 @@ public class ClsConstants
T1439 = 101 T1439 = 101
} }
static ConcurrentDictionary<string, DateTimeOffset> dctScheduler = new(StringComparer.OrdinalIgnoreCase);
internal static string GetCustomerRegistryItem(string KeyName)
{
string rv = string.Empty;
try
{
using (var cn = new SqlConnection(kmCommonLibsCore.Constants.GetCnString(kmCommonLibsCore.Constants.enuServer.RDB)))
{
var Sql = "Select [Value] From crpt.[Registry] Where [Key]=@Key And [Enabled]=1";
var parms = new { Key = KeyName };
var theValue = cn.ExecuteScalar(Sql, parms);
if (theValue != null && !string.IsNullOrWhiteSpace(theValue.ToString()))
rv = theValue?.ToString() ?? string.Empty;
}
}
catch (Exception ex)
{
kmCommonLibsCore.ClsErrorReporting.ErrorEncountered(ex);
rv = string.Empty;
}
return rv;
}
internal static void SetCustomerRegistryItem(string KeyName, string Value)
{
using (var cn = new SqlConnection(kmCommonLibsCore.Constants.GetCnString(kmCommonLibsCore.Constants.enuServer.RDB)))
{
var Sql = "Select Count(*) As Cnt From crpt.[Registry] Where [Key]=@Key And [Enabled]=1";
var parms = new { Key = KeyName };
int cnt = cn.ExecuteScalar<int>(Sql, parms);
if (cnt < 1)
Sql = "Insert Into crpt.[Registry] ([Key], [Value], [Enabled]) Values (@Key, @Value, 1)";
else
Sql = "Update crpt.[Registry] Set [Value]=@Value, [DateChanged]=SysDateTimeOffset() Where [Key]=@Key And [Enabled]=1";
cn.Execute(Sql, parms);
}
}
internal static bool NeedToRun(string TaskName)
{
bool rv = false;
if (!dctScheduler.ContainsKey(TaskName) || dctScheduler[TaskName] < DateTimeOffset.Now)
rv = true;
else
rv = false;
return rv;
}
internal static void SetNextRun(string TaskName, DateTimeOffset theTime)
{
dctScheduler[TaskName] = theTime;
}
} }

View File

@ -1,13 +1,16 @@
using Microsoft.Data.SqlClient; using log4net;
using Dapper;
using Microsoft.Data.SqlClient;
using OfficeOpenXml; using OfficeOpenXml;
using OfficeOpenXml.Export.ToDataTable;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Net.Mail;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
//using static kmCustomReportsNET.ClassObj.ClsConstants;
namespace kmCustomReportsNET.ClassObj; namespace kmCustomReportsNET.ClassObj;
@ -17,12 +20,14 @@ internal class ClsDobbsEmail_T1439 : IDisposable
public string RptSaveToFolder { get; set; } = ClsConstants.KDrive + @"\Projects\Daily Report Archive"; 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 Template1Path { get; set; } = ClsConstants.KDrive + @"\Projects\Daily Reports - Dobbs\T1439 Template 01.xlsx";
public string BusinessName { get; set; } = "DobbsTire"; public string BusinessName { get; set; } = "DobbsTire";
public ClsConstants.enuReportIDs ReportID { get; set; } = ClsConstants.enuReportIDs.T1439; public ClsConstants.enuReportIDs ReportID { get; internal set; } = ClsConstants.enuReportIDs.T1439;
public bool DebugMode { get; set; } = false; public bool DebugMode { get; set; } = false;
#region "Private Variables" #region "Private Variables"
ILog appLog = LogManager.GetLogger(Program.AppName);
DataSet? ds = null; DataSet? ds = null;
List<string> FilesToAttach = new(); List<string> FilesToAttach = new();
string SubjectToUse = string.Empty;
#endregion #endregion
public void Dispose() public void Dispose()
@ -33,28 +38,67 @@ internal class ClsDobbsEmail_T1439 : IDisposable
FilesToAttach.Clear(); FilesToAttach.Clear();
} }
internal void Go() public ClsDobbsEmail_T1439()
{ {
ExcelPackage.LicenseContext = LicenseContext.NonCommercial; ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var cn = new SqlConnection(kmCommonLibsCore.Constants.cnRDB)) }
{
cn.Open();
using (var cm = new SqlCommand("crpt.[Dobbs_T1439_EmailContests]", cn) { CommandType = CommandType.StoredProcedure, CommandTimeout = 120 }) internal void Go()
using (var da = new SqlDataAdapter(cm)) {
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))
{ {
//cm.Parameters.Add("@DateThruOverride", SqlDbType.Date).Value = DateTime.Parse("Oct 7, 2025"); // override the date thru date for testing bool? ReportDueNow = false;
ds = new DataSet();
da.Fill(ds); ReportDueNow = cn.ExecuteScalar<bool>("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);
if (ds != null && ds.Tables.Count > 2 && ds.Tables[0].Rows.Count == 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);
CreateWeeklyStandings();
CreateDetailSnapshots();
} }
} }
@ -64,6 +108,7 @@ internal class ClsDobbsEmail_T1439 : IDisposable
string xlsFilename; string xlsFilename;
int ctr = 0; 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"])); 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)) if (File.Exists(xlsFilename))
{ {
@ -260,4 +305,86 @@ internal class ClsDobbsEmail_T1439 : IDisposable
FilesToAttach.Add(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("<body background=cid:{0}>\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.<br /><br />");
s0.AppendLine("Thank you for the opportunity to service the analytical needs of your organization!<br />");
s0.AppendLine("KeyMotive Data Services<br /><br /><br /><br />");
s0.AppendFormat("<img alt=\"\" src=\"cid:{0}\" />\n</body>", 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<MdlEmailAddress> ConvertToEmailAddressList(string RawAddressString)
{
List<MdlEmailAddress> 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;
}
} }

14
Models/MdlEmailAddress.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace kmCustomReportsNET;
internal class MdlEmailAddress
{
public string EmailAddress { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
}

View File

@ -23,9 +23,10 @@ internal class Program
if (Debugger.IsAttached) if (Debugger.IsAttached)
{ {
using (var obj = new ClsDobbsEmail_T1439()) using (var obj = new ClsDobbsEmail_T1439() { DebugMode = false })
{ {
obj.Go(); obj.Go();
obj.Go();
} }
} }
else else
@ -34,7 +35,7 @@ internal class Program
{ {
x.Service<ServiceMain>(); x.Service<ServiceMain>();
x.EnableServiceRecovery(r => r.RestartService(TimeSpan.FromSeconds(15))); x.EnableServiceRecovery(r => r.RestartService(TimeSpan.FromSeconds(15)));
x.SetServiceName("kmAtomicTime2"); x.SetServiceName("kmCustomReportsNET");
x.StartAutomaticallyDelayed(); x.StartAutomaticallyDelayed();
x.SetDescription("Will run some custom reports occasionally for KeyMotive's customers."); x.SetDescription("Will run some custom reports occasionally for KeyMotive's customers.");
x.UseLog4Net(); x.UseLog4Net();

View File

@ -2,14 +2,14 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EPPlus" Version="7.7.3" /> <PackageReference Include="EPPlus" Version="7.7.3" />
<PackageReference Include="kmCommonLibsCore" Version="2.0.0.158" /> <PackageReference Include="kmCommonLibsCore" Version="2.0.0.179" />
<PackageReference Include="Topshelf" Version="4.3.0" /> <PackageReference Include="Topshelf" Version="4.3.0" />
<PackageReference Include="Topshelf.Log4Net" Version="4.3.0" /> <PackageReference Include="Topshelf.Log4Net" Version="4.3.0" />
</ItemGroup> </ItemGroup>