1582 lines
76 KiB
C#
Executable File
1582 lines
76 KiB
C#
Executable File
#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 ClosedXML.Excel;
|
|
using System.Data;
|
|
using System.Security.Principal;
|
|
//using DocumentFormat.OpenXml;
|
|
using System.Linq;
|
|
using bdf;
|
|
using DocumentFormat.OpenXml.Wordprocessing;
|
|
//using DocumentFormat.OpenXml.Drawing.Charts;
|
|
//using DocumentFormat.OpenXml.Xml;
|
|
|
|
namespace bdf
|
|
{
|
|
class bdf
|
|
{
|
|
public static string product = "BDF";
|
|
public static string version = "2.0.1";
|
|
|
|
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 == "ClosedXML")
|
|
{
|
|
embname = "BDF.Embedded.ClosedXML.dll";
|
|
}
|
|
else if (name == "ClosedXML.Parser")
|
|
{
|
|
embname = "BDF.Embedded.ClosedXML.Parser.dll";
|
|
}
|
|
else if (name == "DocumentFormat.OpenXml")
|
|
{
|
|
embname = "BDF.Embedded.DocumentFormat.OpenXml.dll";
|
|
}
|
|
else if (name == "DocumentFormat.OpenXml.Framework")
|
|
{
|
|
embname = "BDF.Embedded.DocumentFormat.OpenXml.Framework.dll";
|
|
}
|
|
else if (name == "ExcelDataReader.DataSet")
|
|
{
|
|
embname = "BDF.Embedded.ExcelDataReader.DataSet.dll";
|
|
}
|
|
else if (name == "ExcelDataReader")
|
|
{
|
|
embname = "BDF.Embedded.ExcelDataReader.dll";
|
|
}
|
|
else if (name == "ExcelNumberFormat")
|
|
{
|
|
embname = "BDF.Embedded.ExcelNumberFormat.dll";
|
|
}
|
|
else if (name == "Microsoft.Bcl.HashCode")
|
|
{
|
|
embname = "BDF.Embedded.Microsoft.Bcl.HashCode.dll";
|
|
}
|
|
else if (name == "RBush")
|
|
{
|
|
embname = "BDF.Embedded.RBush.dll";
|
|
}
|
|
else if (name == "SixLabors.Fonts")
|
|
{
|
|
embname = "BDF.Embedded.SixLabors.Fonts.dll";
|
|
}
|
|
else if (name == "System.Buffers")
|
|
{
|
|
embname = "BDF.Embedded.System.Buffers.dll";
|
|
}
|
|
else if (name == "System.IO")
|
|
{
|
|
embname = "BDF.Embedded.System.IO.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.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.Runtime")
|
|
{
|
|
embname = "BDF.Embedded.System.Runtime.dll";
|
|
}
|
|
else if (name == "System.Security.Cryptography.Algorithms")
|
|
{
|
|
embname = "BDF.Embedded.System.Security.Cryptography.Algorithms.dll";
|
|
}
|
|
else if (name == "System.Security.Cryptography.Encoding")
|
|
{
|
|
embname = "BDF.Embedded.System.Security.Cryptography.Encoding.dll";
|
|
}
|
|
else if (name == "System.Security.Cryptography.Primitives")
|
|
{
|
|
embname = "BDF.Embedded.System.Security.Cryptography.Primitives.dll";
|
|
}
|
|
else if (name == "System.Security.Cryptography.X509Certificates")
|
|
{
|
|
embname = "BDF.Embedded.System.Security.Cryptography.X509Certificates.dll";
|
|
}
|
|
else if (name == "System.Text.Encoding.CodePages")
|
|
{
|
|
embname = "BDF.Embedded.System.Text.Encoding.CodePages.dll";
|
|
}
|
|
else if (name == "System.Text.RegularExpressions")
|
|
{
|
|
embname = "BDF.Embedded.System.Text.RegularExpressions.dll";
|
|
}
|
|
else
|
|
{
|
|
embname = "something_bad";
|
|
}
|
|
|
|
Logger.Log(5, "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)
|
|
{
|
|
Console.WriteLine("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)
|
|
{
|
|
Console.WriteLine("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)
|
|
{
|
|
// Enforce TLS1.2 Sep2017
|
|
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192;
|
|
|
|
// Logging file
|
|
outfile = new StreamWriter(@"" + logname, logappend);
|
|
outfile.AutoFlush = true;
|
|
|
|
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(0, "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 -------------------------------------------------------------------------------------------------------------------------------
|
|
var updates = new Dictionary<string, string>
|
|
{
|
|
|
|
{ "October", "November" } // change date
|
|
/*
|
|
{ "31", "30" }, // change amount
|
|
{ "10312025", "11302025" } , // change invoice number
|
|
{ "$42,008.75", "$10,000.00" } // change amount
|
|
*/
|
|
};
|
|
|
|
PDF.doPDF2(
|
|
"test.pdf",
|
|
"updated.pdf",
|
|
updates
|
|
);
|
|
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, "Starting to process the {0} BDF...", task);
|
|
|
|
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;
|
|
}
|
|
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();
|
|
// Add a worksheet
|
|
var insisMap = wbk.AddWorksheet(task+InsisSuffix.Split('.')[0]); // add empty worksheet 'InsisMap'
|
|
string path = dirpath + task + InsisSuffix;
|
|
|
|
//If less than 24h old, or -old 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);
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
// ***SO 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
|
|
*/
|
|
// 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);
|
|
}
|
|
|
|
// Look for override data in _override.txt
|
|
Dictionary<string, string> overrides = getOverrides(task);
|
|
|
|
//todo should rework this to use 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 ?? "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
row[kvp.Key] = kvp.Value ?? "";
|
|
}
|
|
}
|
|
//Console.WriteLine("c r:{0} s:{1}+", row["MRR"], sched);
|
|
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];
|
|
}
|
|
|
|
foreach (var kvp in parms)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
dt.Rows.Add(row);
|
|
} // end of foreach SCHED
|
|
|
|
|
|
// 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.Columns().AdjustToContents();
|
|
|
|
//ws.RangeUsed().Sort("A");
|
|
|
|
var used = insisMap.RangeUsed();
|
|
|
|
// Define a range that excludes the header row (row 1)
|
|
var dataRange = used.Range(2, 1, used.RowCount(), used.ColumnCount());
|
|
|
|
// Sort by column A inside that range (currently SO, thinking SCHED is a better idea)
|
|
dataRange.Sort("A");
|
|
|
|
// Save to file (_Megatool mapping)
|
|
try
|
|
{
|
|
wbk.SaveAs(path);
|
|
}
|
|
catch
|
|
{
|
|
Logger.Log(0, "Ensure you do not have ({0}) already open!", path);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// *** -------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
//Date string 202511
|
|
DateTime d = DateTime.Now;
|
|
//string CurrentYearMonth = d.ToString("yyyyMM");
|
|
int current = Int32.Parse(d.AddMonths(month_offset).ToString("yyyyMM"));
|
|
|
|
// 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";
|
|
|
|
//Load and convert all XLS? files that start with 'ROGERS_(task)_SO*' in the (task) subdirectory
|
|
|
|
File.getXLS(task, (base_path + ToDo[(task + "path")]) );
|
|
|
|
Logger.Log(0, "{0} Service Order Workbooks returned.", File.ServiceOrders.Count);
|
|
|
|
// BDF Workbook - create the correct format based on task
|
|
var workbook = BDF.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.Worksheet("BDF Type 2");
|
|
|
|
// 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
|
|
|
|
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 File.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
|
|
//IXLWorksheet ws2 = wb.Worksheet("LDFONS_SDP_data_V2");
|
|
IXLWorksheet ws2 = wb.Worksheet(2); //generic 2nd worksheet
|
|
|
|
string _so = ws2.Cell("A2").Value.ToString(); // This is our SO#
|
|
|
|
Logger.Log(1, "Ingesting {0} ({1}/{2})...", _so, k++, File.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 CCI = (string)ws1.Cell("G2").Value.ToString(); // R000XXXXXX
|
|
|
|
//Format CCI as R + 9 digits, left zero padded
|
|
string _cci = CCI;
|
|
_cci = ("000000000" + Int32.Parse(_cci.Substring(1)));
|
|
CCI = "R" + _cci.Substring(_cci.Length - 9);
|
|
//
|
|
var _rows = wbk.Worksheet(task+InsisSuffix.Split('.')[0]).RangeUsed().RowsUsed(); // _Megatool intermediate sheet
|
|
|
|
foreach (var row in ws2.RowsUsed()) // go through Tab#2 of SO
|
|
{
|
|
var r = new Row { Row_Number = (rows.Count + 1), Contractor = C, Canada_Contract_Identifier = CCI };
|
|
////if ( task == "SIP")
|
|
// var r_nrc = new Row { Row_Number = (rows.Count + 1), Contractor = C, Canada_Contract_Identifier = CCI }; // only used if NRC present
|
|
var r_nrc = BDF.CopyRow(r);
|
|
|
|
if (row.RowNumber() != 1) // skip column titles
|
|
{
|
|
//Process contents of a new row for the Type 2 tab
|
|
if (!sos.Contains(_so)) //UPDATED TO ONLY ENTER 1 LINE PER SO
|
|
{
|
|
|
|
//tcids.Add(ws2.Cell("AF" + row.RowNumber()).Value.ToString());
|
|
sos.Add(_so); // UPDATED TO ADD THE SO# INSTEAD OF UNIQUE SERVICE
|
|
|
|
r.Canada_Contract_Identifier = CCI;
|
|
r.SSC_Order_Number = Int32.Parse(ws2.Cell("A" + row.RowNumber()).Value.ToString());
|
|
|
|
r.SSC_Version = (Int32)ws2.Cell("B" + row.RowNumber()).Value;
|
|
r.SDPID = ws2.Cell("S" + row.RowNumber()).Value.ToString();
|
|
r.Department = ws2.Cell("F" + row.RowNumber()).Value.ToString();
|
|
r.Prov = ws2.Cell("AQ" + row.RowNumber()).Value.ToString();
|
|
r.Billing_End_Date = Int32.Parse(ws2.Cell("M" + row.RowNumber()).Value.ToString().Replace("/", ""));
|
|
r.SCID = ws2.Cell("AB" + row.RowNumber()).Value.ToString();
|
|
r.TCID = ws2.Cell("AF" + row.RowNumber()).Value.ToString();
|
|
r.TA_Number = CCI;
|
|
r.Invoice_Period = current;
|
|
r.Period_of_Service = current;
|
|
//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();
|
|
IXLRangeRow _srow = null;
|
|
IXLRangeRow _rrow = null;
|
|
try
|
|
{
|
|
// Match by SO# (preferred) or TA/Contract# (backup) so we get the right SCHEDA for data
|
|
foreach (var _row in _rows)
|
|
{
|
|
if ((string.Equals(_row.Cell(1).GetString(), r.SSC_Order_Number.ToString(), StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
so_row = _row.RowNumber();
|
|
_srow = _row;
|
|
}
|
|
else if (string.Equals(_row.Cell(2).GetString(), r.TA_Number.ToString(), StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
r0_row = _row.RowNumber();
|
|
_rrow = _row;
|
|
}
|
|
|
|
//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
|
|
{
|
|
//_srow = _row;
|
|
if (so_row == 0) // No SO match
|
|
{
|
|
//i = r0_row;
|
|
_srow = _rrow;
|
|
}
|
|
|
|
//i= _row.RowNumber();
|
|
// Now add Megatool data if it exists, and we always have a SchedA!
|
|
string schA = _srow.Cell(6).GetString();
|
|
r.CI_Name = schA;
|
|
|
|
if (_srow.Cell(1).GetString() == "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();
|
|
if (mrc != "XXX")
|
|
{
|
|
calcTaxes(mrc, "0", ref r);
|
|
}
|
|
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();
|
|
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();
|
|
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())
|
|
{
|
|
try
|
|
{
|
|
if (ws2.Cell("AB" + nrc_row.RowNumber().ToString()).Value.ToString().ToUpper().Contains("BUILD"))
|
|
{
|
|
build_row = nrc_row.RowNumber();
|
|
r_nrc.SSC_Seq_No = Int32.Parse(ws2.Cell("U" + nrc_row.RowNumber().ToString()).Value.ToString());
|
|
r_nrc.SCID = ws2.Cell("AB" + nrc_row.RowNumber().ToString()).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);
|
|
}
|
|
|
|
}
|
|
}
|
|
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 as it doesn't start billing until {2} ({1})", r.SSC_Order_Number, r.CI_Name, r.Billing_Effective_Date);
|
|
}
|
|
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
|
|
}
|
|
|
|
}
|
|
// End of first row in SO (default for billing)
|
|
}
|
|
// End of SO rows processing
|
|
}
|
|
// End of current SO Workbook
|
|
try
|
|
{
|
|
BDF.InsertData(bdf2, rows);
|
|
bdf2.Range(2, 21, bdf2.LastRowUsed().RowNumber(), 31).Style.NumberFormat.Format = "#0.00";
|
|
}
|
|
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);
|
|
if (task != "SIP")
|
|
{
|
|
var row2s = new List<Row2> { new Row2 { Invoice_Period = current, Invoice_Date = int.Parse(invDate), Contractor_Name = "ROGERS", Canada_Contract_Identifier = "K00019754" } };
|
|
|
|
try
|
|
{
|
|
// 1 Record Type | 2 Invoice Date | 3 Invoice Period | 4 CCI | 5 Contractor Name
|
|
BDF.InsertData(bdf1, row2s);
|
|
bdf1.Row(2).Cell(6).Value = sumCol(22, ref bdf2); //Tot Recur Chgs Month
|
|
bdf1.Row(2).Cell(7).Value = sumCol(24, ref bdf2); //Tot Non-Recur Chgs Month
|
|
bdf1.Row(2).Cell(8).Value = (double)bdf1.Row(2).Cell(6).Value + (double)bdf1.Row(2).Cell(7).Value; //Total Chgs Excl Tax
|
|
bdf1.Row(2).Cell(9).Value = sumCol(26, ref bdf2); //Tot Other Charge/Cred
|
|
bdf1.Row(2).Cell(10).Value = sumCol(25, ref bdf2); //tot Service Credits
|
|
bdf1.Row(2).Cell(11).Value = 0; //Tot Late Pmt Amt
|
|
bdf1.Row(2).Cell(12).Value = sumCol(27, ref bdf2); //tot GST
|
|
bdf1.Row(2).Cell(13).Value = sumCol(28, ref bdf2); //tot HST
|
|
bdf1.Row(2).Cell(14).Value = sumCol(29, ref bdf2); //tot QST
|
|
bdf1.Row(2).Cell(15).Value = sumCol(30, ref bdf2); //tot taxes
|
|
bdf1.Row(2).Cell(16).Value = sumCol(31, ref bdf2); //tot amt incl tax
|
|
|
|
if (task != "SIP")
|
|
{
|
|
bdf1.LastColumnUsed().Delete(); // get rid of total usage summary col
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Log(0, "Error creating totals for Tab 1", e.Message);
|
|
}
|
|
|
|
try // Create Custom Invoice from template
|
|
{
|
|
Invoice.Add( ic.Account , "Account PO2-" + "857412"); //bdf2 C2
|
|
Invoice.Add( ic.Date , dateFormal(row2s.Invoice_Date);
|
|
Invoice.Add( ic.Invoice , "10312025" ); //mmddyyyy FIXME
|
|
Invoice.Add( ic.Total_Charges , bdf1.Row(2).Cell(16).Value.ToString() );
|
|
|
|
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 , row2s.Canada_Contract_Identifier );
|
|
|
|
Invoice.Add( ic.PaperFee , "0" );
|
|
Invoice.Add( ic.LateCharge , "0" );
|
|
Invoice.Add( ic.Service_Charges , String.Format("{0}", int.Parse(Invoice[ic.PaperFee]) + int.Parse(Invoice[ic.LateCharge]) );
|
|
Invoice.Add( ic.UsageCharges , "0");
|
|
Invoice.Add( ic.TotalUsageCharges , "0");
|
|
Invoice.Add( ic.DataMonthlyCharges , bdf1.Row(2).Cell(6).Value.ToString() );
|
|
Invoice.Add( ic.DataNon_RecurringCharges , bdf1.Row(2).Cell(7).Value.ToString() );
|
|
Invoice.Add( ic.DataTotalOtherCharges , bdf1.Row(2).Cell(9).Value.ToString() );
|
|
Invoice.Add( ic.Data_Services , ( bdf1.Row(2).Cell(8).Value + bdf1.Row(2).Cell(9).Value - bdf1.Row(2).Cell(10).Value).ToString() );
|
|
//Invoice.Add( ic.TaxON_PST , bdf1.Row(2).Cell(9).Value
|
|
Invoice.Add( ic.TaxON_GST , bdf1.Row(2).Cell(12).Value.ToString());
|
|
Invoice.Add( ic.TaxON_HST , bdf1.Row(2).Cell(13).Value.ToString());
|
|
Invoice.Add( ic.TaxPQ_PST , bdf1.Row(2).Cell(14).Value.ToString());
|
|
Invoice.Add( ic.TaxPQ_GST , "0"); FIXME
|
|
Invoice.Add( ic.TaxPQ_HST , "0");
|
|
Invoice.Add( ic.Taxes , bdf1.Row(2).Cell(15).Value.ToString());
|
|
|
|
Excel2PDF.Program.customInvoie(task, ref Invoice);
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Log(0, "Error Invoice Cells for Tab 1", e.Message);
|
|
}
|
|
}
|
|
else // SIP BDF
|
|
{
|
|
var 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);
|
|
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.Row(2).Cell(17).Value = 0; //sumCol(32, ref bdf2); //Total Usage Charges (SIP only)
|
|
|
|
}
|
|
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 row3 = new List<Row3> { new Row3 { } };
|
|
try
|
|
{
|
|
BDF.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 = bdf.filename.Split('.')[0] + "_" + username.Split('.')[0].Substring(0, 1) + username.Split('.')[1].Substring(0, 1) + "_"
|
|
+ d.ToString("yyyyMMdd") + ".xlsx";
|
|
}
|
|
|
|
else
|
|
{
|
|
traceable = bdf.filename.Split('.')[0] + "_" + username + "_" + d.ToString("yyyyMMdd") + ".xlsx";
|
|
}
|
|
}
|
|
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);
|
|
Logger.Log(0, "Excel file populated! ({0})", traceable);
|
|
}
|
|
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);
|
|
}
|
|
|
|
File.ServiceOrders.RemoveRange(0, File.ServiceOrders.Count);
|
|
|
|
} // 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))
|
|
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");
|
|
}
|
|
}
|
|
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 string dateFormal(int dateInt)
|
|
{
|
|
//int dateInt = 20251130;
|
|
string dateString = dateInt.ToString();
|
|
|
|
// 1. Define the input format ("yyyyMMdd")
|
|
string inputFormat = "yyyyMMdd";
|
|
|
|
// 2. Parse the string into a DateTime object
|
|
DateTime dateTimeObject = DateTime.ParseExact(
|
|
dateString,
|
|
inputFormat,
|
|
CultureInfo.InvariantCulture
|
|
);
|
|
|
|
// 3. Define the desired output format ("MMMM dd, yyyy")
|
|
// MMMM = Full month name
|
|
// dd = Day of the month
|
|
// yyyy = Year
|
|
|
|
string outputFormat = "MMMM dd, yyyy";
|
|
string result = dateTimeObject.ToString(outputFormat);
|
|
|
|
//Console.WriteLine(result);
|
|
// Output: November 30, 2025
|
|
return result;
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
}
|
|
|
|
} // 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");
|
|
}
|
|
}
|
|
|
|
}
|