Files
BDF3/_Main.cs
Doug Macintosh a59a047cd1 Initial import
2026-01-04 10:55:36 -05:00

2083 lines
106 KiB
C#

#define PROD_
/*
* Created by D Macintosh
* Date: 11/14/2025
* Time: 9:32 PM
*
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;
using System.Net;
using System.Text.RegularExpressions;
using Spire.Xls;
using System.Data;
using System.Security.Principal;
using System.Linq;
using System.Globalization;
namespace bdf
{
class bdf
{
public static string product = "BDF";
public static string version = "3.2.0";
public static string fullUser = WindowsIdentity.GetCurrent().Name; // \\DOMAIN\User.Id for NTLM auth for Megatool
public static int debug = 0;
public static int mode = 1;
public static int major_errs = 0;
public static int MAX_RETRY = 3;
public static int month_offset = 1; // by default prep the bill for the upcoming bill cycle, ie end of current month is invoice date
public static int webMaxWait = 1; //max wait time in minutes for webaccess
public static bool logappend = true;
public static string logname = "logfile.txt";
public static StreamWriter outfile;
public static string domain = "RCI";
public static string username = "";
public static string password = "";
public static string dirpath = "." + Path.DirectorySeparatorChar;
public static string base_path = "." + Path.DirectorySeparatorChar;
public static Dictionary<string, string> ToDo = new Dictionary<string, string> { };
public static string token = "";
public static string filename = "output.xlsx"; //we'll change this later to be month specific
public static string InsisSuffix = "_Megatool.xlsx";
public static string overrideSuffix = "_override.txt";
public static bool reuse = false;
public static List<string> todo = new List<string> { };
public static StringBuilder adminLog = new StringBuilder();
public static StringBuilder auditLog = new StringBuilder();
public static int adlvl = 2;
/* see https://denhamcoder.net/2018/08/25/embedding-net-assemblies-inside-net-assemblies/ */ // still needs external copy during compilation!
// Loads NewtonsoftJson lib into memory as .dll
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string name = new AssemblyName(args.Name).Name;
string embname = "other";
if (name == "arial.ttf")
{
embname = "BDF.Embedded.arial.ttf";
}
else if (name == "BouncyCastle.Cryptography")
{
embname = "BDF.Embedded.BouncyCastle.Cryptography.dll";
}
else if (name == "Microsoft.Bcl.AsyncInterfaces")
{
embname = "BDF.Embedded.Microsoft.Bcl.AsyncInterfaces.dll";
}
else if (name == "Microsoft.Extensions.DependencyInjection.Abstractions")
{
embname = "BDF.Embedded.Microsoft.Extensions.DependencyInjection.Abstractions.dll";
}
else if (name == "Microsoft.Extensions.Logging.Abstractions")
{
embname = "BDF.Embedded.Microsoft.Extensions.Logging.Abstractions.dll";
}
else if (name == "Renci.SshNet")
{
embname = "BDF.Embedded.Renci.SshNet.dll";
}
else if (name == "Spire.XLS")
{
embname = "BDF.Embedded.Spire.XLS.dll";
}
else if (name == "System.Buffers")
{
embname = "BDF.Embedded.System.Buffers.dll";
}
else if (name == "System.Formats.Asn1")
{
embname = "BDF.Embedded.System.Formats.Asn1.dll";
}
else if (name == "System.Memory")
{
embname = "BDF.Embedded.System.Memory.dll";
}
else if (name == "System.Numerics.Vectors")
{
embname = "BDF.Embedded.System.Numerics.Vectors.dll";
}
else if (name == "System.Runtime.CompilerServices.Unsafe")
{
embname = "BDF.Embedded.System.Runtime.CompilerServices.Unsafe.dll";
}
else if (name == "System.Threading.Tasks.Extensions")
{
embname = "BDF.Embedded.System.Threading.Tasks.Extensions.dll";
}
else if (name == "System.ValueTuple")
{
embname = "BDF.Embedded.System.ValueTuple.dll";
}
else if (name == "template.xlsx")
{
embname = "BDF.Embedded.template.xlsx";
}
// private_nopassphr.ppk
else if (name == "private_nopassphr.ppk")
{
embname = "BDF.Embedded.private_nopassphr.ppk";
}
else
{
Logger.Log(0, "!! ERROR missing assy: {0}", name);
throw new Exception("Missing critical library or dll file.");
//embname = "something_bad";
}
Logger.Log(4, "returning assy: {0}", name);
try
{
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embname))
{
var assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
catch (Exception e)
{
Logger.Log(0, "EXCemb: {0}:{1}.", e.Message, e.InnerException.Message);
return null;
}
}
public static void Main(string[] args)
{
// Load Embedded Resources
try
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
catch (Exception e)
{
Logger.Log(0, "DLL: {0}:{1}.", e.Message, e.InnerException.Message);
}
//foreach (var resource in Assembly.GetExecutingAssembly().GetManifestResourceNames()) Console.WriteLine("Resource: " + resource);
Main2(args);
}
public static async void Main2(string[] args)
{
// Clears 'async' compiler error
await System.Threading.Tasks.Task.CompletedTask;
// Enforce TLS1.2 Sep2017
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192;
// Logging file
outfile = new StreamWriter(@"" + logname, logappend);
outfile.AutoFlush = true;
//EFT Upload Credentials
sftp.ConnectionDetails sshDetails = new sftp.ConnectionDetails
{
host = "dev.mft.rogers.com",
ppkFile = "BDF.Embedded.private_passphr.ppk", //Add "BDR.Embedded." to filename if embedded
passPhrase = "Rogers1!",
username = "DEV_APP_BDF",
password = "DEV_APP_BDF"
};
string ban2 = product + " v" + version + " (c) 2025 Doug Macintosh";
ban2 = "\u2551 " + ban2 + " \u2551";
string ban1 = "\u2554";
for (int i = 2; i < ban2.Length; i++) { ban1 += "\u2550"; }
ban1 += "\u2557";
string ban3 = "\u255a";
for (int i = 2; i < ban2.Length; i++) { ban3 += "\u2550"; }
ban3 += "\u255d";
Logger.Log(ban1); Logger.Log(ban2); Logger.Log(ban3);
Logger.Log("--- call (613)697-9178 for support ---");
Arguments myargs = new Arguments(args);
CookieContainer cookiejar = new CookieContainer();
if (myargs.Exists("help") || myargs.Exists("h"))
{
// Environment.GetCommandLineArgs() or Environment.ProcessPath. You can then use System.IO.Path.GetFileName(Environment.GetCommandLineArgs());
Logger.Log(" usage: " + System.IO.Path.GetFileName(Environment.GetCommandLineArgs()[0]) + " [-options]");
//Console.WriteLine("retry: -retries n");
//Logger.Log("--- UNLICENSED, FOR EVALUATION USE ONLY ---");
Logger.Log(" login: -u user -p passwd");
Logger.Log(" detail files: -all OR any combo of -ldf -wav -sip");
Logger.Log(" output path: -path " + (Path.DirectorySeparatorChar.ToString() == "\\" ? "C:" : "") + "/directory/subdir");
Logger.Log(" SO basepath: -so C:\\Users\\us.er\\OneDrive\\path\\");
Logger.Log(" subdirs: -ldfdir .\\LDF\\ | -wavdir .\\WAV\\ | -sipdir .\\SIP\\");
Logger.Log(" inv offset: -month=x [x = +/- 6, default is coming bill cycle, ie '1']");
Logger.Log(" reuse: -reuse");
Logger.Log(" redo: -redo");
Logger.Log(" verbose: -v");
//Logger.Log(" debug: -debug n");
return;
}
//WebProxy proxyObject = null;
if (myargs.Exists("debug"))
{
debug = int.Parse(myargs.Single("debug"));
Logger.Log(5, "Setting debug level to {0}", debug);
}
if (myargs.Exists("v"))
{
debug += 1;
Logger.Log(0, "Logging verbosity increased.");
}
// Start User cred
{
if (!fullUser.StartsWith("RCI"))
{
Logger.Log(0, "Your current userid ({0}) must be a member of RCI to proceed.", fullUser);
if ( (debug < 2) && !(fullUser == "doug"))
{
return;
}
else username = fullUser;
}
else
{
domain = fullUser.Split('\\')[0];
username = fullUser.Split('\\')[1];
Logger.Log(4, "Using credentials for ({0})", username);
}
if ((myargs.Exists("u")) && (myargs.Exists("p")))
{
username = myargs.Single("u");
password = myargs.Single("p");
Logger.Log(5, "Setting authorized account to: {0}", username);
}
else if (myargs.Exists("p"))
{
password = myargs.Single("p");
Logger.Log(5, "Setting password for {0}", username);
}
}
// end User cred
// SO Type defs below
{
if (myargs.Exists("all"))
{
todo.Add("LDF");
todo.Add("WAV");
todo.Add("SIP");
}
if (myargs.Exists("ldf"))
{
todo.Add("LDF");
}
if (myargs.Exists("wav"))
{
todo.Add("WAV");
}
if (myargs.Exists("sip"))
{
todo.Add("SIP");
}
if (todo.Count == 0)
{
todo.Add("LDF"); // default
}
string todos = "";
foreach (string t in todo)
{
todos += t + " ";
}
Logger.Log(0, "Generating Bill Detail files for: {0}", todos);
if (myargs.Exists("so"))
{
if (myargs.Single("so") != "") base_path = myargs.Single("so");
if (!base_path.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
base_path += Path.DirectorySeparatorChar.ToString();
}
}
else
{
base_path = "C:\\Users\\" + username +
"\\OneDrive - Rogers Communications Inc\\Jeff Hawthorne's files - GCNS Stream 5 - Dark Fibre - Billing BDF Files\\";
}
Logger.Log(1, "SO Base Path: {0}", base_path);
}
ToDo["LDFprefix"] = "GCNSLDF";
ToDo["WAVprefix"] = "GCNSWAV";
ToDo["SIPprefix"] = "SSCGPAS";
ToDo["LDFpath"] = "." + Path.DirectorySeparatorChar + "Dark Fibre Service Orders" + Path.DirectorySeparatorChar;
ToDo["WAVpath"] = "." + Path.DirectorySeparatorChar + "Wavelength Service Orders" + Path.DirectorySeparatorChar;
ToDo["SIPpath"] = "." + Path.DirectorySeparatorChar + "SIP Service Orders" + Path.DirectorySeparatorChar;
{
if (myargs.Exists("ldfdir"))
{
if (myargs.Single("ldfdir") != "") ToDo["LDFpath"] = myargs.Single("ldfdir"); ;
if (!ToDo["LDFpath"].EndsWith(Path.DirectorySeparatorChar.ToString()))
{
ToDo["LDFpath"] += Path.DirectorySeparatorChar.ToString();
}
}
if (todo.Contains("LDF"))
Logger.Log(0, " LDF SO files expected in sub-directory: {0}", ToDo["LDFpath"]);
if (myargs.Exists("wavdir"))
{
if (myargs.Single("wavdir") != "") ToDo["WAVpath"] = myargs.Single("wavdir"); ;
if (!ToDo["WAVpath"].EndsWith(Path.DirectorySeparatorChar.ToString()))
{
ToDo["WAVpath"] += Path.DirectorySeparatorChar.ToString();
}
}
if (todo.Contains("WAV"))
Logger.Log(0, " WAV SO files expected in sub-directory: {0}", ToDo["WAVpath"]);
if (myargs.Exists("sipdir"))
{
if (myargs.Single("sipdir") != "") ToDo["SIPpath"] = myargs.Single("sipdir"); ;
if (!ToDo["SIPpath"].EndsWith(Path.DirectorySeparatorChar.ToString()))
{
ToDo["SIPpath"] += Path.DirectorySeparatorChar.ToString();
}
}
if (todo.Contains("SIP"))
Logger.Log(0, " SIP SO files expected in sub-directory: {0}", ToDo["SIPpath"]);
}
//end SO Type defs
if (myargs.Exists("path"))
{
dirpath = myargs.Single("path");
if (dirpath == "") dirpath = ".";
if (!dirpath.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
dirpath += Path.DirectorySeparatorChar.ToString();
}
}
else
{
dirpath = "." + Path.DirectorySeparatorChar.ToString();
}
Logger.Log(5, "Setting filestore root path to {0}", dirpath);
if ((username == "") && !reuse)
{
Logger.Log(0, "No valid login credentials found. Exiting.");
return;
}
if (myargs.Exists("month"))
{
// if (myargs.Exists("1")) offset = -1;
int offset = Int32.Parse(myargs.Single("month"));
if ((offset >= -6) && (offset <= 12))
month_offset = offset;
}
// ***MAIN -------------------------------------------------------------------------------------------------------------------------------
/*
byte[] data = System.IO.File.ReadAllBytes(@"./arial.ttf");
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(data) )
{
//sftp.Upload_stream_ppk(ms, "arial3.ttf", "dev.mft.rogers.com", 22, "DEV_APP_BDF");
if ( sftp.serverExists(sshDetails.host))
sftp.Upload_Stream(ms, "arial7.ttf", sshDetails);
}
//sshDetails.ppkFile = "";
byte[] data = System.IO.File.ReadAllBytes(@"./arial.ttf");
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(data))
{
if (sftp.serverExists(sshDetails.host))
sftp.Upload_Stream(ms, "arial_11.ttf", sshDetails);
//sftp.Upload_stream_old(ms, "arial8.ttf", details.host, details.port, details.username, details.password);
}
return;
*/
/*----------------------------
Dictionary<string, string> data = new Dictionary<string, string>
{
{ "Item", "001" },
{ "Code", "ACH" },
{ "Description", "Monthly Service" },
{ "Qty", "2" },
{ "Amount", "100.00" }
};
MegaT.SIPData tt = MegaT.ExtractSIPData("<td nowrap=\"nowrap\" class=\"heading\" width=\"20%\">Code</td>\n \n <td class=\"value\"><input type=\"text\" class=\"tbLongReadonly\" readonly=\"readonly\" value=\"ACH\" /></td>\n </tr> ");
Console.WriteLine("Code = {0}", tt.Code);
return;
*/
bool LoggedIn = false; // are we authenticated to Megatool?
foreach (string task in todo) // tasks are some combination of LDF/WAV/SIP
{
Logger.Log(0, "==================================>>>");
Logger.Log(0, "Starting to process the {0} BDF...", task);
// ***SO Files -------------------------------------------------------------------------------------------------------------------------------
//Load and convert all XLS? files that start with 'ROGERS_(task)_SO*' in the (task) subdirectory
//#CXLFile.getXLS(task, (base_path + ToDo[(task + "path")]));
//#Logger.Log(0, "{0} Service Order Workbooks returned.", CXLFile.ServiceOrders.Count);
CXLFile.S_getXLS(task, (base_path + ToDo[(task + "path")]));
Logger.Log(0, "{0} Service Order Workbooks returned.", CXLFile.S_ServiceOrders.Count);
// ***Megatool -------------------------------------------------------------------------------------------------------------------------------
if (myargs.Exists("redo"))
{
if (System.IO.File.Exists(dirpath + Path.DirectorySeparatorChar + task + InsisSuffix))
{
if (!SafeDeleteFile(dirpath + Path.DirectorySeparatorChar + task + InsisSuffix))
{
Logger.Log(0, "Unable to delete existing {0}, is it open in Excel?", task + InsisSuffix);
reuse = false;
// User interaction to abort?
}
else
{
Logger.Log(1, " -deleted existing {0} intermediate file.", task + InsisSuffix);
}
}
}
if (myargs.Exists("reuse"))
{
if (!System.IO.File.Exists(dirpath + Path.DirectorySeparatorChar + task + InsisSuffix))
{
Logger.Log(0, "Did not find an existing {0} Forcing rebuild...", task + InsisSuffix);
reuse = false;
}
else { reuse = true; }
}
// Megatool subsection, gets mapping between SO's and SCHEDA's, create "(task)_Megatool.xlsx"
//#var wbk = new XLWorkbook();
var wbk = new Spire.Xls.Workbook();
// Add a worksheet
//#var insisMap = wbk.AddWorksheet(task+InsisSuffix.Split('.')[0]); // add empty worksheet 'InsisMap'
var insisMap = wbk.CreateEmptySheet(task + InsisSuffix.Split('.')[0]); // add empty worksheet 'InsisMap'
BDF.cleanSheets(ref wbk); // get rid of the 3 default sheets
string path = dirpath + task + InsisSuffix;
//If less than 24h old, or -reuse switch used, use an existing map file
if ((System.IO.File.Exists(path)) && (System.IO.File.GetLastWriteTime(path).DayOfYear == DateTime.Today.DayOfYear)
|| reuse)
{
try
{
Logger.Log(0, "Loading previous Megatool mapping file ({0})...", path);
//#wbk = new XLWorkbook(path);
//wbk = new Spire.Xls.Workbook();
wbk.LoadFromFile(path);
Logger.Log(3, "Megatool mapping file has {0} entries.", wbk.Worksheets[0].LastRow - 1);
}
catch
{
Logger.Log(0, "Please verify you do not have ({0}) open in Excel and retry.", path);
return;
}
}
else
{
if (!LoggedIn) //authenticate to Megatool
{
int tries = 1;
// Megatool login procedure
do
{
Logger.Log(0, "Initiating connection...");
tries++;
Logger.Log("** Password is required to access Megatool. You must be on the Corporate Lan/VPN.**");
while (password == "")
{
Logger.Log(0, "Please enter the password for ({0}) and hit Return.", fullUser);
password = ReadPassword();
}
try
{
LoggedIn = MegaT.Auth(username, password, ref cookiejar);
if (!LoggedIn) { Logger.Log(1, " retrying {0}", tries); }
}
catch (Exception)
{
Logger.Log("Exception attempting to login to MegaTool");
if (!LoggedIn) { Logger.Log(1, " retrying {0}", tries); }
}
}
while (!LoggedIn && (tries <= MAX_RETRY));
if (!LoggedIn)
{
Logger.Log("Exiting due to inability to login to MegaTool website");
return;
}
}
// Build TA->SO Dictionary
Dictionary<string, string> ta = new Dictionary<string, string> { };
//#foreach (XLWorkbook wb in CXLFile.ServiceOrders) // List of XL workbooks passed from XLImport
foreach (Spire.Xls.Workbook wb in CXLFile.S_ServiceOrders) // List of XL workbooks passed from XLImport
{
Spire.Xls.Worksheet ws1 = wb.Worksheets[0]; //generic 1st worksheet
Spire.Xls.Worksheet ws2 = wb.Worksheets[1]; //generic 2nd worksheet
string _so = ws2[2, 1].Value.ToString(); // This is our SO#
//#string CCI = (string)ws1.Cell("G2").Value.ToString(); // R000XXXXXX
string CCI = ws1[2, 7].Value.ToString(); // R000XXXXXX or K000 for SIP? -
// also CCIs are different, one overarching for all LDF/WAV/SIP plus one for indiv SO
//Format CCI as R + 9 digits, left zero padded
string _cci = CCI;
_cci = ("000000000" + Int32.Parse(_cci.Substring(1)));
CCI = CCI.Substring(0, 1) + _cci.Substring(_cci.Length - 9); // Preserve R/K+000123456
try
{
//Console.WriteLine("{0}:{1}", CCI, _so);
if ( !ta.ContainsKey(CCI))
ta.Add(CCI, _so);
}
catch (Exception e)
{
Logger.Log(0,"SO-TA table mapping error. {0}", e.Message);
}
}
Logger.Log(1, "Added {0} TA->SO mappings", ta.Count);
// ***SCHED Files -------------------------------------------------------------------------------------------------------------------------------
List<string> active = new List<string> { };
Dictionary<string, double> sch2mrr = new Dictionary<string, double> { };
List<string> scheds = new List<string> { };
// GET ALL GCNSLDFXXX SCHEDS FROM INSIS
MegaT.GetSchedAs( ToDo[(task+"prefix")], ref scheds, ref cookiejar);
Logger.Log(1, "Found {0} candidate {1} SCHEDAs", scheds.Count, ToDo[(task + "prefix")] );
// FILTER OUT ALL XL/DISCONNECTED SCHEDS
foreach (string sched in scheds)
{
bool inactive = MegaT.SchedXL(sched, ref cookiejar);
if (!inactive)
{
active.Add(sched);
sch2mrr.Add(sched, MegaT.getMRR(sched, ref cookiejar)); // for each active SCH, get current MRR from main page
}
else
{
Logger.Log(5, " {0} ({1})", sched, inactive ? "inactive" : "active");
}
}
Logger.Log(0, "Found {0} active {1}xxx SCHEDAs", active.Count, ToDo[(task + "prefix")]);
if (active.Count == 0) // no valid SCHEDs so we're done here!
{
Logger.Log(0, "ERROR: No active {0} SCHEDAs found. Exiting as no point proceding further.", task);
return;
}
// -------------------------------------
// OBTAIN DETAIL INFORMATION FOR ALL ACTIVE SCHEDS FROM 'SCHEDULE', SO MOST IMPORTANT, BUT GRAB CONTRACT, TA ETC AS NEEDED
var dt = new DataTable();
// Create intermediate file columns based on dictionary keys coming from GetParms
/*
dt.Columns.Add("SO", typeof(String));
dt.Columns.Add("TA", typeof(String));
dt.Columns.Add("COP", typeof(String));
dt.Columns.Add("PRID", typeof(String));
dt.Columns.Add("CONTRACT", typeof(String));
dt.Columns.Add("SCHED", typeof(String)); // Cell(6) SCHED
dt.Columns.Add("BSD", typeof(String)); // Cell(7) BSD
dt.Columns.Add("MRR", typeof(String)); // Cell(8) MRR
dt.Columns.Add("NRC", typeof(String)); // Cell(9) NRC
//added for SIP Access and Session cost/qty
dt.Columns.Add("AQty", typeof(String));
dt.Columns.Add("ACst", typeof(String));
dt.Columns.Add("SQty", typeof(String));
dt.Columns.Add("SCst", typeof(String));
*/
// Build our dictionary with a dummy call for parms, this is extensible for coding, we can add/remove parms as needed
foreach ( var k in MegaT.GetParms("dummy", ref cookiejar))
{
dt.Columns.Add( k.Key, typeof(String) ); // order of entry is important when referencing by row/cell
//Console.WriteLine("Adding: " + k.Key);
}
if (task == "SIP")
{
dt.Columns.Add("AQty", typeof(String));
dt.Columns.Add("ACst", typeof(String));
dt.Columns.Add("SQty", typeof(String));
dt.Columns.Add("SCst", typeof(String));
}
List<string> so_found = new List<string> { };
// Look for override data in [TASK]_override.txt
//Dictionary<string, string> overrides = getOverrides(task); //using SCHED as key, not SO
Dictionary<string, string> overrides = getOverrides_so(task); //using SCHED as key, not SO
foreach (string sched in active)
{
Dictionary<string, string> parms = MegaT.GetParms(sched, ref cookiejar); // scrape megatool for current SCHEDA
// Create a new row
var row = dt.NewRow();
row["SCHED"] = sched;
// Fill row with dictionary values
foreach (var kvp in parms)
{
//Console.WriteLine(" * s={0} p={1} v={2}", sched, kvp.Key, kvp.Value);
if (kvp.Value.Length >= 3)
{
if ((kvp.Value.Substring(0, 3)) == "R00")
{
row["TA"] = kvp.Value ?? "";
}
else if ((kvp.Value.Substring(0, 3)) == "K00")
{
row["CONTRACT"] = kvp.Value ?? "";
}
else
{
row[kvp.Key] = kvp.Value ?? "";
}
if (kvp.Key.Equals("SO")) so_found.Add(kvp.Value); // track these to see if we need to add unmatched SO's to megatool file
}
else
{
row[kvp.Key] = kvp.Value ?? "";
}
}
//Console.WriteLine("c r:{0} s:{1}+", row["MRR"], sched);
//Try to fix bad SCHED<->SO mappings
string value = "ZZZ";
string my_so = (string)row["SO"];
string my_ta = (string)row["TA"];
if (my_so == "XXX")
{
row["SO"] = ta.TryGetValue(my_ta, out value) ? value : "XxX";
Logger.Log(1, "Fixed {0}->{1} using TA={2}", (string)row["SO"], (string)row["SCHED"], (string)row["TA"]);
so_found.Add(value);
}
//else Logger.Log(0, "Unable to fix {0}->{1} mapping because of TA={2} != ROW_TA{3}", (string)row["SCHED"], (string)row["SO"], value, (string)row["TA"]);
// SIP parameters based on SCHEDs
if (task == "SIP")
{
//List <MegaT.SIPData> sipInfo = MegaT.GetSIPDetails(sched, ref cookiejar);
List<MegaT.SIPData> sipInfo = MegaT.GetSIPDetails_bySCHED(sched, ref cookiejar);
double sQty = 0;
double sCst = 0;
double aQty = 0;
double aCst = 0;
row["AQty"] = row["ACst"] = row["SQty"] = row["SCst"] = "XXX";
foreach (var s in sipInfo)
{
row["BSD"] = MegaT.ConvertDate(s.StartDate);
//Logger.Log(5, " {0} {1}",sched, s.ToString());
if ( string.Equals(s.Code.ToString(), "ACH", StringComparison.OrdinalIgnoreCase))
{
Logger.Log(2, "Found Access: {0} x {1}", s.UnitPrice, s.Quantity);
aQty += 1;
aCst = Convert.ToDouble(s.UnitPrice);
row["AQty"] = aQty.ToString();
row["ACst"] = s.UnitPrice;
}
if (string.Equals(s.Code.ToString(), "VSS", StringComparison.OrdinalIgnoreCase))
{
sQty += Int32.Parse(s.Quantity);
sCst = Convert.ToDouble(s.UnitPrice);
row["SQty"] = sQty.ToString(); // handle multiple session Adds
row["SCst"] = s.UnitPrice;
Logger.Log(2, "Found Sessions: {0} x {1}, Total Qty Found {2}", s.UnitPrice, s.Quantity, sQty);
}
}
Logger.Log(1, "{0} : Access ${1} Sessions${2} ",sched, aQty*aCst, sQty*sCst);
}
//CHECKs for delta between Schedule Details and main page
if (sch2mrr[sched] != 0)
{
if ((row["MRR"].ToString() != "XXX") && (Double.Parse(row["MRR"].ToString()) != sch2mrr[sched]))
{
Logger.Log(0, " -MRR discrepancy for {2} between SchedA {0} and Schedule {1} MRRs", sch2mrr[sched], row["MRR"], sched);
}
row["MRR"] = sch2mrr[sched];
}
// overrides used to be here
dt.Rows.Add(row);
} // end of foreach SCHED
//ADD lines for any missing SO's/SO's not mapped to a Sched, such as would happen with 2 x SO per SCHED in SIP
//scan through S_ServiceOrders, check ws2(2,1)=SO is present in dt, if not, add new row with SO defined
Logger.Log(0, "Validating {0} SOs", so_found.Count);
try
{
foreach (Spire.Xls.Workbook SOS in CXLFile.S_ServiceOrders)
{
Worksheet s2 = SOS.Worksheets[1]; //generic 2nd worksheet
string s = s2[2, 1].Value.ToString(); // This is our SO#
if (RemoveStringKey(so_found, s)) // if megatool found the SO remove it from the manual adds
Logger.Log(1, " Removed {0}", s);
else
{
Logger.Log(0, " Inserted {0}", s);
var orphan_row = dt.NewRow(); // we need valid values for SO, and dummies for SCHED(6), NRC(9), AQty(10), SQty(12)
orphan_row["SO"] = s;
orphan_row["SCHED"] = "UNKNOWN";
orphan_row["BSD"] = "XXX";
orphan_row["MRR"] = "XXX";
orphan_row["NRC"] = "XXX";
if (task == "SIP")
{
orphan_row["AQty"] = "XXX";
orphan_row["SQty"] = "XXX";
}
dt.Rows.Add(orphan_row);
}
}
foreach (string _s in so_found)
{
Logger.Log(1, " Orphan {0}", _s);
}
}
catch (Exception e)
{
Logger.Log(0, "Issue finding orphan SOs ({0}:{1})", e.Message, e.InnerException.Message);
return;
}
//We have to do overrides after the manual adds
//Loop through Megatool sheet and replace as needed
try
{
foreach (DataRow row in dt.Rows)
{
// Skip deleted or detached rows
if (row.RowState == DataRowState.Deleted ||
row.RowState == DataRowState.Detached)
continue;
string so = row[0]?.ToString();
foreach (DataColumn column in dt.Columns)
{
string ivalue = "";
/*
if (overrides.ContainsKey(parms["SCHED"] + kvp.Key))
//if (overrides.TryGetValue(parms["SO"] + kvp.Key, out ivalue)) { } // key not found, move on
{
ivalue = overrides[(parms["SCHED"] + kvp.Key)];
Logger.Log(0, " >REPLACE {0}-{1} (was:{2} now:{3})", parms["SCHED"], kvp.Key, kvp.Value, ivalue);
row[kvp.Key] = ivalue;
}
*/
if (overrides.ContainsKey(so + column.ColumnName))
//if (overrides.TryGetValue(parms["SO"] + kvp.Key, out ivalue)) { } // key not found, move on
{
ivalue = overrides[(so + column.ColumnName)];
Logger.Log(0, " >REPLACE {0}-{1} (was:{2} now:{3})", so, column.ColumnName, row[column], ivalue);
row[column] = ivalue;
}
}
}
}
catch (Exception e)
{
Logger.Log(0, "Issue applying overrides to SOs ({0}:{1})", e.Message, e.InnerException.Message);
return;
}
// Now dump out the INSIS data into the intermediate file
//using (var wb = new XLWorkbook())
{
// Insert the DataTable starting at cell A1
//#insisMap.Cell(1, 1).InsertTable(dt);
insisMap.InsertDataTable(dt, true, 1, 1);
//#insisMap.Columns().AdjustToContents();
insisMap.AllocatedRange.AutoFitColumns();
//ws.RangeUsed().Sort("A");
//#var used = insisMap.RangeUsed();
var used = insisMap.AllocatedRange;
// Define a range that excludes the header row (row 1)
//#var dataRange = used.Range(2, 1, used.RowCount(), used.ColumnCount());
//used.UpdateRange(2, 1, used.RowCount, used.ColumnCount);
// Sort by column A inside that range (currently SO, thinking SCHED is a better idea)
//#used.Sort("A");
// Create sort fields
// Create sort settings
wbk.DataSorter.SortColumns.Add(0, SortComparsionType.Values, OrderBy.Ascending); //sorts = new SortColumns();
// Column index 0 = first column inside sortRange = Column A
//sorts.Add(sortRange, 0, OrderBy.Ascending);
// Perform the sort
//sheet.Sort(sortRange, sorts);
wbk.DataSorter.Sort(used);
// Apply AutoFilter to the header row (row 1)
//Spire.Xls.Core.IXLSRange range = sheet.Range[1, 1, lastRow, lastCol];
wbk.Worksheets[0].AutoFilters.Range = used;
wbk.Worksheets[0].AutoFilters.Filter();
//Apply Table formatting
BDF.TableFormatter.ApplyTableFormat(used);
// Save to file (_Megatool mapping)
try
{
//#wbk.SaveAs(path);
wbk.SaveToFile(path, ExcelVersion.Version2016);
}
catch
{
Logger.Log(0, "Ensure you do not have ({0}) already open!", path);
return;
}
}
}
// wbk is the Megatool worksheet
// *** -------------------------------------------------------------------------------------------------------------------------------
//Date string 202511
DateTime d = DateTime.Now;
//string CurrentYearMonth = d.ToString("yyyyMM");
int current = Int32.Parse(d.AddMonths(month_offset).ToString("yyyyMM"));
string monthAbbreviation = d.AddMonths(month_offset).ToString(" MMM", new CultureInfo("en-US")); // for Type X tabs
// Go to the first day of this month, then subtract 1 day
DateTime lastDayPrevMonth = new DateTime(d.Year, d.Month, 1).AddMonths(month_offset).AddDays(-1);
// Format as yyyymmdd
string invDate = lastDayPrevMonth.ToString("yyyyMMdd");
//string effDate = (new DateTime(d.Year, d.Month, 1)).ToString("yyyyMMdd");
Logger.Log(0, "Beginning actual BDF processing ({0})", current);
bdf.filename = "BDF_" + task + "_" + current.ToString() + ".xlsx";
// BDF Workbook - create the correct format based on task
//#var workbook = BDF.CreateBDF(task);
var workbook = BDF.S_CreateBDF(task);
// bdf2 is link to 2nd Tab with the individual connection details, all sheets have Type 2
//#var bdf2 = workbook.Worksheet(2);
var bdf2 = workbook.Worksheets[1]; // or use string name, 0-based index
bdf2.Name += monthAbbreviation;
//var bdf2 = workbook.Worksheets["BDF Type 2"]; // or use string name
//var bdf2 = workbook.Worksheet("BDF Type 2");
//workbook.SaveToFile("_stepped.xlsx", ExcelVersion.Version2013);
// make an empty list of type BDF.Rows to be added to BDF worksheet#2 at end
// Type 2 is common across all 3 task types, but last row not used for SIP
var rows = new List<Row> { }; // Type 2 rows to add to sheet, currently only 1 for DF/WAV plus one more for Builds. SIP will have 3
try
{
//Process each line in each SO for unique SOs -- UPDATED TO ONLY DO 1 LINE PER SO FILE plus a BUILD line if present
int k = 1;
//#foreach (XLWorkbook wb in CXLFile.ServiceOrders) // List of XL workbooks passed from XLImport
foreach (Spire.Xls.Workbook wb in CXLFile.S_ServiceOrders) // List of XL workbooks passed from XLImport
{
// Two tabs, LDF specific details below
// /1.LDFONS_Service_Order_V2 and
// 2.LDFONS_SDP_data_V2
//IXLWorksheet ws1 = wb.Worksheet("LDFONS_Service_Order_V2");
//#IXLWorksheet ws1 = wb.Worksheet(1); //generic 1st worksheet
Spire.Xls.Worksheet ws1 = wb.Worksheets[0]; //generic 1st worksheet
//IXLWorksheet ws2 = wb.Worksheet("LDFONS_SDP_data_V2");
Spire.Xls.Worksheet ws2 = wb.Worksheets[1]; //generic 2nd worksheet
//string _so = ws2.Cell("A2").Value.ToString(); // This is our SO#
//string _so = ws2.GetStringValue(2, 1); // Cell("A2").Value.ToString(); // This is our SO#
string _so = ws2[2, 1].Value.ToString(); // This is our SO#
//#Logger.Log(1, "Ingesting {0} ({1}/{2})...", _so, k++, CXLFile.ServiceOrders.Count);
Logger.Log(1, "Ingesting {0} ({1}/{2})...", _so, k++, CXLFile.S_ServiceOrders.Count);
List<string> sos = new List<string> { }; //UPDATED USE 1 entry per SO found, expect 1 SO per file
//#string C = ws1.Cell("A2").Value.ToString(); //ROGERS
string C = ws1[2, 1].Value.ToString(); //ROGERS
//#string CCI = (string)ws1.Cell("G2").Value.ToString(); // R000XXXXXX
string CCI = ws1[2, 7].Value.ToString(); // R000XXXXXX or K000 for SIP? -
// also CCIs are different, one overarching for all LDF/WAV/SIP plus one for indiv SO
//Format CCI as R + 9 digits, left zero padded
string _cci = CCI;
_cci = ("000000000" + Int32.Parse(_cci.Substring(1)));
CCI = CCI.Substring(0,1) + _cci.Substring(_cci.Length - 9); // Preserve R/K+000123456
//#var _rows = wbk.Worksheet(task+InsisSuffix.Split('.')[0]).RangeUsed().RowsUsed(); // _Megatool intermediate sheet
//var _rows = wbk.Worksheets[task + InsisSuffix.Split('.')[0]].AllocatedRange; // .RangeUsed().RowsUsed(); // _Megatool intermediate sheet
//int RowMax = 1;
bool SIP = (task == "SIP");
//RowMax = SIP ? 3 : 1; // 3 if SIP, 1 if other
// All rows of the Megatool intermediate // todo remove header row from searches
var _rows = wbk.Worksheets[0].AllocatedRange.Rows; // .RangeUsed().RowsUsed(); // _Megatool intermediate sheet
//#foreach (var row in ws2.RowsUsed()) // go through Tab#2 of SO
foreach (var row in ws2.AllocatedRange.Rows) // Rows.ToArray() ) // go through Tab#2 of SO
{
if (row.Row == 1) continue;
//Console.WriteLine("a1 <{2}> ({3}) row{0} of {1}", row.Row, ws2.AllocatedRange.LastRow, ws2.GetNumber(row.Row, 1), 0);
if ( double.IsNaN(ws2.GetNumber(row.Row, 1)) ) break; // if there are blank lines in the SO then quit!
var r = new Row { Row_Number = (rows.Count + 1), Contractor = C }; //this needs to be the SO's CCI, so tab2
var r_nrc = BDF.CopyRow(r); // spare row if onetime found
string scid = ws2.GetStringValue(row.Row, SIP ? 26 : 28);
bool processRow = ( ( task != "SIP") && scid.Contains("Segment")) ||
( ( task == "SIP" ) && ( scid.Contains("NAP") || scid.Contains("SAP") || scid.Contains("DID") ) ); // these are billable lines
Logger.Log(5, "SCID:{0}:{1}", scid, rows.Count);
if ( (row.Row > 1) && processRow )
{
r.Canada_Contract_Identifier = CCI; //from tab1
//#r.SSC_Order_Number = Int32.Parse(ws2.Cell("A" + row.RowNumber()).Value.ToString());
r.SSC_Order_Number = (Int32)(ws2.GetNumber(row.Row, 1));
//#r.SSC_Version = (Int32)ws2.Cell("B" + row.RowNumber()).Value;
r.SSC_Version = (Int32)ws2.GetNumber(row.Row, 2);
r.Quantity = (Int32)ws2.GetNumber(row.Row, SIP ? 24 : 26);
//#r.SDPID = ws2.Cell("S" + row.RowNumber()).Value.ToString();
r.SDPID = ws2.GetStringValue(row.Row, SIP ? 18 : 19);
//#r.Department = ws2.Cell("F" + row.RowNumber()).Value.ToString();
r.Department = ws2.GetStringValue(row.Row, 6);
//#r.Prov = ws2.Cell("AQ" + row.RowNumber()).Value.ToString();
r.Prov = ws2.GetStringValue(row.Row, SIP ? 39 : 43);
//r.Billing_End_Date = Int32.Parse(ws2.Cell("M" + row.RowNumber()).Value.ToString().Replace("/", ""));
r.Billing_End_Date = Int32.Parse(ws2.GetStringValue(row.Row, 13).Replace("/", ""));
//#r.SCID = ws2.Cell("AB" + row.RowNumber()).Value.ToString();
r.SCID = ws2.GetStringValue(row.Row, SIP ? 26 : 28);
//#r.TCID = ws2.Cell("AF" + row.RowNumber()).Value.ToString();
r.TCID = ws2.GetStringValue(row.Row, SIP ? 29 : 32);
r.TA_Number = CCI;
r.Invoice_Period = current;
r.Period_of_Service = current;
if (SIP)
{
r.PO_Number = CCI;
r.TA_Number = "";
}
else
{
r.TA_Number = CCI;
}
//Add in Megatool and maybe EWP? data like SCHEDA
//Get matching InsisMap row#
//int i = 0;
int so_row = 0;
int r0_row = 0;
//#int max = wbk.Worksheet(task + InsisSuffix.Split('.')[0]).RowsUsed().Count();
//int max = wbk.Worksheets[task + InsisSuffix.Split('.')[0]].Rows.Length;
int max = wbk.Worksheets[0].Rows.Length;
//#IXLRangeRow _srow = null;
CellRange _srow = null;
//#IXLRangeRow _rrow = null;
CellRange _rrow = null;
try
{
// Match by SO# (preferred) or TA/Contract# (backup) so we get the right SCHEDA for data
//Console.WriteLine("d");
foreach (var _row in _rows) //check each Megatool row
{
if (row.Row == 1)
continue;
//#if ((string.Equals(_row[1,1].ToString() .Cell(1).GetString(), r.SSC_Order_Number.ToString(), StringComparison.OrdinalIgnoreCase)))
if ((string.Equals(_row[_row.Row, 1].Value.ToString(), r.SSC_Order_Number.ToString(), StringComparison.OrdinalIgnoreCase)))
{
//#so_row = _row.RowNumber();
so_row = _row.Row;
_srow = _row;
}
//#else if (string.Equals(_row.Cell(2).GetString(), r.TA_Number.ToString(), StringComparison.OrdinalIgnoreCase))
else if (string.Equals(_row[_row.Row, 2].Value.ToString(), r.TA_Number.ToString(), StringComparison.OrdinalIgnoreCase))
{
//#r0_row = _row.RowNumber();
r0_row = _row.Row;
_rrow = _row;
}
Logger.Log(6, "_row:{0} is [{3}] so_row:{1} r0_row:{2}", _row.Row, so_row, r0_row, _row[_row.Row, 1].Value);
//Console.WriteLine("sr={0} rr={1} max={2} cur={3}",so_row, r0_row, max, _row.RowNumber());
//#if ((so_row != 0) || ((r0_row != 0) && (_row.RowNumber() == max))) // prefer SO match, take R000 otherwise
if ((so_row != 0) || ((r0_row != 0) && (_row.Row == max))) // prefer SO match, take R000 otherwise
{
Logger.Log(5, "_row:{0} is [{3}] so_row:{1} r0_row:{2}", _row.Row, so_row, r0_row, _row[_row.Row, 1].Value);
//_srow = _row;
if (so_row == 0) // No SO match
{
//i = r0_row;
_srow = _rrow;
so_row = r0_row; // may need to remove!!!
}
//i= _row.RowNumber();
// Now add Megatool data if it exists, and we always have a SchedA!
//#string schA = _srow.Cell(6).GetString();
string schA = _srow[so_row,6].Value.ToString() ;
r.CI_Name = schA;
//# if (_srow.Cell(1).GetString() == "XXX") //SO not defined
if (_srow[so_row, 1].Value.ToString() == "XXX") //SO not defined
{
Logger.Log(5, " {0}-SO not found in InsisMap! Linking SO ({1}) by TA/Contract", r.SSC_Order_Number, schA);
}
//#string mrc = _srow.Cell(8).GetString();
string mrc = _srow[so_row, 8].Value.ToString();
if ( !SIP && (mrc != "XXX") )
{
calcTaxes(mrc, "0", ref r);
}
else if (SIP) // we need to understand which SIP line item we are workign with, Access, Sessions or DID
{
double new_mrc = 0;
//Access, r.SCID contains 'NAP'
if (r.SCID.Contains("NAP"))
{
if ( !string.Equals(_srow[so_row, 10].Value.ToString(), "XXX", StringComparison.OrdinalIgnoreCase))
{
double qty = Convert.ToDouble(_srow[so_row, 10].Value.ToString()); // should always be 1
double cost = Convert.ToDouble(_srow[so_row, 11].Value.ToString()); // should always be $200
double mega_mrc = qty * cost;
if (!(qty == r.Quantity))
Logger.Log(0, " - ACH Mismatch for {0} SO:({1} X {2}) vs MT:({3} X {4})", r.CI_Name, r.Quantity, 200, qty, cost);
}
new_mrc = r.Quantity * 200;
}
//Sessions, r.SCID contains 'SAP'
else if (r.SCID.Contains("SAP"))
{
if (!string.Equals(_srow[so_row, 12].Value.ToString(), "XXX", StringComparison.OrdinalIgnoreCase))
{
double qty = Convert.ToDouble(_srow[so_row, 12].Value.ToString());
double cost = Convert.ToDouble(_srow[so_row, 13].Value.ToString());
double mega_mrc = qty * cost;
if (!(qty == r.Quantity))
Logger.Log(0, " - VSS Mismatch for {0} SO:({1} X {2}) vs MT:({3} X {4})", r.CI_Name, r.Quantity, 9.8, qty, cost);
}
new_mrc = r.Quantity * 9.80;
}
//DID, r.SCID contains 'DID'
else if (r.SCID.Contains("DID"))
{
new_mrc = r.Quantity * 0.75; // grab the qty from the SO, price is fixed at $0.75
}
calcTaxes(new_mrc.ToString(), "0", ref r); // throw a zero if we don't understand!
}
else
{
Logger.Log(0, " {0}-MRR not found ({1}) ", r.SSC_Order_Number, schA);
}
//Fix up Billing Effective Date as there are some customs, return as INT23
//#string bef = _srow.Cell(7).GetString();
string bef = _srow[so_row, 7].Value.ToString();
if (bef == "XXX")
{
Logger.Log(1, " -- Bill Start Date not found in INSIS for {0}, retrieving from exceptions.", r.CI_Name);
r.Billing_Effective_Date = getBEF(r.CI_Name);
}
else
{
r.Billing_Effective_Date = Int32.Parse(bef);
}
// Logic to determine if we need to add an extra row for an NRC item
//#string nrc = _srow.Cell(9).GetString();
string nrc = _srow[so_row, 9].Value.ToString();
if (nrc != "XXX")
{
double _nrc = Double.Parse(nrc + "0");
if (_nrc != 0)
{
string billMonth = r.Billing_Effective_Date.ToString();
billMonth = billMonth.Substring(0, (billMonth.Length - 2));
Logger.Log(2, "Billing for {0} and BEF is {1}", current, billMonth);
if (current.ToString() == billMonth)
{
Logger.Log(0, " >SO{1} ADD NRC={0:0.00} charge to current BDF ({2})", _nrc, r.SSC_Order_Number, r.CI_Name);
r_nrc = BDF.CopyRow(r);
calcTaxes("0", nrc, ref r_nrc);
int build_row = 0;
//foreach (var nrc_row in ws2.RowsUsed())
foreach (var nrc_row in ws2.AllocatedRange.Rows)
{
try
{
//if (ws2.Cell("AB" + nrc_row.RowNumber().ToString()).Value.ToString().ToUpper().Contains("BUILD"))
if (ws2[nrc_row.Row,28].Value.ToString().ToUpper().Contains("BUILD"))
{
//#build_row = nrc_row.RowNumber();
build_row = nrc_row.Row;
//#r_nrc.SSC_Seq_No = Int32.Parse(ws2.Cell("U" + nrc_row.RowNumber().ToString()).Value.ToString());
r_nrc.SSC_Seq_No = Int32.Parse(ws2[nrc_row.Row, 21].Value.ToString());
//#r_nrc.SCID = ws2.Cell("AB" + nrc_row.RowNumber().ToString()).Value.ToString();
r_nrc.SCID = ws2[nrc_row.Row, 28].Value.ToString();
break;
}
}
catch (Exception e)
{
Logger.Log(0, "nrc {0}:{1}", e.Message, e.InnerException.Message);
}
}
if (build_row == 0)
{
Logger.Log(0, "WARNING - No 'Build' row in SO-{0} found for this charge, using '* MANUAL *' ({1})", r.SSC_Order_Number, r.CI_Name);
r_nrc.SSC_Seq_No = 0;
r_nrc.SCID = "* MANUAL *";
}
}
else if (current >= Int32.Parse(billMonth))
{
Logger.Log(0, " >SO{1} SKIP NRC={0:0.00} as presumed already billed ({2})", _nrc, r.SSC_Order_Number, r.CI_Name);
}
else
{
Logger.Log(0, " >SO{1} SKIP NRC={0:0.00} as it is a future billing ({2})", _nrc, r.SSC_Order_Number, r.CI_Name);
}
}
}
//Console.WriteLine("a5");
break;
} // end of if scheda match
} // end of row interations in InsisMap
}
catch (Exception e)
{
Logger.Log(0, "InsisMap Exc: {0}:{1}", e.Message, e.InnerException.Message);
}
//Now add row(s) as needed
try
{
if ((so_row + r0_row) == 0)
{
Logger.Log(0, "Megatool InsisMap : Row not found: {0}", r.SSC_Order_Number);
}
if (r.Billing_Effective_Date > (current * 100 + 1))
{
Logger.Log(0, " >SO{0} SKIP - {1} doesn't start billing until {2} : {4} x {3}", r.SSC_Order_Number, r.CI_Name, r.Billing_Effective_Date, r.SCID.Substring(5), r.Quantity);
}
else if (r.Billing_Effective_Date == 0) // this happens for new SCHEDS that don't have bill start dates yet
{
Logger.Log(0, " >SO{0} ZEROED as Bill Start Date is unknown ({1})", r.SSC_Order_Number, r.CI_Name);
calcTaxes("0", "0", ref r); // recalc MRR with zeros,
r_nrc.Non_recurring_Charges_for_the_Month = 0; // removes NRC line
}
else
{
rows.Add(r);
if (r_nrc.Non_recurring_Charges_for_the_Month != 0)
rows.Add(r_nrc);
}
}
catch (Exception e)
{
Logger.Log(0, "Exc:add {0}:{1}", e.Message, e.InnerException.Message);
}
// End row adds
}
else
{
break;
}
Logger.Log(4, "SCID:{0}:{1}", scid, rows.Count);
// End of first row in SO (default for billing)
}
// End of SO rows processing
}
// End of current SO Workbook
try
{
//#BDF.InsertData(bdf2, rows);
BDF.S_InsertData(bdf2, rows);
CellRange reformat = bdf2[2, 21, bdf2.LastRow, 31];
reformat.Style.NumberFormat = "#0.00";
reformat = bdf2[2, 17, bdf2.LastRow, 17];
reformat.Style.NumberFormat = "#";
//#bdf2.Range(2, 21, bdf2.LastRowUsed().RowNumber(), 31).Style.NumberFormat.Format = "#0.00";
if (task == "SIP") bdf2.DeleteColumn(36); // clean up unused column from Tab2 for SIP data
}
catch (Exception e)
{
Logger.Log(0, "Exc:add2 {0}:{1}", e.Message, e.InnerException.Message);
}
}
catch (Exception e)
{
Logger.Log(0, "Exception Rows: {0}:{1} ", e.Message, e.InnerException);
}
//End of SO Workbooks
Logger.Log("Finalizing...");
Dictionary<string, string> Invoice = new Dictionary<string, string> { };
InvoiceCell ic = new InvoiceCell { };
// finalize the totals on first sheet
//var bdf1 = workbook.Worksheet("BDF Type 1");
//#var bdf1 = workbook.Worksheet(1);
var bdf1 = workbook.Worksheets[0];
bdf1.Name += monthAbbreviation;
List<Row2> row2s = null;
if (task != "SIP")
{
row2s = new List<Row2> { new Row2 { Invoice_Period = current, Invoice_Date = int.Parse(invDate), Contractor_Name = "ROGERS", Canada_Contract_Identifier = "K00019754" } };
try
{
//#BDF.InsertData(bdf1, row2s);
BDF.S_InsertData(bdf1, row2s);
/*
bdf1.Row(2).Cell(6).Value = sumCol(22, ref bdf2);
bdf1.Row(2).Cell(7).Value = sumCol(24, ref bdf2);
bdf1.Row(2).Cell(8).Value = (double)bdf1.Row(2).Cell(6).Value + (double)bdf1.Row(2).Cell(7).Value;
bdf1.Row(2).Cell(9).Value = sumCol(26, ref bdf2);
bdf1.Row(2).Cell(10).Value = sumCol(25, ref bdf2);
bdf1.Row(2).Cell(11).Value = 0;
bdf1.Row(2).Cell(12).Value = sumCol(27, ref bdf2);
bdf1.Row(2).Cell(13).Value = sumCol(28, ref bdf2);
bdf1.Row(2).Cell(14).Value = sumCol(29, ref bdf2);
bdf1.Row(2).Cell(15).Value = sumCol(30, ref bdf2);
bdf1.Row(2).Cell(16).Value = sumCol(31, ref bdf2);
*/
bdf1[2, 6].NumberValue = S_sumCol(22, ref bdf2);
bdf1[2, 7].NumberValue = S_sumCol(24, ref bdf2);
bdf1[2, 8].NumberValue = (double)bdf1[2,6].NumberValue + (double)bdf1[2,7].NumberValue;
bdf1[2, 9].NumberValue = S_sumCol(26, ref bdf2);
bdf1[2, 10].NumberValue = S_sumCol(25, ref bdf2);
bdf1[2, 11].NumberValue = 0;
bdf1[2, 12].NumberValue = S_sumCol(27, ref bdf2);
bdf1[2, 13].NumberValue = S_sumCol(28, ref bdf2);
bdf1[2, 14].NumberValue = S_sumCol(29, ref bdf2);
bdf1[2, 15].NumberValue = S_sumCol(30, ref bdf2);
bdf1[2, 16].NumberValue = S_sumCol(31, ref bdf2);
//#bdf1.LastColumnUsed().Delete(); // get rid of total usage summary col
bdf1.DeleteColumn(bdf1.LastColumn);
}
catch (Exception e)
{
Logger.Log(0, "Error creating totals for Tab 1", e.Message);
}
}
else // SIP BDF
{
row2s = new List<Row2> { new Row2 { Invoice_Period = current, Invoice_Date = int.Parse(invDate), Contractor_Name = "ROGERS", Canada_Contract_Identifier = "K00019754" } };
try
{
//#BDF.InsertData(bdf1, row2s);
BDF.S_InsertData(bdf1, row2s);
/*
bdf1.Row(2).Cell(6).Value = sumCol(22, ref bdf2);
bdf1.Row(2).Cell(7).Value = sumCol(24, ref bdf2);
bdf1.Row(2).Cell(8).Value = (double)bdf1.Row(2).Cell(6).Value + (double)bdf1.Row(2).Cell(7).Value;
bdf1.Row(2).Cell(9).Value = sumCol(26, ref bdf2);
bdf1.Row(2).Cell(10).Value = sumCol(25, ref bdf2);
bdf1.Row(2).Cell(11).Value = 0;
bdf1.Row(2).Cell(12).Value = sumCol(27, ref bdf2);
bdf1.Row(2).Cell(13).Value = sumCol(28, ref bdf2);
bdf1.Row(2).Cell(14).Value = sumCol(29, ref bdf2);
bdf1.Row(2).Cell(15).Value = sumCol(30, ref bdf2);
bdf1.Row(2).Cell(16).Value = sumCol(31, ref bdf2);
*/
bdf1[2, 6].NumberValue = S_sumCol(22, ref bdf2);
bdf1[2, 7].NumberValue = S_sumCol(24, ref bdf2);
bdf1[2, 8].NumberValue = (double)bdf1[2, 6].NumberValue + (double)bdf1[2, 7].NumberValue;
bdf1[2, 9].NumberValue = S_sumCol(26, ref bdf2);
bdf1[2, 10].NumberValue = S_sumCol(25, ref bdf2);
bdf1[2, 11].NumberValue = 0;
bdf1[2, 12].NumberValue = S_sumCol(27, ref bdf2);
bdf1[2, 13].NumberValue = S_sumCol(28, ref bdf2);
bdf1[2, 14].NumberValue = S_sumCol(29, ref bdf2);
bdf1[2, 15].NumberValue = S_sumCol(30, ref bdf2);
bdf1[2, 16].NumberValue = S_sumCol(31, ref bdf2);
}
catch (Exception e)
{
Logger.Log(0, "Error creating totals for SIP Tab 1", e.Message);
}
// Create the header-only TAB3 for SIP
//#var bdf3 = workbook.Worksheet(3);
var bdf3 = workbook.Worksheets[2];
bdf3.Name += monthAbbreviation;
var row3 = new List<Row3> { new Row3 { } };
try
{
//BDF.InsertData(bdf3, row3);
BDF.S_InsertData(bdf3, row3);
}
catch (Exception e)
{
Logger.Log(0, "Error creating totals for SIP Tab 3", e.Message);
}
}
//DateTime dd = DateTime.Now;
string traceable = "";
try
{
if ( username.Contains("."))
{
traceable = "_" + username.Split('.')[0].Substring(0, 1) + username.Split('.')[1].Substring(0, 1) + "_"
+ d.ToString("yyyyMMdd");
}
else
{
traceable = "_" + username + "_" + d.ToString("yyyyMMdd");
}
}
catch (Exception e)
{
Logger.Log(0, "traceable: ", e.Message);
}
try
{
//#bdf1.Range(2, 6, bdf1.LastRowUsed().RowNumber(), 17).Style.NumberFormat.Format = "#0.00"; workbook.SaveAs(traceable);
CellRange reformat = bdf1[2, 6, bdf1.LastDataRow, 17];
reformat.Style.NumberFormat = "#0.00";
//add AutoFilters to Sheet2
bdf2.AutoFilters.Range = bdf2.AllocatedRange;
bdf2.AutoFilters.Filter();
//#workbook.SaveAs(traceable);
workbook.SaveToFile(bdf.filename.Split('.')[0] + traceable + ".xlsx", ExcelVersion.Version2016);
Logger.Log(0, "Excel file populated! ({0})", bdf.filename.Split('.')[0] + traceable + ".xlsx");
}
catch (Exception e)
{
Logger.Log(0, "Error formatting and saving Workbook ({0})", traceable);
Logger.Log(0, "({0})", e.Message);
Logger.Log(0, "Please close the workbook ({0}) if you currently have it open in Excel and then retry.", traceable);
}
// Create PDF Invoice
try // Create Custom Invoice from template
{
Invoice.Add(ic.Account, "Account P02-" + "857412"); //bdf2 C2
Invoice.Add(ic.Date, PDF.dateFormal(row2s[0].Invoice_Date));
Invoice.Add(ic.Invoice, ("Invoice " + invDate.Substring(4) + invDate.Substring(0, 4) + " - " + task)); //mmddyyyy
//#Invoice.Add(ic.Total_Charges, bdf1.Row(2).Cell(16).Value.ToString());
Invoice.Add(ic.Total_Charges, String.Format("${0:N2}", bdf1[2, 16].NumberValue ));
Invoice.Add(ic.Account2, Invoice[ic.Account]);
Invoice.Add(ic.Date2, Invoice[ic.Date]);
Invoice.Add(ic.Invoice2, Invoice[ic.Invoice]);
Invoice.Add(ic.Total_Charges2, Invoice[ic.Total_Charges]);
Invoice.Add(ic.CCI, "Canada Contract Identifier " + row2s[0].Canada_Contract_Identifier);
Invoice.Add(ic.PaperFee, String.Format("{0:N2}", 0));
Invoice.Add(ic.LateCharge, String.Format("{0:N2}", 0));
Invoice.Add(ic.Service_Charges, String.Format("${0:N2}", Double.Parse(Invoice[ic.PaperFee]) + Double.Parse(Invoice[ic.LateCharge] ) ));
//Invoice.Add(ic.UsageCharges, String.Format("{0:N2}", 0));
Invoice.Add(ic.TotalUsageCharges, String.Format("${0:N2}", 0));
Invoice.Add(ic.DataMonthlyCharges, String.Format("{0:N2}", bdf1[2, 6].NumberValue));
Invoice.Add(ic.DataNon_RecurringCharges, String.Format("{0:N2}", bdf1[2, 7].NumberValue));
Invoice.Add(ic.DataTotalOtherCharges, String.Format("{0:N2}", bdf1[2, 9].NumberValue));
Invoice.Add(ic.Data_Services, String.Format("${0:N2}", (bdf1[2, 8].NumberValue + bdf1[2, 9].NumberValue - bdf1[2, 10].NumberValue) ));
//Invoice.Add( ic.TaxON_PST , bdf1.Row(2).Cell(9).Value
Invoice.Add(ic.TaxON_GST, String.Format("{0:N2}", 0));
Invoice.Add(ic.TaxON_HST, String.Format("{0:N2}", bdf1[2, 13].NumberValue));
Invoice.Add(ic.TaxPQ_PST, String.Format("{0:N2}", bdf1[2, 14].NumberValue));
Invoice.Add(ic.TaxPQ_GST, String.Format("{0:N2}", bdf1[2, 12].NumberValue));
Invoice.Add(ic.TaxPQ_HST, String.Format("{0:N2}", 0 ));
Invoice.Add(ic.Taxes, String.Format("${0:N2}", bdf1[2, 15].NumberValue));
Logger.Log("PDF Invoice being created...");
//Load ARIAL.TTF font to working dir if needed
try
{
PDF.customInvoice(task, traceable, ref Invoice);
}
catch
{
string appDir = AppDomain.CurrentDomain.BaseDirectory;
ExtractResourceToFile("BDF.Embedded.arial.ttf", (appDir + "./arial.ttf")); // arial.ttf is needed to render the PDF
PDF.customInvoice(task, traceable, ref Invoice);
}
}
catch (Exception e)
{
Logger.Log(0, "Error Invoice Cells for Tab 1", e.Message);
}
// Cleanup stuff
CXLFile.S_ServiceOrders.RemoveRange(0, CXLFile.S_ServiceOrders.Count);
Logger.Log("All done! Have a Great Day :) ");
} // end of MAIN()
} // end of todo loop
// END OF MAIN2
public static Dictionary<string, string> getOverrides(string task) //returns with SCHEDA prefix
{
Dictionary<string, string> o = new Dictionary<string, string> { };
if (System.IO.File.Exists(task + overrideSuffix))
{
Logger.Log(0, "Found Overrides file ({0}), parsing it...", task + overrideSuffix);
foreach (var line in System.IO.File.ReadLines(task + overrideSuffix))
{
if (string.IsNullOrWhiteSpace(line))
continue;
// Split by spaces: first token is the index word
string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2)
{
Logger.Log(0, " -Skipping: Invalid override line format: {0}", line);
continue;
}
string indexWord = parts[0]; // convert from SO to SCHEDA
// Validate numeric range
//if (!int.TryParse(indexWord, out int indexNum) ||
// indexNum < 100000 || indexNum > 999999)
Match match = Regex.Match( indexWord , @"^[A-Za-z]{7}[0-9]{3}", System.Text.RegularExpressions.RegexOptions.None);
if (!match.Success)
{
Logger.Log(0, " -Skipping: Invalid SCHEDA '{0}' in line: {1}", indexWord, line);
continue;
}
// Dictionary for key=value pairs
Dictionary<string, string> pairs = new Dictionary<string, string>();
// Parse remaining tokens
for (int i = 1; i < parts.Length; i++)
{
var kv = parts[i].Split('=');
if (kv.Length != 2)
{
Logger.Log(0, " -Skipping: Malformed override entry format: {0}", parts[i]);
continue;
}
string key = kv[0].Trim();
string value = kv[1].Trim();
pairs[key] = value;
}
// Validate overrides, SO was already checked
// SO TA COP PRID CONTRACT SCHED BSD MRR NRC
// 124111 R000137538 333754 3050 GCNSLDF047 XXX 900 0
//
//foreach (string Parm in new string[] { "COP", "PRID", "SCHED", "BSD", "MRR", "NRC" }) // checklist
try
{
string ivalue = "";
if (!pairs.TryGetValue("COP", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num))
if (!(num >= 100000 && num <= 999999)) //invalid COP
{
Logger.Log(0, " >{1} SKIP invalid override for COP of {0}", ivalue, indexWord);
pairs.Remove("COP");
}
if (!pairs.TryGetValue("PRID", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num2))
if (!(num2 >= 1000 && num2 <= 9999)) //invalid PRID
{
Logger.Log(0, " >{1} SKIP invalid override for PRID of {0}", ivalue, indexWord);
pairs.Remove("PRID");
}
if (!pairs.TryGetValue("SO", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num3))
if (!(num3 >= 100000 && num3 <= 999999)) //invalid SO
{
Logger.Log(0, " >{1} SKIP invalid override for SO of {0}", ivalue, indexWord);
pairs.Remove("SO");
}
if (!pairs.TryGetValue("BSD", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num4))
if (!(num4 >= 20200000 && num4 <= 20300000)) //invalid COP
{
Logger.Log(0, " >{1} SKIP invalid override for BSD of {0}", ivalue, indexWord);
pairs.Remove("BSD");
}
if (!pairs.TryGetValue("MRR", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num5))
if (!(num5 >= 0 && num5 <= 99999)) //invalid MRR
{
Logger.Log(0, " >{1} SKIP invalid override for MRR of {0}", ivalue, indexWord);
pairs.Remove("MRR");
}
if (!pairs.TryGetValue("NRC", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid MRR
{
Logger.Log(0, " >{1} SKIP invalid override for NRC of {0}", ivalue, indexWord);
pairs.Remove("NRC");
}
}
catch (Exception e)
{
Logger.Log(0, "Overrides Exc: {0}:{1}", e.Message, e.InnerException.Message);
}
string so_overrides = "";
{
foreach (var p in pairs)
{
so_overrides += (String.Format(" {0} = {1}", p.Key, p.Value));
o.Add(indexWord + p.Key, p.Value);
}
Logger.Log(1, " - {0} : {1}", indexWord, so_overrides);
}
}
}
else
{
Logger.Log(1, " Override file ({0}) not found. Skipping Overrides.", task + overrideSuffix);
}
return o;
}
public static Dictionary<string,string> getOverrides_so(string task)
{
Dictionary<string, string> o = new Dictionary<string, string> { };
if (System.IO.File.Exists(task+overrideSuffix))
{
Logger.Log(0, "Found Overrides file ({0}), parsing it...", task + overrideSuffix);
foreach (var line in System.IO.File.ReadLines(task + overrideSuffix))
{
if ( string.IsNullOrWhiteSpace(line) || line.Substring(0, 1).Contains("#") ) // clean up blank or comment lines (start with #).
continue;
// Split by spaces: first token is the index word
string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length< 2)
{
Logger.Log(0, " -Skipping: Invalid override line format: {0}", line);
continue;
}
string indexWord = parts[0];
// Validate numeric range
if (!int.TryParse(indexWord, out int indexNum) ||
indexNum< 100000 || indexNum> 999999)
{
Logger.Log(0, " -Skipping: Invalid SO# '{0}' in line: {1}", indexWord, line);
continue;
}
// Dictionary for key=value pairs
Dictionary<string, string> pairs = new Dictionary<string, string>();
// Parse remaining tokens
for (int i = 1; i < parts.Length; i++)
{
var kv = parts[i].Split('=');
if (kv.Length != 2)
{
Logger.Log(0, " -Skipping: Malformed override entry format: {0}", parts[i]);
continue;
}
string key = kv[0].Trim();
string value = kv[1].Trim();
pairs[key] = value;
}
// Validate overrides, SO was already checked
// SO TA COP PRID CONTRACT SCHED BSD MRR NRC
// 124111 R000137538 333754 3050 GCNSLDF047 XXX 900 0
//
//foreach (string Parm in new string[] { "COP", "PRID", "SCHED", "BSD", "MRR", "NRC" }) // checklist
try
{
string ivalue = "";
if (!pairs.TryGetValue("COP", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num))
if (!(num >= 100000 && num <= 999999)) //invalid COP
{
Logger.Log(0, " >SO{1} SKIP invalid override for COP of {0}", ivalue, indexWord);
pairs.Remove("COP");
}
if (!pairs.TryGetValue("PRID", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num2))
if (!(num2 >= 1000 && num2 <= 9999)) //invalid PRID
{
Logger.Log(0, " >SO{1} SKIP invalid override for PRID of {0}", ivalue, indexWord);
pairs.Remove("PRID");
}
if (!pairs.TryGetValue("SCHED", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue.Substring(7), out int num3))
if (!(num3 >= 1 && num3 <= 999)) //invalid SCHED
{
Logger.Log(0, " >SO{1} SKIP invalid override for SCHED of {0}", ivalue, indexWord);
pairs.Remove("SCHED");
}
if (!pairs.TryGetValue("BSD", out ivalue)) { } // key not found, move on
else if (int.TryParse(ivalue, out int num4))
if (!(num4 >= 20200000 && num4 <= 20300000)) //invalid COP
{
Logger.Log(0, " >SO{1} SKIP invalid override for BSD of {0}", ivalue, indexWord);
pairs.Remove("BSD");
}
if (!pairs.TryGetValue("MRR", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num5))
if (!(num5 >= 0 && num5 <= 99999)) //invalid MRR
{
Logger.Log(0, " >SO{1} SKIP invalid override for MRR of {0}", ivalue, indexWord);
pairs.Remove("MRR");
}
if (!pairs.TryGetValue("NRC", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid MRR
{
Logger.Log(0, " >SO{1} SKIP invalid override for NRC of {0}", ivalue, indexWord);
pairs.Remove("NRC");
}
if ( task == "SIP")
{
if (!pairs.TryGetValue("AQty", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid
{
Logger.Log(0, " >SO{1} SKIP invalid override for AQty of {0}", ivalue, indexWord);
pairs.Remove("AQty");
}
if (!pairs.TryGetValue("ACst", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid
{
Logger.Log(0, " >SO{1} SKIP invalid override for ACst of {0}", ivalue, indexWord);
pairs.Remove("ACst");
}
if (!pairs.TryGetValue("SQty", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid
{
Logger.Log(0, " >SO{1} SKIP invalid override for SQty of {0}", ivalue, indexWord);
pairs.Remove("SQty");
}
if (!pairs.TryGetValue("SCst", out ivalue)) { } // key not found, move on
else if (double.TryParse(ivalue, out double num6))
if (!(num6 >= 0 && num6 <= 99999)) //invalid
{
Logger.Log(0, " >SO{1} SKIP invalid override for SCst of {0}", ivalue, indexWord);
pairs.Remove("SCst");
}
}
}
catch (Exception e)
{
Logger.Log(0, "Overrides Exc: {0}:{1}", e.Message, e.InnerException.Message);
}
string so_overrides = "";
{
foreach (var p in pairs)
{
so_overrides += (String.Format(" {0} = {1}", p.Key, p.Value));
o.Add(indexWord + p.Key, p.Value);
}
Logger.Log(1, " -SO{0} : {1}", indexWord, so_overrides);
}
}
}
return o;
}
public static void calcTaxes( string mrc, string nrc, ref Row r)
{
r.Recurring_Charges_for_the_Month = Double.Parse(mrc);
r.Total_Recurring_Charges_for_the_Month = r.Recurring_Charges_for_the_Month;
r.Non_recurring_Charges_for_the_Month = Double.Parse(nrc);
r.Total_Non_recurring_Charges_for_the_Month = r.Non_recurring_Charges_for_the_Month;
r.Total_Service_Credits = 0;
r.Total_Other_Charges_and_Credits = 0;
double taxable = (r.Total_Recurring_Charges_for_the_Month + r.Total_Non_recurring_Charges_for_the_Month - r.Total_Other_Charges_and_Credits);
if (r.Prov == "QC")
{
r.Total_GST_Amount = Math.Round((0.05) * taxable, 2);
r.Total_HST_Amount = 0;
r.Total_QST_Amount = Math.Round((0.09975) * taxable, 2);
}
else if (r.Prov == "ON")
{
r.Total_GST_Amount = 0;
r.Total_HST_Amount = Math.Round((0.13) * taxable, 2);
r.Total_QST_Amount = 0;
}
else if (r.Prov == "NS")
{
r.Total_GST_Amount = 0;
r.Total_HST_Amount = Math.Round((0.14) * taxable, 2);
r.Total_QST_Amount = 0;
}
else if ( (r.Prov == "AB") || (r.Prov == "NWT") || (r.Prov == "NU") || (r.Prov == "YK"))
{
r.Total_GST_Amount = Math.Round((0.05) * taxable, 2);
r.Total_HST_Amount = 0;
r.Total_QST_Amount = 0;
}
else if ( (r.Prov == "BC") || (r.Prov == "MB"))
{
r.Total_GST_Amount = Math.Round((0.05) * taxable, 2);
//r.Total_PST_Amount = Math.Round((0.07) * taxable, 2);
r.Total_HST_Amount = 0;
r.Total_QST_Amount = Math.Round((0.07) * taxable, 2);
}
else if ((r.Prov == "NB") || (r.Prov == "NFLD") || (r.Prov == "PEI"))
{
r.Total_GST_Amount = 0;
r.Total_HST_Amount = Math.Round((0.15) * taxable, 2);
r.Total_QST_Amount = 0;
}
else if ( (r.Prov == "SK") )
{
r.Total_GST_Amount = Math.Round((0.05) * taxable, 2);
//r.Total_PST_Amount = Math.Round((0.06) * taxable, 2);
r.Total_HST_Amount = 0;
r.Total_QST_Amount = Math.Round((0.06) * taxable, 2);
}
r.Total_Taxes = r.Total_GST_Amount + r.Total_HST_Amount + r.Total_QST_Amount;
r.Total_Amount_including_taxes = r.Total_Taxes + taxable;
}
public static Int32 getBEF(string sch)
{
Dictionary<string, int> lookup = new Dictionary<string, int>
{
{"GCNSLDF007" , 20250815} ,
{"GCNSLDF008" , 20250613} ,
{"GCNSLDF009" , 20250506} ,
{"GCNSLDF013" , 20250108} ,
{"GCNSLDF014" , 20250411} ,
{"GCNSLDF027" , 20251101} ,
{"GCNSLDF028" , 20250701} ,
{"GCNSLDF029" , 20251001} ,
{"GCNSLDF030" , 20250901} ,
{"GCNSLDF034" , 20251101} ,
{"GCNSLDF041" , 20251001} ,
{"GCNSLDF047" , 20251101}
};
if ( lookup.ContainsKey(sch) )
{
return lookup[sch];
}
else
{
Logger.Log(0, " ERROR: Bill Start Date Exception not found for ({0})", sch);
return 0;
}
}
/*
public static double sumCol(int col, ref IXLWorksheet ws)
{
//IXLWorksheet ws = wbk.Worksheet("BDF Type 2");
int lastRow = ws.LastRowUsed().RowNumber();
double total = 0;
for (int row = 2; row <= lastRow; row++)
{
var cellValue = ws.Cell(row, col).GetDouble();
total += cellValue;
}
return total;
}
*/
public static double S_sumCol(int col, ref Spire.Xls.Worksheet sheet)
{
if (sheet == null)
throw new System.ArgumentNullException(nameof(sheet));
// Determine the last used row in the worksheet
int lastRow = sheet.LastRow;
double total = 0.0;
// Loop through each row and sum numeric values in the target column
// Worksheet("BDF Type 2") - 1st row is a header row so skip it
for (int row = 2; row <= lastRow; row++)
{
Spire.Xls.CellRange cell = sheet.Range[row, col];
if (cell != null && cell.HasNumber)
{
total += cell.NumberValue;
}
else
{
// Attempt to parse text values as numbers
double parsed;
if (double.TryParse(cell.Text, out parsed))
{
total += parsed;
}
}
}
return total;
}
public static string ReadPassword()
{
// Using StringBuilder is a good balance between security and ease of use in console apps
StringBuilder passwordBuilder = new StringBuilder();
ConsoleKeyInfo key;
Console.Write(">>>>>>>>>>>>>>>>>>>>>>>> ");
do
{
// Read the key, but do not display it (intercept = true)
key = Console.ReadKey(true);
// Handle standard characters
if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
{
passwordBuilder.Append(key.KeyChar);
Console.Write("*"); // Display an asterisk or other mask character
}
// Handle backspace
else if (key.Key == ConsoleKey.Backspace && passwordBuilder.Length > 0)
{
passwordBuilder.Remove(passwordBuilder.Length - 1, 1);
Console.Write("\b \b"); // Erase the last character from the console
}
}
// Stop when the Enter key is pressed
while (key.Key != ConsoleKey.Enter);
Console.WriteLine(); // Add a new line after the password entry is complete
return passwordBuilder.ToString();
}
public static bool SafeDeleteFile(string filePath)
{
try
{
// Validate input
if (string.IsNullOrWhiteSpace(filePath))
return false;
// Normalize path (removes illegal characters, etc.)
string fullPath = System.IO.Path.GetFullPath(filePath);
// Make sure file exists
if (!System.IO.File.Exists(fullPath))
return false;
// Remove read-only attribute if necessary
System.IO.FileAttributes attrs = System.IO.File.GetAttributes(fullPath);
if ((attrs & System.IO.FileAttributes.ReadOnly) == System.IO.FileAttributes.ReadOnly)
{
System.IO.File.SetAttributes(fullPath, System.IO.FileAttributes.Normal);
}
// Attempt deletion
System.IO.File.Delete(fullPath);
// Verify deletion
return !System.IO.File.Exists(fullPath);
}
catch (System.Exception)
{
// Could log the exception if needed
return false;
}
}
public static void ExtractResourceToFile(string resourceName, string outputPath)
{
// Get the assembly that contains the embedded resource
Assembly assembly = Assembly.GetExecutingAssembly();
// Get the stream of the embedded resource
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
if (stream == null)
{
Console.WriteLine($"Resource '{resourceName}' not found.");
return;
}
// Create the output file in the application's working directory
using (FileStream fileStream = File.Create(outputPath))
{
// Copy the resource stream to the file stream
stream.CopyTo(fileStream);
}
}
Logger.Log(2, "Resource {0} successfully saved to {1}.", resourceName, outputPath);
}
public static bool RemoveStringKey(List<string> list, string key)
{
if (list == null || key == null)
return false;
int index = list.FindIndex(s => string.Equals(s, key, StringComparison.OrdinalIgnoreCase));
if (index < 0)
return false;
list.RemoveAt(index);
return true;
}
/*
public static bool RemoveStringKey(List<string> list, string key)
{
if (list == null || key == null)
return false;
Console.WriteLine("c");
// Find the first matching string
int index = list.FindIndex(s => s.Equals(key, StringComparison.OrdinalIgnoreCase));
Console.WriteLine("d");
if (index >= 0)
{
Console.WriteLine("e");
list.RemoveAt(index);
return true;
}
Console.WriteLine("f");
return false;
}
*/
} // bdf class
public static class IDictionaryExtensions
{
public static TKey FindKeyByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TValue value)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
foreach (KeyValuePair<TKey, TValue> pair in dictionary)
if (value.Equals(pair.Value)) return pair.Key;
throw new Exception("the value is not found in the dictionary");
}
}
}