2025-10-17 06:03:43 -04:00
using log4net ;
using Dapper ;
using Microsoft.Data.SqlClient ;
2025-10-08 02:16:58 -04:00
using OfficeOpenXml ;
2025-10-17 06:03:43 -04:00
using OfficeOpenXml.Export.ToDataTable ;
2025-10-08 02:16:58 -04:00
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Drawing ;
using System.Linq ;
2025-10-17 06:03:43 -04:00
using System.Net.Mail ;
2025-10-08 02:16:58 -04:00
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" ;
2025-10-17 06:03:43 -04:00
public ClsConstants . enuReportIDs ReportID { get ; internal set ; } = ClsConstants . enuReportIDs . T1439 ;
2025-10-08 02:16:58 -04:00
public bool DebugMode { get ; set ; } = false ;
#region "Private Variables"
2025-10-17 06:03:43 -04:00
ILog appLog = LogManager . GetLogger ( Program . AppName ) ;
2025-10-08 02:16:58 -04:00
DataSet ? ds = null ;
List < string > FilesToAttach = new ( ) ;
2025-10-17 06:03:43 -04:00
string SubjectToUse = string . Empty ;
2025-10-08 02:16:58 -04:00
#endregion
public void Dispose ( )
{
if ( ds ! = null )
ds . Dispose ( ) ;
ds = null ;
FilesToAttach . Clear ( ) ;
}
2025-10-17 06:03:43 -04:00
public ClsDobbsEmail_T1439 ( )
2025-10-08 02:16:58 -04:00
{
ExcelPackage . LicenseContext = LicenseContext . NonCommercial ;
2025-10-17 06:03:43 -04:00
}
internal void Go ( )
{
if ( ClsConstants . NeedToRun ( ReportID . ToString ( ) ) )
2025-10-08 02:16:58 -04:00
{
2025-10-17 06:03:43 -04:00
DateTimeOffset nxtRunTime ;
2025-10-08 02:16:58 -04:00
2025-10-17 06:03:43 -04:00
appLog . DebugFormat ( "{0} report is checking to see if we need to run..." , ReportID . ToString ( ) ) ;
using ( var cn = new SqlConnection ( kmCommonLibsCore . Constants . cnRDB ) )
2025-10-08 02:16:58 -04:00
{
2025-10-17 06:03:43 -04:00
bool? ReportDueNow = false ;
2025-10-08 02:16:58 -04:00
2025-10-24 09:48:08 -04:00
ReportDueNow = DebugMode | | cn . ExecuteScalar < bool > ( "Select Top 1 [NeedToSend] From [crpt].[Dobbs_EmailContestCalendar] Where [SendReport]=@Today" , new { Today = DateTime . Today } ) ;
2025-10-17 06:03:43 -04:00
if ( ReportDueNow . HasValue & & ReportDueNow . Value )
{
cn . Open ( ) ;
2025-10-08 02:16:58 -04:00
2025-10-17 06:03:43 -04:00
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 ) ;
2025-10-08 02:16:58 -04:00
}
}
private void CreateWeeklyStandings ( )
{
DataRow drDates = ds . Tables [ 0 ] . Rows [ 0 ] ;
string xlsFilename ;
int ctr = 0 ;
2025-10-17 06:03:43 -04:00
SubjectToUse = string . Format ( "Email Capture Contest - Week {0} ({1:MMM d}-{2:MMM d}) Results" , drDates [ "WeekNumber" ] , drDates [ "wkFrom" ] , drDates [ "wkTo" ] ) ;
2025-10-08 02:16:58 -04:00
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 < string > 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 ) ;
}
}
2025-10-17 06:03:43 -04:00
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 ;
}
2025-10-08 02:16:58 -04:00
}