3.5.2 commit

This commit is contained in:
Doug Macintosh
2026-03-08 16:20:06 -04:00
parent a59a047cd1
commit bfe37f6426
26 changed files with 1998 additions and 102714 deletions

577
BDF.cs
View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Spire.Xls;
namespace bdf
{
@@ -9,8 +8,8 @@ namespace bdf
{
public Int32 Row_Number { get; set; } = 1;
public Int32 Record_Type { get; set; } = 2;
public Int32 Contractor_Billing_Account_Number { get; set; } = 857412;
public Int32 Invoice_Number { get; set; } = 61262091;
public Int32 Contractor_Billing_Account_Number { get; set; } = 0; // This will change for each service type
public String Invoice_Number { get; set; } = "INV X";
public Int32 Invoice_Period { get; set; } = 0;
public String Canada_Contract_Identifier { get; set; } = "X";
public String Contractor { get; set; } = "ROGERS";
@@ -36,7 +35,7 @@ namespace bdf
public Double Total_GST_Amount { get; set; } = 0;
//public Double Total_PST_Amount { get; set; } = 0;
public Double Total_HST_Amount { get; set; } = 0;
public Double Total_QST_Amount { get; set; } = 0;
public Double Total_QST_Amount { get; set; } = 0; // to be used for both PST and QST per call with Diana Aboud Feb 9, 2026
public Double Total_Taxes { get; set; } = 0;
public Double Total_Amount_including_taxes { get; set; } = 0;
public String CI_Name { get; set; } = "X";
@@ -44,6 +43,12 @@ namespace bdf
public String TCID { get; set; } = "X";
public String PO_Number { get; set; } = "";
public String TA_Number { get; set; } = "X";
//var copy = original.Clone<MyClass>();
public T Clone<T>() where T : class
{
return (T)this.MemberwiseClone();
}
}
public class Row2 // Generic Type 1
@@ -81,62 +86,19 @@ namespace bdf
public String Department { get; set; } = "X";
public String SCID { get; set; } = "X";
public Int32 Total_Usage_Charges_for_the_Month { get; set; } = 0;
public Int32 Total_Other_Charges_and_Credits { get; set; } = 0;
public Int32 Total_GST_Amount { get; set; } = 0;
//public Int32 Total_PST_Amount { get; set; } = 0;
public Int32 Total_HST_Amount { get; set; } = 0;
public Int32 Total_QST_Amount { get; set; } = 0;
public Int32 Total_Taxes { get; set; } = 0;
public Int32 Total_Amount_Including_Taxes { get; set; } = 0;
public String PO_Number { get; set; } = "X";
}
public class BDF
{
public static Row CopyRow(Row r)
{
Row n = new Row { };
n.Row_Number = r.Row_Number;
n.Record_Type = r.Record_Type;
n.Contractor_Billing_Account_Number = r.Contractor_Billing_Account_Number;
n.Invoice_Number = r.Invoice_Number;
n.Invoice_Period = r.Invoice_Period;
n.Canada_Contract_Identifier = r.Canada_Contract_Identifier;
n.Contractor = r.Contractor;
n.SSC_Order_Number = r.SSC_Order_Number;
n.SSC_Version = r.SSC_Version;
n.SSC_Seq_No = r.SSC_Seq_No;
n.SDPID = r.SDPID;
n.Department = r.Department;
n.Prov = r.Prov;
n.Service_Project_ID = r.Service_Project_ID;
n.Billing_Effective_Date = r.Billing_Effective_Date;
n.Billing_End_Date = r.Billing_End_Date;
n.Billing_Cancel_Date = r.Billing_Cancel_Date;
n.Period_of_Service = r.Period_of_Service;
n.SCID = r.SCID;
n.Quantity = r.Quantity;
n.Recurring_Charges_for_the_Month = r.Recurring_Charges_for_the_Month;
n.Total_Recurring_Charges_for_the_Month = n.Total_Recurring_Charges_for_the_Month;
n.Non_recurring_Charges_for_the_Month = r.Non_recurring_Charges_for_the_Month;
n.Total_Non_recurring_Charges_for_the_Month = r.Total_Non_recurring_Charges_for_the_Month;
n.Total_Service_Credits = r.Total_Service_Credits;
n.Total_Other_Charges_and_Credits = r.Total_Other_Charges_and_Credits;
n.Total_GST_Amount = r.Total_GST_Amount;
n.Total_HST_Amount = r.Total_HST_Amount;
//n.Total_PST_Amount = r.Total_PST_Amount; // do not uncomment creates a extra ghost column in output
n.Total_QST_Amount = r.Total_QST_Amount;
n.Total_Taxes = r.Total_Taxes;
n.Total_Amount_including_taxes = r.Total_Amount_including_taxes;
n.CI_Name = r.CI_Name;
n.CI_Name_2 = r.CI_Name_2;
n.TCID = r.TCID;
n.PO_Number = r.PO_Number;
n.TA_Number = r.TA_Number;
return n;
}
public static Spire.Xls.Workbook S_CreateBDF(string type)
public static Spire.Xls.Workbook CreateBDF(string type)
{
if (type == "LDF" || type == "WAV")
return S_CreateBDF();
@@ -153,7 +115,6 @@ namespace bdf
cleanSheets(ref workbook);
{
//Headers "SIP BDF Type 1"
worksheet1.Range[1, 1].Value = "Record Type";
@@ -174,7 +135,6 @@ namespace bdf
worksheet1.Range[1, 16].Value = "Total Amount Including Taxes";
worksheet1.Range[1, 17].Value = "Total Usage Charges"; // this line was the only delta
var worksheet2 = workbook.Worksheets.Add("BDF Type 2");
//Headers "BDF Type 2"
@@ -229,22 +189,22 @@ namespace bdf
worksheet3.Range[1, 9].Value = "Department";
worksheet3.Range[1, 10].Value = "SCID";
worksheet3.Range[1, 11].Value = "Total Usage Charges for the Month";
worksheet3.Range[1, 12].Value = "Total GST Amount";
worksheet3.Range[1, 13].Value = "Total HST Amount";
worksheet3.Range[1, 14].Value = "Total QST Amount";
worksheet3.Range[1, 15].Value = "Total Taxes";
worksheet3.Range[1, 16].Value = "Total Amount including taxes";
worksheet3.Range[1, 12].Value = "Total Other Charges and Credits";
worksheet3.Range[1, 13].Value = "Total GST Amount";
worksheet3.Range[1, 14].Value = "Total HST Amount";
worksheet3.Range[1, 15].Value = "Total QST Amount";
worksheet3.Range[1, 16].Value = "Total Taxes";
worksheet3.Range[1, 17].Value = "Total Amount including taxes";
worksheet3.Range[1, 18].Value = "PO Number";
}
Logger.Log(0, "Excel BDF template file created! {0}", bdf.dirpath + bdf.filename);
Logger.Log(0, "Excel BDF template file created! {0}", bdf.output_path + bdf.filename);
return workbook;
}
public static Spire.Xls.Workbook S_CreateBDF()
{
var workbook = new Spire.Xls.Workbook();
//using (var workbook = new XLWorkbook())
//Console.WriteLine("WS Count = {0}", workbook.Worksheets.Count);
var worksheet1 = workbook.Worksheets.Add("BDF Type 1");
cleanSheets(ref workbook);
@@ -255,7 +215,7 @@ namespace bdf
worksheet1.Range[1, 2].Value = "Invoice Date";
worksheet1.Range[1, 3].Value = "Invoice Period";
worksheet1.Range[1, 4].Value = "Canada Contract Identifier";
worksheet1.Range[1, 5].Value = "Contractor";
worksheet1.Range[1, 5].Value = "Contractor Name";
worksheet1.Range[1, 6].Value = "Total Recurring Charges for the Month";
worksheet1.Range[1, 7].Value = "Total Non-Recurring Charges for the Month";
worksheet1.Range[1, 8].Value = "Total Charges Excluding Taxes";
@@ -311,7 +271,7 @@ namespace bdf
}
Logger.Log(0, "Excel BDF template file created! {0}", bdf.dirpath + bdf.filename);
Logger.Log(0, "Excel BDF template file created! {0}", bdf.output_path + bdf.filename);
return workbook;
}
@@ -403,7 +363,7 @@ namespace bdf
// ------------------------------------------------------
Spire.Xls.CellRange tableRange = worksheet.Range[startRow, startCol, totalRows, totalCols];
TableFormatter.ApplyTableFormat(tableRange);
ApplyTableFormat(tableRange);
// ------------------------------------------
// Autofit column widths to contents
@@ -412,79 +372,77 @@ namespace bdf
}
public static class TableFormatter
/*
/// Applies "table-style" formatting to a specified range:
/// - Bold gray header row
/// - Bordered cells
/// - Alternating (banded) row background colors
/// Fully compatible with FreeSpire.XLS.
/// </summary>
/// <param name="range">Spire.Xls.CellRange to format</param>
///
// Spire.Xls.Worksheet sheet = wb.Worksheets[0];
// Define a range with header + rows
// Spire.Xls.CellRange tableRange = sheet.Range["A1:D10"];
// Apply table styling
// TableFormatter.ApplyTableFormat(tableRange);
*/
public static void ApplyTableFormat(Spire.Xls.CellRange range)
{
/// <summary>
/// Applies "table-style" formatting to a specified range:
/// - Bold gray header row
/// - Bordered cells
/// - Alternating (banded) row background colors
/// Fully compatible with FreeSpire.XLS.
/// </summary>
/// <param name="range">Spire.Xls.CellRange to format</param>
///
// Spire.Xls.Worksheet sheet = wb.Worksheets[0];
if (range == null)
throw new System.ArgumentNullException("range");
// Define a range with header + rows
// Spire.Xls.CellRange tableRange = sheet.Range["A1:D10"];
int rowCount = range.RowCount;
int colCount = range.ColumnCount;
// Apply table styling
// TableFormatter.ApplyTableFormat(tableRange);
if (rowCount == 0 || colCount == 0)
return;
public static void ApplyTableFormat(Spire.Xls.CellRange range)
// ---------------------------
// 1. Format Header Row
// ---------------------------
for (int col = 0; col < colCount; col++)
{
if (range == null)
throw new System.ArgumentNullException("range");
Spire.Xls.CellRange headerCell =
range[1, col + 1]; // 1-based indexing inside CellRange segment
int rowCount = range.RowCount;
int colCount = range.ColumnCount;
headerCell.Style.Font.IsBold = true;
headerCell.Style.Color = System.Drawing.Color.LightGray;
headerCell.Style.Borders.LineStyle = Spire.Xls.LineStyleType.Thin;
if (rowCount == 0 || colCount == 0)
return;
// ---------------------------
// 1. Format Header Row
// ---------------------------
for (int col = 0; col < colCount; col++)
{
Spire.Xls.CellRange headerCell =
range[1, col + 1]; // 1-based indexing inside CellRange segment
headerCell.Style.Font.IsBold = true;
headerCell.Style.Color = System.Drawing.Color.LightGray;
headerCell.Style.Borders.LineStyle = Spire.Xls.LineStyleType.Thin;
headerCell.Borders[Spire.Xls.BordersLineType.DiagonalDown].LineStyle = Spire.Xls.LineStyleType.None;
headerCell.Borders[Spire.Xls.BordersLineType.DiagonalUp].LineStyle = Spire.Xls.LineStyleType.None;
}
// ---------------------------
// 2. Format Data Rows (banded)
// ---------------------------
for (int row = 2; row <= rowCount; row++)
{
bool isEven = (row % 2 == 0);
System.Drawing.Color rowColor = isEven
? System.Drawing.Color.FromArgb(245, 245, 245) // light gray band
: System.Drawing.Color.White;
for (int col = 1; col <= colCount; col++)
{
Spire.Xls.CellRange cell = range[row, col];
cell.Style.Color = rowColor;
cell.Style.Borders.LineStyle = Spire.Xls.LineStyleType.Thin;
cell.Borders[Spire.Xls.BordersLineType.DiagonalDown].LineStyle = Spire.Xls.LineStyleType.None;
cell.Borders[Spire.Xls.BordersLineType.DiagonalUp].LineStyle = Spire.Xls.LineStyleType.None;
}
}
// ---------------------------
// 3. Auto-fit column widths
// ---------------------------
range.AutoFitColumns();
headerCell.Borders[Spire.Xls.BordersLineType.DiagonalDown].LineStyle = Spire.Xls.LineStyleType.None;
headerCell.Borders[Spire.Xls.BordersLineType.DiagonalUp].LineStyle = Spire.Xls.LineStyleType.None;
}
// ---------------------------
// 2. Format Data Rows (banded)
// ---------------------------
for (int row = 2; row <= rowCount; row++)
{
bool isEven = (row % 2 == 0);
System.Drawing.Color rowColor = isEven
? System.Drawing.Color.FromArgb(245, 245, 245) // light gray band
: System.Drawing.Color.White;
for (int col = 1; col <= colCount; col++)
{
Spire.Xls.CellRange cell = range[row, col];
cell.Style.Color = rowColor;
cell.Style.Borders.LineStyle = Spire.Xls.LineStyleType.Thin;
cell.Borders[Spire.Xls.BordersLineType.DiagonalDown].LineStyle = Spire.Xls.LineStyleType.None;
cell.Borders[Spire.Xls.BordersLineType.DiagonalUp].LineStyle = Spire.Xls.LineStyleType.None;
}
}
// ---------------------------
// 3. Auto-fit column widths
// ---------------------------
range.AutoFitColumns();
}
public static void cleanSheets(ref Spire.Xls.Workbook workbook)
@@ -496,366 +454,5 @@ namespace bdf
workbook.Worksheets.RemoveAt(0);
}
/*
public static XLWorkbook CreateBDF(string type)
{
if (type == "LDF" || type == "WAV")
return CreateBDF();
else if (type == "SIP")
return CreateBDFSIP();
else
return null;
}
public static XLWorkbook CreateBDF()
{
var workbook = new XLWorkbook();
//using (var workbook = new XLWorkbook())
{
var worksheet1 = workbook.Worksheets.Add("BDF Type 1");
//Headers "BDF Type 1"
worksheet1.Cell(1, 1).Value = "Record Type";
worksheet1.Cell(1, 2).Value = "Invoice Date";
worksheet1.Cell(1, 3).Value = "Invoice Period";
worksheet1.Cell(1, 4).Value = "Canada Contract Identifier";
worksheet1.Cell(1, 5).Value = "Contractor Name";
worksheet1.Cell(1, 6).Value = "Total Recurring Charges for the Month";
worksheet1.Cell(1, 7).Value = "Total Non-Recurring Charges for the Month";
worksheet1.Cell(1, 8).Value = "Total Charges Excluding Taxes";
worksheet1.Cell(1, 9).Value = "Total Other Charges and Credits";
worksheet1.Cell(1, 10).Value = "Total Service Credits";
worksheet1.Cell(1, 11).Value = "Total Late Payment Amount";
worksheet1.Cell(1, 12).Value = "Total GST Amount";
worksheet1.Cell(1, 13).Value = "Total HST Amount";
worksheet1.Cell(1, 14).Value = "Total QST Amount";
worksheet1.Cell(1, 15).Value = "Total Taxes";
worksheet1.Cell(1, 16).Value = "Total Amount Including Taxes";
var worksheet2 = workbook.Worksheets.Add("BDF Type 2");
//Headers "BDF Type 2"
worksheet2.Cell(1, 1).Value = "Row Number";
worksheet2.Cell(1, 2).Value = "Record Type";
worksheet2.Cell(1, 3).Value = "Contractor Billing Account Number";
worksheet2.Cell(1, 4).Value = "Invoice Number";
worksheet2.Cell(1, 5).Value = "Invoice Period";
worksheet2.Cell(1, 6).Value = "Canada Contract Identifier";
worksheet2.Cell(1, 7).Value = "Contractor";
worksheet2.Cell(1, 8).Value = "SSC Order Number";
worksheet2.Cell(1, 9).Value = "SSC Version";
worksheet2.Cell(1, 10).Value = "SSC Seq No";
worksheet2.Cell(1, 11).Value = "SDPID";
worksheet2.Cell(1, 12).Value = "Department";
worksheet2.Cell(1, 13).Value = "Prov";
worksheet2.Cell(1, 14).Value = "Service Project ID";
worksheet2.Cell(1, 15).Value = "Billing Effective Date";
worksheet2.Cell(1, 16).Value = "Billing End Date";
worksheet2.Cell(1, 17).Value = "Billing Cancel Date";
worksheet2.Cell(1, 18).Value = "Period of Service";
worksheet2.Cell(1, 19).Value = "SCID";
worksheet2.Cell(1, 20).Value = "Quantity";
worksheet2.Cell(1, 21).Value = "Recurring Charges for the Month";
worksheet2.Cell(1, 22).Value = "Total Recurring Charges for the Month";
worksheet2.Cell(1, 23).Value = "Non-recurring Charges for the Month";
worksheet2.Cell(1, 24).Value = "Total Non-recurring Charges for the Month";
worksheet2.Cell(1, 25).Value = "Total Service Credits";
worksheet2.Cell(1, 26).Value = "Total Other Charges and Credits";
worksheet2.Cell(1, 27).Value = "Total GST Amount";
worksheet2.Cell(1, 28).Value = "Total HST Amount";
worksheet2.Cell(1, 29).Value = "Total QST Amount";
worksheet2.Cell(1, 30).Value = "Total Taxes";
worksheet2.Cell(1, 31).Value = "Total Amount including taxes";
worksheet2.Cell(1, 32).Value = "CI Name";
worksheet2.Cell(1, 33).Value = "CI Name 2";
worksheet2.Cell(1, 34).Value = "TCID";
worksheet2.Cell(1, 35).Value = "PO Number";
worksheet2.Cell(1, 36).Value = "TA Number";
}
Logger.Log(0, "Excel BDF template file created! {0}", bdf.dirpath + bdf.filename);
return workbook;
}
public static XLWorkbook CreateBDFSIP()
{
var workbook = new XLWorkbook();
//using (var workbook = new XLWorkbook())
{
var worksheet1 = workbook.Worksheets.Add("BDF Type 1");
//Headers "SIP BDF Type 1"
worksheet1.Cell(1, 1).Value = "Record Type";
worksheet1.Cell(1, 2).Value = "Invoice Date";
worksheet1.Cell(1, 3).Value = "Invoice Period";
worksheet1.Cell(1, 4).Value = "Canada Contract Identifier";
worksheet1.Cell(1, 5).Value = "Contractor";
worksheet1.Cell(1, 6).Value = "Total Recurring Charges for the Month";
worksheet1.Cell(1, 7).Value = "Total Non-Recurring Charges for the Month";
worksheet1.Cell(1, 8).Value = "Total Charges Excluding Taxes";
worksheet1.Cell(1, 9).Value = "Total Other Charges and Credits";
worksheet1.Cell(1, 10).Value = "Total Service Credits";
worksheet1.Cell(1, 11).Value = "Total Late Payment Amount";
worksheet1.Cell(1, 12).Value = "Total GST Amount";
worksheet1.Cell(1, 13).Value = "Total HST Amount";
worksheet1.Cell(1, 14).Value = "Total QST Amount";
worksheet1.Cell(1, 15).Value = "Total Taxes";
worksheet1.Cell(1, 16).Value = "Total Amount Including Taxes";
worksheet1.Cell(1, 17).Value = "Total Usage Charges"; // this line was the only delta
var worksheet2 = workbook.Worksheets.Add("BDF Type 2");
//Headers "BDF Type 2"
worksheet2.Cell(1, 1).Value = "Line Number"; //slight change
worksheet2.Cell(1, 2).Value = "Record Type";
worksheet2.Cell(1, 3).Value = "Contractor Billing Account Number";
worksheet2.Cell(1, 4).Value = "Invoice Number";
worksheet2.Cell(1, 5).Value = "Invoice Period";
worksheet2.Cell(1, 6).Value = "Canada Contract Identifier";
worksheet2.Cell(1, 7).Value = "Contractor";
worksheet2.Cell(1, 8).Value = "SSC Reference Number"; //slight change
worksheet2.Cell(1, 9).Value = "SSC Version";
worksheet2.Cell(1, 10).Value = "SSC Seq No";
worksheet2.Cell(1, 11).Value = "SDPID";
worksheet2.Cell(1, 12).Value = "Department";
worksheet2.Cell(1, 13).Value = "Prov";
worksheet2.Cell(1, 14).Value = "Service Project ID";
worksheet2.Cell(1, 15).Value = "Billing Effective Date";
worksheet2.Cell(1, 16).Value = "Billing End Date";
worksheet2.Cell(1, 17).Value = "Billing Cancel Date";
worksheet2.Cell(1, 18).Value = "Period of Service";
worksheet2.Cell(1, 19).Value = "SCID";
worksheet2.Cell(1, 20).Value = "Qty"; //slight change
worksheet2.Cell(1, 21).Value = "Recurring Charges for the Month";
worksheet2.Cell(1, 22).Value = "Total Recurring Charges for the Month";
worksheet2.Cell(1, 23).Value = "Non-recurring Charges for the Month";
worksheet2.Cell(1, 24).Value = "Total Non-recurring Charges for the Month";
worksheet2.Cell(1, 25).Value = "Total Service Credits";
worksheet2.Cell(1, 26).Value = "Total Other Charges and Credits";
worksheet2.Cell(1, 27).Value = "Total GST Amount";
worksheet2.Cell(1, 28).Value = "Total HST Amount";
worksheet2.Cell(1, 29).Value = "Total QST Amount";
worksheet2.Cell(1, 30).Value = "Total Taxes";
worksheet2.Cell(1, 31).Value = "Total Amount including taxes";
worksheet2.Cell(1, 32).Value = "CI Name";
worksheet2.Cell(1, 33).Value = "CI Name 2";
worksheet2.Cell(1, 34).Value = "TCID";
worksheet2.Cell(1, 35).Value = "PO #"; //slight change
// worksheet2.Cell(1, 36).Value = "TA Number"; //this line removed for SIP-2
var worksheet3 = workbook.Worksheets.Add("BDF Type 3");
//Headers "SIP BDF Type 3"
worksheet3.Cell(1, 1).Value = "Line Number";
worksheet3.Cell(1, 2).Value = "Record Type";
worksheet3.Cell(1, 3).Value = "Contractor Billing Account Number";
worksheet3.Cell(1, 4).Value = "Invoice Number";
worksheet3.Cell(1, 5).Value = "Invoice Period";
worksheet3.Cell(1, 6).Value = "Canada Contract Identifier";
worksheet3.Cell(1, 7).Value = "Contractor";
worksheet3.Cell(1, 8).Value = "Period of Service";
worksheet3.Cell(1, 9).Value = "Department";
worksheet3.Cell(1, 10).Value = "SCID";
worksheet3.Cell(1, 11).Value = "Total Usage Charges for the Month";
worksheet3.Cell(1, 12).Value = "Total GST Amount";
worksheet3.Cell(1, 13).Value = "Total HST Amount";
worksheet3.Cell(1, 14).Value = "Total QST Amount";
worksheet3.Cell(1, 15).Value = "Total Taxes";
worksheet3.Cell(1, 16).Value = "Total Amount including taxes";
}
Logger.Log(0, "Excel BDF template file created! {0}", bdf.dirpath + bdf.filename);
return workbook;
}
public static void InsertData<T>(IXLWorksheet worksheet, List<T> items)
{
if (items == null || items.Count == 0)
return;
var type = typeof(T);
var props = type.GetProperties();
//Logger.Log(0, "prop={0} items={1}", props.Length, items.Count);
// Write headers
//for (int i = 0; i < props.Length; i++)
//{
// //Logger.Log(0, "name={0}", props[i].Name);
// worksheet.Cell(1, i + 1).Value = props[i].Name;
// worksheet.Cell(1, i + 1).Style.Font.Bold = true;
//}
// Write data
for (int r = 0; r < items.Count; r++)
{
for (int c = 0; c < props.Length; c++)
{
//if (props[c].Name == "Total_PST_Amount") continue;
//Logger.Log(0, "value={0}", props[c].GetValue(items[r], null));
var value = props[c].GetValue(items[r], null);
//Console.WriteLine("props {0}:{1}", props[c].Name, value);
if (props[c].Name.ToString() == "Billing_Cancel_Date") // GOC wants this field bank instead of 0
{
//Console.WriteLine("skip");
continue;
}
//Logger.Log(0, "Type={0}", value.GetType().Name);
try
{
if (value.GetType().Name == "Int32")
{
worksheet.Cell(r + 2, c + 1).Value = (Int32)value;
}
else if (value.GetType().Name == "String")
{
worksheet.Cell(r + 2, c + 1).Value = (String)value;
}
else if (value.GetType().Name == "Double")
{
worksheet.Cell(r + 2, c + 1).Value = (Double)value;
}
else
{
worksheet.Cell(r + 2, c + 1).Value = "z";
}
}
catch (Exception e)
{
Logger.Log(0, "Exception: {0} : {1} !", e.Message, e.InnerException);
}
}
}
// Format table
//Logger.Log("Making range");
var range = worksheet.Range(1, 1, items.Count + 1, props.Length);
//Logger.Log("Making table");
range.CreateTable();
worksheet.Columns().AdjustToContents();
}
public class ListObject
{
public string Name { get; private set; }
public Spire.Xls.Worksheet Sheet { get; private set; }
public CellRange Range { get; private set; }
public ListObject(string name)
{
Name = name;
}
/// <summary>
/// Creates a fake ListObject-style table at the given worksheet and row/column.
/// </summary>
public void CreateTable<T>(Spire.Xls.Worksheet sheet, int startRow, int startCol, List<T> items)
{
Sheet = sheet;
if (items == null || items.Count == 0)
throw new ArgumentException("Items list must contain at least one element.");
PropertyInfo[] props = typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
int row = startRow;
int col = startCol;
// ---------------------------------------------------
// HEADER ROW
// ---------------------------------------------------
for (int i = 0; i < props.Length; i++)
{
CellRange cell = sheet.Range[row, col + i];
cell.Text = props[i].Name;
cell.Style.Font.IsBold = true;
cell.Style.Color = System.Drawing.Color.LightGray;
cell.Style.Borders.LineStyle = LineStyleType.Thin;
}
row++;
// ---------------------------------------------------
// DATA ROWS
// ---------------------------------------------------
int dataStartRow = row;
int itemIndex = 0;
foreach (T item in items)
{
for (int i = 0; i < props.Length; i++)
{
object value = props[i].GetValue(item, null);
CellRange cell = sheet.Range[row, col + i];
cell.Value2 = value;
// Border
cell.Style.Borders.LineStyle = LineStyleType.Thin;
// Alternating (banded) rows
if (itemIndex % 2 == 0)
cell.Style.Color = System.Drawing.Color.White;
else
cell.Style.Color = System.Drawing.Color.FromArgb(245, 245, 245);
}
itemIndex++;
row++;
}
int lastRow = row - 1;
int lastCol = col + props.Length - 1;
// Record the table's occupied range
Range = sheet.Range[startRow, startCol, lastRow, lastCol];
// ---------------------------------------------------
// AUTO-FIT WIDTHS
// ---------------------------------------------------
Range.AutoFitColumns();
}
/// <summary>
/// Updates all values in an existing fake ListObject.
/// </summary>
public void Refresh<T>(List<T> items)
{
if (Sheet == null || Range == null)
throw new InvalidOperationException("Table has not been created.");
PropertyInfo[] props = typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
int headerRow = Range.Row;
int dataStartRow = headerRow + 1;
int row = dataStartRow;
int col = Range.Column;
foreach (T item in items)
{
for (int i = 0; i < props.Length; i++)
{
object value = props[i].GetValue(item, null);
Sheet.Range[row, col + i].Value2 = value;
}
row++;
}
}
}
*/
}
}
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,124 +0,0 @@
License Agreement
BY INSTALLING, DOWNLOADING, COPYING OR OTHERWISE USING THE PRODUCT, YOU AGREE TO BE BOUND BY THE TERMS OF THIS EULA. IF YOU DO NOT AGREE TO THE TERMS OF THIS EULA, DO NOT INSTALL, DOWNLOAD, COPY OR USE THE PRODUCT.
1. IMPORTANT NOTICE.
YOU SHOULD READ THE FOLLOWING TERMS AND CONDITIONS CAREFULLY BEFORE YOU DOWNLOAD, INSTALL OR USE E-ICEBLUE'S COMPONENT AND RELATED DOCUMENTATION (THE "LICENSED SOFTWARE") DISTRIBUTED UNDER THE TRADEMARK OF COMPONENT AND/OR E-ICEBLUE. BY INSTALLING OR USING THE LICENSED SOFTWARE, YOU AGREE TO BE BOUND BY THIS LICENSE AGREEMENT, AND ITS TERMS SHALL BE BINDING WITH RESPECT TO YOUR USE OF THE LICENSED SOFTWARE. IF YOU DO NOT AGREE TO THE FOLLOWING TERMS AND CONDITIONS, DO NOT INSTALL OR USE THE SOFTWARE.
2. DEFINITIONS.
A. "e-iceblue" means e-iceblue Corporation
B. "You" and "Your" mean the party purchasing a license to use the Licensed Software under the terms of this agreement.
C. "Application Programming Interface or API" means a publicly accessible interface defining the ways by which an application program may request services from libraries and/or software.
D. "Licensed Software" means compiled Objects, Modules, License Key and any and all updates thereto, together with all associated documentation provided by e-iceblue or its authorized resellers.
E. "License Key" means a unique code provided by e-iceblue or its authorized resellers which identifies You, as well as the license type, and which unlocks or enables certain features of the Licensed Software.
F. "Application" or "Your Application" means a software application that You develop which incorporates all or parts of the Licensed Software.
G. "Evaluation Trial Period" means a specified period of time during which You may temporarily use the Licensed Software for evaluation purposes only.
3. LICENSE GRANT.
The Cumulative License granted to You by e-iceblue is a combination of the Base License Grant, described in section (3A) below, which is common to every Licensed Software title covered by this agreement, and one or more supplemental License Grant which covers the specific product obtained by You from e-iceblue or its authorized resellers.
Four basic types of supplemental License Grants are described in sections (3B): Evaluation License, Developer License, Developer OEM License, Site Enterprise License, Site OEM License.
These five basic types are hereby further defined and/or restricted as to the number of developers, servers, geography locations and distribution method(s), depending on the specific product(s) being licensed by You.
The precise combination of the Base License Grant and one or more supplemental License Grant(s) obtained by You is identified by e-iceblue at the time of purchase or most recent upgrade.
3A. BASE LICENSE GRANT.
In consideration of Your payment of applicable license fees and/or Your acceptance of the terms of this Agreement, e-iceblue hereby grants to You certain nonexclusive and nontransferable rights limited by the terms of this Agreement.
The Licensed Software is licensed (not sold) to You, for use strictly under the terms of this Agreement, and e-iceblue reserves all rights not expressly granted to You herein. If You upgrade the Licensed Software to a higher-numbered version thereof or to a comparable E-iceblue product, this license is terminated and Your rights shall be limited to the license associated with the upgraded product or version.
In addition, You acknowledge that the Licensed Software may contain certain third party software components which are distributed under the terms of their own licenses.
3B. EVALUATION LICENSE.
In order to facilitate an efficient evaluation process of the Licensed Software by developers, e-iceblue may, at its discretion, provide specially designed, temporary License Key(s) that are encoded with an embedded expiration date.
The License granted in conjunction with such License Key(s) is considered temporary, and multiple developers may use it for the sole purpose of evaluating the Licensed Software during a specific Evaluation Trial Period. Licensed Evaluation Trial Software contains mechanisms that inhibit its ability to function at a later date.
It is Your responsibility to ensure that the Applications You create do not contain Licensed Evaluation Trial Software and that their ability to function at a later date is not inhibited or diminished.
3C. DEVELOPER LICENSE.
The following terms and conditions contained in this section (3C) apply to You ONLY if at the time of original purchase or most recent upgrade, the License granted to You by E-iceblue was defined as "Developer License".
The specific license level selected by you at the time of purchase or most recent upgrade determines whether the license applies to (1) a single named developer, or (2) a team of named developers, for example a Developer Team, or (3) a single site (facility or campus) whereby an unlimited number of developers located within said site (facility or campus) may be allowed access to the Licensed Software.
You are hereby granted a nonexclusive, royalty-free license to integrate the Licensed Software into Your Applications and to distribute such Licensed Software in connection with said Applications, provided that
(a) said Applications do not in any way compete with the Licensed Software, or provide substantially the same functionality as the Licensed Software, or expose the functionality of the Licensed Software through a programmable interface;
(b) each of Your Applications developed using Licensed Software is substantially larger, more complex, and contains a significantly wider range of functions as compared to the Licensed Software;
(c) each of Your Applications developed using Licensed Software is designed for end users, rather than for developers who would be able to build other software that would compete with the Licensed Software, and
(d) You do not permit further distribution of the Licensed Software by Your end users.
You may embed the License Keys in the Applications You distribute, provided that the following conditions are met:
(a) each such Application must be marked with a prominent copyright notice bearing Your name as declared by You during purchase of the License;
(b) the License Key may not be embedded in any such Application or distributed in any other manner that makes the License Key visible to the end user, and
(c) each such Application must include the following comment in its source code within close proximity to each copy of an embedded License Key: "This application utilizes a licensed copy of e-iceblue software, copyright (c) 2004-2018, which is the property of e-iceblue Corporation, www.e-iceblue.com. All rights are reserved by e-iceblue.
Use of any objects outside of the context of this application is a violation of United States and international copyright laws and other applicable laws."
For each License Key provided to You by e-iceblue, depending on the specific license level selected by you at the time of purchase or most recent upgrade, You are granted a nonexclusive License to make the Licensed Software and/or the License Key(s) available either to the specified number of Your named developers or to an unlimited number of Your developers located at a single site (facility or campus) as indicated by e-iceblue and further explained below.
Should either the number of named developers or the number of sites with access to the Licensed Software and/or the License Key(s) ever exceed the number indicated at the time of original purchase or most recent upgrade, You agree to inform E-iceblue of such change and to upgrade Your License accordingly by paying an upgrade fee to e-iceblue in a timely manner.
One Developer Subscription authorizes One developer to utilize our product to create unlimited number of applications which can be deployed at only One geography location within your organization. This type of license supports one server or multiple servers in the same place, which is/are used to host your web application.
One Developer OEM Subscription authorizes One developer to create any number of applications using our product which can be deployed at Unlimited geography locations. This type of license allows royalty-free distribution.
One Site Enterprise Subscription entitles up to 10 developers in the register enterprise to create an unlimited number of custom applications/service using our product. It allows deployment of any number of custom applications at up to 10 geography locations.
One Site Enterprise OEM Subscription authorizes up to 50 developers in the register organization to create an unlimited number of custom applications using our product. It allows royalty-free deployment of any number of custom applications to Unlimited geography locations.
4. RESTRICTIONS ON USE AND TRANSFER.
You may not sublicense, rent, lease, assign or otherwise transfer the Licensed Software or any of Your rights thereto, either in whole or in part, to anyone else, except that You may, after obtaining written permission from e-iceblue, permanently transfer the Licensed Software in its entirety, provided You retain no copies of the Licensed Software and the transferee agrees to the terms and conditions of this Agreement.
Use of the Licensed Software with a License Key obtained from a source other than e-iceblue or its authorized resellers is expressly and strictly forbidden. e-iceblue reserves the right to take any and all actions that e-iceblue, in its sole discretion, deems necessary to protect against, monitor and control the use of the Licensed Software with illegal License Keys.
You agree to ensure that anyone who uses any portion of the Licensed Software provided to You complies with the terms and conditions of this Agreement.
5. INTELLECTUAL PROPERTY RIGHTS.
You acknowledge that the Licensed Software contains copyrighted material, trade secrets, trademarks and other proprietary material of e-iceblue ("Confidential Information"), and is protected under United States and international copyright law and other applicable laws.
You may not engage in any unauthorized use or disclosure of any Confidential Information. You agree that the source code of the Licensed Software is confidential and proprietary to e-iceblue. Accordingly, You may not copy the Licensed Software, or decompile, disassemble, reverse engineer or create a derivative work based upon the Licensed Software, or authorize anyone else to do so.
You must reproduce and maintain all copyright notices that are contained in the Licensed Software on any copy thereof that You make or use.
6. TERM AND TERMINATION.
Except as otherwise provided in this Agreement, depending on the specific license level selected by you at the time of purchase or most recent upgrade, the term of the license granted herein is either perpetual, or alternatively the license is periodic, valid for a specific period of time, such as a month or a year.
The license becomes effective when You install or use the Licensed Software. You may terminate this license at any time by destroying any and all copies of the Licensed Software or by returning all such copies to e-iceblue.
This Agreement and the associated license for the Licensed Software will terminate automatically and without provision of notice by e-iceblue if You fail to comply with any of the terms or conditions of this Agreement or if You cease permanent use of the Licensed Software, for whatever reason.
Upon termination of this Agreement for any reason, You agree that You will destroy all copies of the Licensed Software or return all such copies to e-iceblue. In addition to this sentence and the previous sentence, Sections 4, 5 and 7-13 shall survive any termination of this Agreement.
7. LIMITED WARRANTY.
e-iceblue warrants that the Licensed Software will perform substantially in accordance with its accompanying documentation, when operated in the execution environment specified in such documentation, for the warranty period ending thirty (30) days following the date on which You first install or first use the Licensed Software.
This limited warranty is void if failure of the Licensed Software to conform to such warranty is caused in whole or in part by
(a) any defect in any hardware or other equipment used with the Licensed Software;
(b) any failure of any hardware or any other equipment used with the Licensed Software to function in accordance with applicable manufacturer's specifications for such items;
(c) any alteration, modification or enhancement of the Licensed Software by You or anyone other than e-iceblue;
(d) any failure by You or anyone else to follow e-iceblue's instructions with respect to proper use of the Licensed Software; or
(e) improper use, abuse, accident, neglect or negligence on the part of You or anyone other than e-iceblue.
e-iceblue will not be obligated to honor the limited warranty or provide any remedy thereunder unless the Licensed Software is returned to e-iceblue along with the original dated receipt.
Any replacement Licensed Software will be warranted for thirty (30) days following the date on which e-iceblue provides it to You.
EXCEPT AS OTHERWISE SET FORTH IN THIS AGREEMENT, THE LICENSED SOFTWARE IS PROVIDED TO YOU "AS IS", AND E-ICEBLUE MAKES NO EXPRESS OR IMPLIED WARRANTIES WHATSOEVER WITH RESPECT TO ITS FUNCTIONALITY, CONDITION, PERFORMANCE, OPERABILITY OR USE.
WITHOUT LIMITING THE FOREGOING, E-ICEBLUE DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR FREEDOM FROM INFRINGEMENT.
SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSIONS MAY NOT APPLY TO YOU.
THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS, AND YOU MAY ALSO HAVE OTHER RIGHTS THAT VARY FROM ONE JURISDICTION TO ANOTHER.
8. LIMITATIONS OF LIABILITY.
YOUR SOLE AND EXCLUSIVE REMEDY FOR ANY BREACH OF THE FOREGOING LIMITED WARRANTY SHALL BE, AT E-ICEBLUE'S OPTION, EITHER (A) REPAIR OR REPLACEMENT OF THE LICENSED SOFTWARE SO THAT IT CONFORMS TO THE FOREGOING LIMITED WARRANTY, OR (B) REFUND OF THE FEE THAT YOU PAID TO LICENSE THE LICENSED SOFTWARE.
IN NO EVENT SHALL E-ICEBLUE BE LIABLE FOR ANY DAMAGES OF ANY TYPE, WHETHER DIRECT OR INDIRECT, CONSEQUENTIAL, INCIDENTAL OR SPECIAL DAMAGES, INCLUDING WITHOUT LIMITATION, LOST REVENUES, LOST PROFITS, LOSSES RESULTING FROM BUSINESS INTERRUPTION OR LOSS OF DATA, REGARDLESS OF THE FORM OF ACTION OR LEGAL THEORY UNDER WHICH SUCH LIABILITY MAY BE ASSERTED, EVEN IF E-ICEBLUE HAS BEEN ADVISED OF THE POSSIBILITY OR LIKELIHOOD OF SUCH DAMAGES.
E-ICEBLUE SHALL HAVE NO LIABILITY WITH RESPECT TO ANY DATA THAT IS READ, ACCESSED, STORED OR PROCESSED WITH THE LICENSED SOFTWARE, OR FOR THE COSTS OF RECOVERING ANY SUCH DATA.
IN NO EVENT SHALL E-ICEBLUE'S MAXIMUM AGGREGATE LIABILITY UNDER THIS AGREEMENT EXCEED THE TOTAL FEES PAID OR PAYABLE BY YOU TO LICENSE THE LICENSED SOFTWARE.
SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU.
9. INDEMNIFICATION.
You agree to defend, indemnify, and hold E-iceblue and all of its employees, agents, representatives, directors, officers, partners, shareholders, attorneys, predecessors, successors, and assigns harmless from and against any and all claims, proceedings, damages, injuries, liabilities, losses, costs, and expenses (including reasonable attorneys' fees and litigation expenses), relating to or arising from Your use of the Licensed Software, or any breach of this Agreement, except to the extent such claim relates to or arises from a violation by e-iceblue of any third party copyright, trademark, trade secret or other intellectual property right.
10. EXPORT.
You agree that You will not export or transmit the Licensed Software or any Applications, directly or indirectly, to any restricted countries or in any manner that would violate United States laws and regulations as shall from time to time govern the license and delivery of technology abroad by persons subject to the jurisdiction of the United States government, including the Export Administration Act of 1979, as amended, and any applicable laws or regulations issued thereafter.
11. U.S. GOVERNMENT RESTRICTED RIGHTS.
If You are licensing the Licensed Software on behalf of the U.S. Government or any of its agencies ("Government"), the use, duplication, reproduction, release, modification, disclosure or transfer of the Licensed Software by the Government is subject to restricted rights in accordance with Federal Acquisition Regulation ("FAR") 12.212 for civilian agencies and Defense Federal Acquisition Regulation Supplement ("DFARS") 227.7202 for military agencies.
The Licensed Software is commercial. Use of the Licensed Software by the Government is further restricted in accordance with the terms and conditions of this Agreement.
12. MISCELLANEOUS.
If any provision of this Agreement is held to be invalid or unenforceable under any circumstances, its application in any other circumstances and the remaining provisions of this Agreement shall not be affected.
No waiver of any right under this Agreement shall be effective unless given in writing by an authorized representative of e-iceblue.
No waiver by e-iceblue of any right shall be deemed to be a waiver of any other right of e-iceblue arising under this Agreement.
This Agreement is solely between You and e-iceblue and shall not be construed to create any third party beneficiary rights in any other individual, partnership, corporation or other entity.
This Agreement shall be governed by and interpreted in accordance with the laws of the State of New York, without regard to its provisions governing conflicts of law.
Any and all disputes between You and e-iceblue pertaining to this Agreement shall be submitted to one arbitrator in binding arbitration within ten miles of New York City, New York in accordance with the Commercial Rules of the American Arbitration Association ("AAA").
The arbitrator shall be experienced in computer consulting, the development of custom software, the sale of packaged software, or related services.
If You and e-iceblue do not agree on an arbitrator within sixty (60) days of the institution of the arbitration, the arbitrator shall be chose by AAA.
Evidence and argument may be presented in person or by telephone, fax, postal mail, electronic mail, and other methods of communication approved by the arbitrator.
The prevailing party in such proceeding shall be entitled to recover its actually incurred costs, including reasonable attorney's fees, arbitration and court costs.
All hearings shall be held and a written arbitration award issued within one-hundred eighty (180) days of the date on which the arbitrator is appointed.
Judgment on the award shall be final and binding and may be entered in any court of competent jurisdiction.
13. ENTIRE AGREEMENT.
YOU AGREE THAT THIS AGREEMENT IS THE COMPLETE AND EXCLUSIVE STATEMENT OF THE AGREEMENT BETWEEN YOU AND E-ICEBLUE, AND THAT IT SUPERSEDES ANY PROPOSALS OR PRIOR AGREEMENTS, ORAL OR WRITTEN, AND ANY OTHER COMMUNICATIONS RELATING TO THE LICENSED SOFTWARE AND THE SUBJECT MATTER HEREOF.
E-ICEBLUE SHALL NOT BE BOUND BY ANY PROVISION OF ANY PURCHASE ORDER, RECEIPT, ACCEPTANCE, CONFIRMATION, CORRESPONDENCE OR OTHERWISE, OR BY ANY AGREEMENT BETWEEN YOU AND ANY OTHER PARTY, UNLESS E-ICEBLUE SPECIFICALLY AGREES TO SUCH PROVISION IN WRITING IN A FORM OF A LEGAL CONTRACT, DATED AND SIGNED BY YOU AND BY E-ICEBLUE'S OFFICER OR AUTHORIZED EMPLOYEE.
NO VENDOR, DISTRIBUTOR, PROVIDER, RESELLER, OEM, SALES REPRESENTATIVE, OR OTHER PERSON IS AUTHORIZED TO MODIFY THIS AGREEMENT OR TO MAKE ANY WARRANTY, REPRESENTATION OR PROMISE REGARDING THE LICENSED SOFTWARE WHICH IS DIFFERENT FROM THOSE SET FORTH IN THIS AGREEMENT.

84
Logger.cs Executable file → Normal file
View File

@@ -13,27 +13,22 @@ namespace bdf
{
sb.AppendFormat(format, objs);
}
catch (FormatException e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message);
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message, e.InnerException.Message);
}
if (level <= bdf.debug )
{
Console.WriteLine(sb.ToString());
bdf.outfile.WriteLine(sb.ToString());
}
if (level <= bdf.adlvl )
{
bdf.adminLog.AppendLine(sb.ToString());
}
}
/*
public static void Log(uint level, string format, string s1, string s2)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] ", DateTime.Now);
sb.AppendFormat(format, s1, s2);
}
if (level <= bdf.debug )
{
Console.WriteLine(sb.ToString());
@@ -44,40 +39,7 @@ namespace bdf
bdf.adminLog.AppendLine(sb.ToString());
}
}
public static void Log(uint level, string format, string s1)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] ", DateTime.Now);
sb.AppendFormat(format, s1);
if (level <= bdf.debug )
{
Console.WriteLine(sb.ToString());
bdf.outfile.WriteLine(sb.ToString());
}
if (level <= bdf.adlvl )
{
bdf.adminLog.AppendLine(sb.ToString());
}
}
public static void Log(uint level, string message)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] {1}", DateTime.Now, message);
if (level <= bdf.debug )
{
Console.WriteLine(sb.ToString());
bdf.outfile.WriteLine(sb.ToString());
}
if (level <= bdf.adlvl )
{
bdf.adminLog.AppendLine(sb.ToString());
}
}
*/
public static void Log(string message)
{
StringBuilder sb = new StringBuilder();
@@ -87,6 +49,26 @@ namespace bdf
bdf.adminLog.AppendLine(sb.ToString());
}
public static void Log(string task, string format, params object[] objs)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] ", task);
try
{
sb.AppendFormat(format, objs);
}
catch (FormatException e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message, e.InnerException.Message);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Logger: invalid parameters for formatting. {0}:{1}", e.Message, e.InnerException.Message);
}
bdf.reportfile.WriteLine(sb.ToString());
}
}
}

465
MegaT.cs
View File

@@ -5,17 +5,13 @@ using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Reflection;
namespace bdf
{
public class MegaT
{
// SIP Extractions section
// A class to hold the extracted data for a single row of SIP INSIS data
public class SIPData
// A class to hold the extracted data for a single row of INSIS data
public class INSISData
{
public string Item { get; set; }
public string Code { get; set; }
@@ -35,13 +31,12 @@ namespace bdf
}
}
public static List<SIPData> GetSIPDetails_bySCHED(string sched, ref CookieContainer cookies)
public static List<INSISData> GetRVNUDetails_bySCHED(string sched, ref CookieContainer cookies)
{
bool success = false;
byte[] webResp = null;
List<SIPData> sip_rvnu = new List<SIPData> { };
List<INSISData> rvnu_items = new List<INSISData> { };
success = Web.MakeRequest(
"GET",
@@ -53,7 +48,7 @@ namespace bdf
if (!success)
{
Logger.Log(5, "Get SIP INSIS TopLevel Details FAIL {0}", sched);
Logger.Log(5, "Get INSIS RVNU TopLevel Details FAIL {0}", sched);
}
string html = Encoding.ASCII.GetString(webResp);
@@ -63,16 +58,16 @@ namespace bdf
{
try
{
Dictionary<string, string> rvnu = SIP_RVNU_items(html);
HashSet<string > rvnu_links = RVNU_item_links(html);
foreach (var kvp in rvnu)
foreach (var link in rvnu_links)
{
success = false;
webResp = null;
success = Web.MakeRequest(
"GET",
"http://megatool.rogers.com/megatool/megatool/INSIS/" + kvp.Value.ToString(),
"http://megatool.rogers.com/megatool/megatool/INSIS/" + link.ToString(),
false,
"",
ref webResp,
@@ -80,13 +75,14 @@ namespace bdf
if (!success)
{
Logger.Log(5, "Get INSIS RVNU Details FAIL {0}-{1} {2}", sched, kvp.Key, webResp);
Logger.Log(5, "Get INSIS RVNU Details FAIL {0}-{1} {2}", sched, link, webResp);
}
string html2 = Encoding.ASCII.GetString(webResp);
SIPData x = ExtractSIPData(html2);
sip_rvnu.Add(x);
Logger.Log(6, "Desc: {0} sip_rnvu size {1}", x.Description, sip_rvnu.Count);
INSISData x = ExtractINSISData(html2);
if (!x.BillingType.Contains("Delete")) // Feb 12 2026
rvnu_items.Add(x);
Logger.Log(6, "Desc: {0} | rvnu_items size={1}", x.Description, rvnu_items.Count);
}
@@ -96,12 +92,12 @@ namespace bdf
Logger.Log(0, "Error SCHED {0} - SIP HTML={0}", sched, e.Message);
}
}
return sip_rvnu;
return rvnu_items;
}
public static Dictionary<string, string> SIP_RVNU_items(string html)
public static HashSet<string> RVNU_item_links(string html)
{
Dictionary<string, string> result = new System.Collections.Generic.Dictionary<string, string>( System.StringComparer.OrdinalIgnoreCase);
HashSet<string> result = new HashSet<string>(System.StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrWhiteSpace(html))
return result;
@@ -132,27 +128,9 @@ namespace bdf
if (tdMatches.Count < 5)
continue;
// ----- Extract Service Code (5th <td>) -----
string serviceCode =
System.Text.RegularExpressions.Regex.Replace(
tdMatches[4].Groups[1].Value,
"<[^>]+>",
string.Empty
).Trim();
if (serviceCode.Length == 0)
continue;
// Skip "Install" rows
if (serviceCode.IndexOf("Install", System.StringComparison.OrdinalIgnoreCase) >= 0)
{
//Console.WriteLine("skipping [{0}]", serviceCode);
continue;
}
// ----- Extract openIt('...') from 4th <td> -----
string fourthTd = tdMatches[3].Groups[1].Value;
//Console.WriteLine("4th [{0}]", fourthTd);
//Logger.Log(6,"4th [{0}]", fourthTd);
string openItValue = "";
if (fourthTd.IndexOf("RVNU", System.StringComparison.OrdinalIgnoreCase) >= 0)
@@ -167,36 +145,31 @@ namespace bdf
if (!onclickMatch.Success)
{
//Console.WriteLine("no match");
Logger.Log(3,"no rvnu match");
continue;
}
openItValue = onclickMatch.Groups["openit"].Value.Trim();
}
else // Skip non-RVNU rows
{
//Console.WriteLine("non-revenue [{0}]", fourthTd);
Logger.Log(4,"non-revenue [{0}]", fourthTd);
continue;
}
// Avoid duplicate keys
if (!result.ContainsKey(serviceCode))
{
result.Add(serviceCode, openItValue);
}
result.Add(openItValue);
}
return result;
}
public static SIPData ExtractSIPData(string html)
public static INSISData ExtractINSISData(string html)
{
var extractedData = new SIPData();
var extractedData = new INSISData();
// Regex to find table rows (<tr>) within a specific table structure (adjust if needed, e.g., using a table ID)
// The pattern uses capturing groups for each <td> content
// It assumes <td> tags might have extra spaces or attributes, but the content inside is the target.
Dictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrWhiteSpace(html))
@@ -220,17 +193,17 @@ namespace bdf
if (!result.ContainsKey(heading))
{
result.Add(heading.Replace(" ", ""), value); //Remove field label spaces to make them valid dictionary entries
Logger.Log(3, "Found: {0}={1}", heading, value);
Logger.Log(5, "Found: {0}={1}", heading, value);
}
}
System.Type type = typeof(SIPData);
System.Type type = typeof(INSISData);
foreach (System.Reflection.PropertyInfo prop in type.GetProperties(
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public))
{
//Console.WriteLine("a4n {0} : {1}", prop.PropertyType.Name, prop.Name);
Logger.Log(6,"a4n {0} : {1}", prop.PropertyType.Name, prop.Name);
if (prop.PropertyType != typeof(string))
continue;
@@ -240,7 +213,7 @@ namespace bdf
if (result.TryGetValue(prop.Name, out string value))
{
//Console.WriteLine("a5 {0}", value);
Logger.Log(6,"a5 {0}", value);
try
{
prop.SetValue( extractedData, (string)value);
@@ -254,6 +227,7 @@ namespace bdf
return extractedData;
}
// Takes MM-d-yyyy and converts to yyyyMMdd
public static string ConvertDate(string input)
{
System.DateTime date =
@@ -267,291 +241,7 @@ namespace bdf
}
//------------------------------------
/*
public static Dictionary<string, string> ExtractServiceCodesFromTable(string html)
{
Dictionary<string, string> result = new Dictionary<string, string>();
if (string.IsNullOrWhiteSpace(html))
return result;
// Match each <tr> with id="R<number>", including multi-line content
string trPattern = @"<tr[^>]*id\s*=\s*['""]R\d+['""][^>]*>(.*?)</tr>";
var trMatches = Regex.Matches(
html,
trPattern,
RegexOptions.IgnoreCase | RegexOptions.Singleline // Singleline allows . to match newlines
);
foreach (Match trMatch in trMatches)
{
string trContent = trMatch.Groups[1].Value;
// Match all <td> elements inside the <tr>
var tdMatches = Regex.Matches(
trContent,
@"<td[^>]*>(.*?)</td>",
RegexOptions.IgnoreCase | RegexOptions.Singleline
);
if (tdMatches.Count >= 4)
{
string fourthTd = tdMatches[3].Groups[1].Value;
// Extract openIt('...') string inside the <a> tag
string onclickPattern = @"openIt\('(?<openit>[^']+)'\)";
var onclickMatch = Regex.Match(fourthTd, onclickPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (onclickMatch.Success)
{
string openItValue = onclickMatch.Groups["openit"].Value.Trim();
//result.Add(openItValue);
Console.WriteLine("Found {0}", openItValue);
}
}
}
return result;
}
/*
// Match each <tr> row
string rowPattern = @"<tr[^>]*id\s*=\s*['""]R\d+['""][^>]*>(.*?)</tr>";
MatchCollection rowMatches = Regex.Matches(html, rowPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
foreach (Match rowMatch in rowMatches)
{
string rowContent = rowMatch.Groups[1].Value;
Console.WriteLine("<TR> {0}", rowContent);
foreach (Match trMatch in rowContent)
{
string trContent = trMatch.Groups[1].Value;
Console.WriteLine("<TR> {0}", trContent);
// Match all <td> elements inside the <tr>
var tdMatches = Regex.Matches(
trContent,
@"<td[^>]*>(.*?)</td>",
RegexOptions.IgnoreCase | RegexOptions.Singleline
);
if (tdMatches.Count >= 4)
{
string fourthTd = tdMatches[3].Groups[1].Value;
// Extract openIt('...') string inside the <a> tag
string onclickPattern = @"openIt\('(?<openit>[^']+)'\)";
var onclickMatch = Regex.Match(fourthTd, onclickPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (onclickMatch.Success)
{
string openItValue = onclickMatch.Groups["openit"].Value.Trim();
result.Add(openItValue);
}
}
}
// Match <a ... onclick='...' ...> followed by <td> with service code
string cellPattern =
@"<a[^>]*onclick\s*=\s*['""][^'""]*'(?<onclick>[^']+)'[^'""]*['""][^>]*>.*?</a>.*?" +
@"<td[^>]*>\s*(?<code>[^<\s][^<]*)\s*</td>";
Match cellMatch = Regex.Match(rowContent, cellPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (cellMatch.Success)
{
string onclick = cellMatch.Groups["onclick"].Value.Trim();
string code = cellMatch.Groups["code"].Value.Trim();
if (!string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(onclick))
{
// Avoid duplicate keys
if (!result.ContainsKey(code))
result[code] = onclick;
Console.WriteLine("Found {0} : {1}", code, onclick);
}
}
}
return result;
*/
// from Megatool RVNU sub-page, return extracted SIPData item
// old
public static List<SIPData> ExtractSIPData_RevScreen(string htmlContent)
{
var extractedData = new List<SIPData>();
// Regex to find table rows (<tr>) within a specific table structure (adjust if needed, e.g., using a table ID)
// The pattern uses capturing groups for each <td> content
// It assumes <td> tags might have extra spaces or attributes, but the content inside is the target.
string rowPattern = @"<tr\s*[^>]*?\bid=[^>]*?>(.*?)</tr\s*>"; //@"<tr\s*[^>]*>(.*?)</tr\s*>";
string cellPattern = @"<td\s*[^>]*>[$]*(.*?)</td>";
// Find all rows in the HTML
MatchCollection rows = Regex.Matches(htmlContent, rowPattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
foreach (Match rowMatch in rows)
{
string rowHtml = rowMatch.Groups[1].Value;
// Find all cells in the current row
MatchCollection cells = Regex.Matches(rowHtml, cellPattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
// Check if the row has exactly 9 columns of data (Item, Description, Unit Price, Qty, Amount)
if (cells.Count >= 9)
{
// Extract the inner text and clean up whitespace
string item = cells[0].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string code = cells[1].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string description = cells[2].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string period = cells[3].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string unitPrice = cells[4].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string qty = cells[5].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string amount = cells[6].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string billingType = cells[7].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string currency = cells[8].Groups[1].Value.Replace("&nbsp;", " ").Trim();
// Add to the list
extractedData.Add(new SIPData
{
Item = item,
Code = code,
Description = description,
Period = period,
UnitPrice = unitPrice,
Quantity = qty,
Amount = amount,
BillingType = billingType,
Currency = currency
});
}
}
return extractedData;
}
//old version
public static double getSIP_RVNU(string sched, ref CookieContainer cookies)
{
bool success = false;
double mrr = 0;
byte[] webResp = null;
success = Web.MakeRequest(
"GET",
"http://megatool.rogers.com/megatool/megatool/INSIS/insisMainwindow.asp?serv_id=" + sched,
false,
"",
ref webResp,
ref cookies);
if (!success)
{
Logger.Log(5, "MRR FAIL {0}", sched);
}
string html = Encoding.ASCII.GetString(webResp);
if (html.Length > 5000)
{
try
{
Regex word = new Regex(@"<tr\b[^>]*>[\s\S]*?Total\s+MRR[\s\S]*?\$\s*([0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{2})?)[\s\S]*?<\/tr>"); // find MRR dollar value
Match m = word.Match(html); //
if (m.Success)
{
Group g = m.Groups[1];
//Capture c = g.Captures[0];
Logger.Log(6, "Regex Match {0} / Group Count {1} / Captures Count {2} / result={3}", m.Success, m.Groups.Count, m.Captures.Count, g.Value);
mrr = Convert.ToDouble(g.Value);
if ((mrr >= 0) && (mrr <= 999999))
Logger.Log(5, "MRR found successfully {0}", mrr);
}
else
{
Logger.Log(1, "No MRR found.");
}
}
catch (Exception e)
{
Logger.Log(0, "Error parsing MRR {0}", e.Message);
}
}
return mrr;
}
// _RevScreen
public static List<SIPData> GetSIPDetails(string sched, ref CookieContainer cookies)
{
string token = "";
bool success = false;
byte[] webResp = null;
string html = "";
// http://megatool.rogers.com/megatool/megatool/INSIS/revenue.asp?logo=N&serv_id==
if (sched != "dummy")
{
success = Web.MakeRequest(
"GET",
"http://megatool.rogers.com/megatool/megatool/INSIS/revenue.asp?logo=N&serv_id=" + sched,
false,
"",
ref webResp,
ref cookies);
if (!success)
{
Logger.Log(0, "Get SIP details fail{0}", token);
}
//Console.WriteLine(Encoding.ASCII.GetString(webResp));
html = Encoding.ASCII.GetString(webResp);
}
else
{
success = true;
html = "";
}
List<SIPData> data = new List<SIPData> { };
// SIP details extraction
try
{
// data = ExtractSIPData(html);
SIPData junk = ExtractSIPData(html);
/*
foreach (var row in data)
{
//Console.WriteLine(row.ToString());
if ( row.Description.Contains("Access") ) Logger.Log(1,"Found Access: {0} x {1}", row.UnitPrice, row.Qty);
if ( row.Description.Contains("Session") ) Logger.Log(1, "Found Sessions: {0} x {1}", row.UnitPrice, row.Qty);
}
*/
}
catch (Exception e)
{
Logger.Log(0, "Exception: SIP Details {0}:{1}", e.Message, e.InnerException.Message);
}
return data; // no match found
}
//------------------------------------
// SCHED-A Info Extraction
// SCHED-A Info Extraction from "Schedule Details" Megatool page, most import is SO<->SCHED mapping
public static Dictionary<string, string> GetParms(string sched, ref CookieContainer cookies)
{
string token = "";
@@ -561,7 +251,8 @@ namespace bdf
Dictionary<string, string> parms = new Dictionary<string, string> { };
if (sched != "dummy")
//if (sched != "dummy")
if ( sched.Length != 3 ) // not a 'dummy' request
{
success = Web.MakeRequest(
"GET",
@@ -586,7 +277,7 @@ namespace bdf
html = "";
}
//following builds the columns in order, one IF per column
try
{
// SO + up to 5 non-digits + six digits
@@ -746,63 +437,19 @@ namespace bdf
{
Logger.Log(0, "Exception: {0}:{1}", e.Message, e.InnerException.Message);
}
if (sched.ToUpper() == "SIP") // add SIP extension columns to Megatool table to track Sessions and Access costs
{
parms.Add("AQty", "XXX");
parms.Add("ACst", "XXX");
parms.Add("SQty", "XXX");
parms.Add("SCst", "XXX");
}
return parms; // no match found
}
// <tr\b[^>]*>[\s\S]*?MRR[\s\S]*?\$\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)[\s\S]*?</tr>
public static double getMRR(string sched, ref CookieContainer cookies)
{
bool success = false;
double mrr = 0;
byte[] webResp = null;
success = Web.MakeRequest(
"GET",
"http://megatool.rogers.com/megatool/megatool/INSIS/insisMainwindow.asp?serv_id=" + sched,
false,
"",
ref webResp,
ref cookies);
if (!success)
{
Logger.Log(5, "MRR FAIL {0}", sched);
}
string html = Encoding.ASCII.GetString(webResp);
if (html.Length > 5000)
{
try
{
Regex word = new Regex(@"<tr\b[^>]*>[\s\S]*?Total\s+MRR[\s\S]*?\$\s*([0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{2})?)[\s\S]*?<\/tr>"); // find MRR dollar value
Match m = word.Match(html); //
if (m.Success)
{
Group g = m.Groups[1];
//Capture c = g.Captures[0];
Logger.Log(6, "Regex Match {0} / Group Count {1} / Captures Count {2} / result={3}", m.Success, m.Groups.Count, m.Captures.Count, g.Value);
mrr = Convert.ToDouble(g.Value);
if ((mrr >= 0) && (mrr <= 999999))
Logger.Log(5, " {1} MRR found successfully {0}", mrr, sched);
}
else
{
Logger.Log(1, "No MRR found.");
}
}
catch (Exception e)
{
Logger.Log(0, "Error parsing MRR {0}", e.Message);
}
}
return mrr;
}
// Deal with filtering out which SCHEDs are actually active with a given prefix
public static bool SchedXL(string sched, ref CookieContainer cookies)
{
string token = "";
@@ -906,7 +553,9 @@ namespace bdf
break;
string value = html.Substring(start, end - start);
scheds.Add(value);
if ( !scheds.Exists(s => s == value) ) // skip any duplicate SCHEDA entries, such as with WAVs
scheds.Add(value);
index = end + endKey.Length;
}
@@ -921,22 +570,27 @@ namespace bdf
bool success = false;
// Explicit credentials (domain\user)
var creds = new NetworkCredential(user, pass, "RCI");
// var creds = new NetworkCredential(user, pass, "RCI");
// Add to global cred cache for NTLM auth - Needed to survive Windows 11 / .NET481. Works fine in Mono or with Fiddler, but not straight .exe
bdf.cache.Add(new Uri(url), "NTLM", CredentialCache.DefaultNetworkCredentials);
// A cookie container is REQUIRED to capture session cookies
// var cookies = new CookieContainer();
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.AllowAutoRedirect = false; // Required for NTLM handshake
request.PreAuthenticate = false; // NTLM cannot pre-authenticate
request.PreAuthenticate = true;
//request.PreAuthenticate = false; // NTLM cannot pre-authenticate
request.UseDefaultCredentials = false;
request.Credentials = creds; // Enables SSPI NTLM handshake
request.Credentials = bdf.cache;
//request.Credentials = creds; // Enables SSPI NTLM handshake
request.CookieContainer = cookies; // Store session cookies
request.KeepAlive = true; // NTLM requires same connection
//request.UnsafeAuthenticatedConnectionSharing = true;
request.UserAgent = "NTLMClient/.NET4.8";
Logger.Log(1, "Megatool NTLM authentication for ({0})...", user);
Logger.Log(1, "Megatool authentication for ({0})...", user);
HttpWebResponse response;
@@ -963,11 +617,7 @@ namespace bdf
{
body = reader.ReadToEnd();
}
/*
Console.WriteLine("\n--- Page Content ---\n");
Console.WriteLine(body);
Console.WriteLine("\n--- Cookies Received ---");
*/
foreach (Cookie ck in cookies.GetCookies(request.RequestUri))
{
Logger.Log(5, $"{ck.Name} = {ck.Value}; Domain={ck.Domain}; Path={ck.Path}");
@@ -978,7 +628,6 @@ namespace bdf
return success;
}
}
}
}

601
PDF.cs
View File

@@ -1,25 +1,76 @@
using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization;
using Spire.Xls;
using System.Reflection;
using System.Threading.Tasks;
using Renci.SshNet;
namespace bdf
{
public class Taxes // Stores by-province taxes for Invoices
{
public double PST { get; set; }
public double GST { get; set; }
public double HST { get; set; }
public Taxes(double value1, double value2, double value3)
{
this.PST = value1;
this.GST = value2;
this.HST = value3;
}
public Taxes(Taxes tax, double value1, double value2, double value3)
{
this.PST = tax.PST + value1;
this.GST = tax.GST + value2;
this.HST = tax.HST + value3;
}
public double Totaled()
{
return this.PST + this.GST + this.HST;
}
}
public class InvoiceCell // Invoice Cells from Invoice Template
{
public String Account { get; set; } = "I2"; // "Account"+ (also I32)
public String Date { get; set; } = "I3"; // I3 (also I33)
public String Invoice { get; set; } = "I4"; //I4 "Invoice" (also I34)
public String Total_Charges { get; set; } = "I14"; //I14 (also I36)
public String Account { get; set; } = "I2"; // "Account"+ (also I40)
public String Date { get; set; } = "I3"; // I3 (also I41)
public String Invoice { get; set; } = "I4"; //I4 "Invoice" (also I42)
public String Total_Charges { get; set; } = "I14"; //I14 (also I44)
public String Account2 { get; set; } = "I32"; // "Account"+ (also I32)
public String Date2 { get; set; } = "I33"; // I3 (also I33)
public String Invoice2 { get; set; } = "I34"; //I4 "Invoice" (also I34)
public String Total_Charges2 { get; set; } = "I36"; //I14 (also I36)
public String Account2 { get; set; } = "I40"; // "Account"+
public String Date2 { get; set; } = "I41"; // I3
public String Invoice2 { get; set; } = "I42"; //I4 "Invoice"
public String Total_Charges2 { get; set; } = "I44"; //I14
public String Addr_Dept { get; set; } = "C7";
public String Addr_Client { get; set; } = "C8"; //Maps to D7
public String Addr_Street { get; set; } = "C9"; //Maps to D8
public String Addr_City { get; set; } = "C10"; //Maps to D9
public String Addr_PC { get; set; } = "C11"; //Maps to D10
public String SrvAddr_1 { get; set; } = "D7";
public String SrvAddr_2 { get; set; } = "D8"; //Maps to D7
public String SrvAddr_3 { get; set; } = "D9"; //Maps to D8
public String SrvAddr_4 { get; set; } = "D10"; //Maps to D9
public String BackBill_Title { get; set; } = "C26"; //for SIP
public String BackBill_Charges { get; set; } = "H26";//for SIP
public String _Hidden_SO { get; set; } = ""; //for SIP
public String _Hidden_Acct { get; set; } = ""; //for SIP
public String _Hidden_Addr1 { get; set; } = ""; //for SIP
public String _Hidden_Addr2 { get; set; } = ""; //for SIP
public String _Hidden_Addr3 { get; set; } = ""; //for SIP
public String _Hidden_Addr4 { get; set; } = ""; //for SIP
public Dictionary<string, Taxes> TX { get; set; } = new Dictionary<string, Taxes> {}; // format of "ON" pst,gst,hst
public String CCI { get; set; } = "C12"; // C12 "Canada Contract Identifier"
@@ -41,159 +92,8 @@ namespace bdf
public String Taxes { get; set; } = "I31";
}
/*
// Source - https://stackoverflow.com/a
// Posted by Alexandru
// Retrieved 2025-12-03, License - CC BY-SA 3.0
internal class OutputSink : IDisposable
{
[DllImport("kernel32.dll")]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")]
public static extern int SetStdHandle(int nStdHandle, IntPtr hHandle);
private readonly TextWriter _oldOut;
private readonly TextWriter _oldError;
private readonly IntPtr _oldOutHandle;
private readonly IntPtr _oldErrorHandle;
public OutputSink()
{
_oldOutHandle = GetStdHandle(-11);
_oldErrorHandle = GetStdHandle(-12);
_oldOut = Console.Out;
_oldError = Console.Error;
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
SetStdHandle(-11, IntPtr.Zero);
SetStdHandle(-12, IntPtr.Zero);
}
public void Dispose()
{
SetStdHandle(-11, _oldOutHandle);
SetStdHandle(-12, _oldErrorHandle);
Console.SetOut(_oldOut);
Console.SetError(_oldError);
}
}
*/
public class PDF
{
public static void Demo()
{
//MakePDF();
Dictionary<string, string> Invoice = new Dictionary<string, string> { };
InvoiceCell ic = new InvoiceCell { };
Invoice.Add(ic.Account, "Account P02-" + "123456"); //bdf2 C2
int d = 20250731;
Invoice.Add(ic.Date, dateFormal(d));
//string dt = "20250930";
Invoice.Add(ic.Invoice, ("Invoice " + d.ToString().Substring(4) + d.ToString().Substring(0, 4) + " - NU")); //mmddyyyy
Invoice.Add(ic.Total_Charges, String.Format("${0:n}", 10000));
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]);
customInvoice("doug", "", ref Invoice);
}
static void MakePDF()
{
// Create a Workbook object
Spire.Xls.Workbook workbook = new Spire.Xls.Workbook();
// Load an Excel file (replace with your file path)
workbook.LoadFromFile("test.xlsx");
//PdfFont fieldFont = new PdfFont(PdfFontFamily.Helvetica, 10f);
// Get the first worksheet
Spire.Xls.Worksheet sheet = workbook.Worksheets[0];
// Set the print area to a specific cell range
// Comment this line out if you need to export the entire worksheet as a PDF
//sheet.PageSetup.PrintArea = "B1:E6";
// Optional: Set worksheets to fit to page when converting
workbook.ConverterSetting.SheetFitToPage = true;
// Save the Excel file to PDF
workbook.SaveToFile("Output.pdf", FileFormat.PDF);
// Dispose resources
workbook.Dispose();
}
static void LoadStream()
{
// 1. Create a Workbook instance
Workbook workbook = new Workbook();
// 2. Create a Stream object (example using FileStream)
// Replace "sample.xls" with your actual file path or retrieve the stream from your source
FileStream fileStream = System.IO.File.OpenRead("sample.xls");
// Ensure the stream position is at the beginning (if necessary)
fileStream.Seek(0, SeekOrigin.Begin);
// 3. Use the Workbook.LoadFromStream() method to load the file
try
{
workbook.LoadFromStream(fileStream);
}
catch (Exception ex)
{
// Handle exceptions, e.g., file format not supported (Excel 95 or earlier not supported)
Logger.Log(0, "Error loading stream: {0}", ex.Message);
}
finally
{
// 4. Close the stream after loading
fileStream.Dispose();
}
// Now you can work with the workbook data
Worksheet sheet = workbook.Worksheets[0];
// ... do operations like reading cells, etc. ...
// Example of saving the processed file to a new file
workbook.SaveToFile("From_stream_processed.xls", ExcelVersion.Version97to2003);
Process.Start("From_stream_processed.xls");
}
static void LoadStreamXLSX()
{
// 1. Create a Workbook instance
Workbook workbook = new Workbook();
// 2. Open a FileStream from your source file
using (FileStream fileStream = System.IO.File.OpenRead("Sample.xlsx"))
{
// Ensure the stream position is at the beginning
fileStream.Seek(0, SeekOrigin.Begin);
// 3. Load the workbook from the stream
workbook.LoadFromStream(fileStream);
// 4. (Optional) Work with the workbook, e.g., modify a cell
workbook.Worksheets[0].Range["A1"].Text = "Data loaded from stream!";
// (Optional) Save the result to a new stream or file
// workbook.SaveToStream(outputStream);
// workbook.SaveToFile("Output.xlsx", ExcelVersion.Version2016);
}
}
public static Workbook LoadEmbeddedWorkbook(string resourceName)
{
@@ -213,7 +113,225 @@ namespace bdf
return wb;
}
public static void customInvoice(string type, string trace, ref Dictionary<string, string> CellData)
// this version creates PDF invoice with 1 line per type of provincial taxes, first line is 29, line 30 in template must be handled and line 31 has the totals
public static MemoryStream customInvoiceAsMS_taxes(ref Dictionary<string, string> CellData, ref InvoiceCell ic)
{
MemoryStream ms = new MemoryStream();
Workbook workbook = new Workbook();
string fontDirectory = AppDomain.CurrentDomain.BaseDirectory; // for non Windows systems use the .exe folder
string[] fontDirectories = { fontDirectory };
/*
foreach( var kvp in ic.TX)
{
Console.WriteLine("TX: {4} - {3} PST={0:N2} GST={1:N2} HST={2:N2} TOTAL={5:N2}", kvp.Value.PST, kvp.Value.GST, kvp.Value.HST, kvp.Key, CellData[ic.Invoice],kvp.Value.Totaled());
}
*/
workbook = LoadEmbeddedWorkbook("BDF.Embedded.template.xlsx");
int dpi = 600;// image conversion resolution
workbook.ConverterSetting.XDpi = (dpi);
workbook.ConverterSetting.YDpi = (dpi);
workbook.ConverterSetting.JPEGQuality = 99;
workbook.CustomFontFileDirectory = fontDirectories;
foreach (var cell in CellData)
{
if (cell.Key != "")
workbook.Worksheets[0].Range[cell.Key].Text = cell.Value;
} // end foreach
// Now we modify the TAX lines starting on row 29.
// Col C - DataPROV ColF/G/H - PST/GST/HST and Col I for total
Worksheet sheet = workbook.Worksheets[0];
double TotalTax = 0;
int add_row = 29; // these are Excel 1-based
int tot_row = 30;
// Add in correct number of rows for pending data
for (int i = 1; i<ic.TX.Count; i++)
{
Logger.Log(3,"add={0} tot={1} count={2} i={3}", add_row, tot_row, ic.TX.Count, i);
InsertAndCopyRow(sheet, add_row, add_row + 1);
tot_row++;
sheet.DeleteRow(tot_row+1);
}
foreach (var prov in ic.TX)
{
sheet[add_row, 3].Value = "Data-" + prov.Key;
sheet[add_row, 6].NumberValue = prov.Value.PST;
sheet[add_row, 7].NumberValue = prov.Value.GST;
sheet[add_row, 8].NumberValue = prov.Value.HST;
TotalTax += prov.Value.Totaled();
Logger.Log(3, "row={0} amt={1} tot={2}", add_row, TotalTax, tot_row);
add_row++;
}
sheet[tot_row, 9].NumberValue = TotalTax;
workbook.ConverterSetting.SheetFitToPage = true;
ExcelDocumentProperties edp = new ExcelDocumentProperties { };
edp.Title = "BDF Invoice for " + CellData[ic.Account];
edp.Subject = CellData[ic.Invoice];
edp.Author = bdf.fullUser;
edp.Comments += "\n" + DateTime.Now.ToString();
edp.ApplyTo(workbook);
//Load ARIAL.TTF font to working dir if needed
try
{
workbook.SaveToStream(ms, FileFormat.PDF);
}
catch (Exception e)
{
bdf.ExtractResourceToFile("BDF.Embedded.arial.ttf", (AppDomain.CurrentDomain.BaseDirectory + "./arial.ttf")); // arial.ttf is needed to render the PDF
workbook.SaveToStream(ms, FileFormat.PDF);
Logger.Log(1, "Error Rendering PDF Invoice", e.Message);
}
return ms;
}
public static void InsertAndCopyRow(Worksheet sheet,int sourceRowIndex,int targetRowIndex)
{
sheet.InsertRow(targetRowIndex);
int lastColumn = sheet.LastColumn;
for (int col = 1; col <= lastColumn; col++)
{
CellRange sourceCell = sheet.Range[sourceRowIndex, col];
CellRange targetCell = sheet.Range[targetRowIndex, col];
// Copy value
targetCell.Value2 = sourceCell.Value2;
// Copy formula if present
if (!string.IsNullOrEmpty(sourceCell.Formula))
targetCell.Formula = sourceCell.Formula;
// Copy number format
targetCell.NumberFormat = sourceCell.NumberFormat;
// Copy font properties
targetCell.Style.Font.FontName = sourceCell.Style.Font.FontName;
targetCell.Style.Font.Size = sourceCell.Style.Font.Size;
targetCell.Style.Font.IsBold = sourceCell.Style.Font.IsBold;
targetCell.Style.Font.IsItalic = sourceCell.Style.Font.IsItalic;
targetCell.Style.Font.Color = sourceCell.Style.Font.Color;
// Copy fill
targetCell.Style.Color = sourceCell.Style.Color;
// Copy alignment
targetCell.Style.HorizontalAlignment = sourceCell.Style.HorizontalAlignment;
targetCell.Style.VerticalAlignment = sourceCell.Style.VerticalAlignment;
// Copy borders
targetCell.Style.Borders[BordersLineType.EdgeLeft].LineStyle =
sourceCell.Style.Borders[BordersLineType.EdgeLeft].LineStyle;
targetCell.Style.Borders[BordersLineType.EdgeRight].LineStyle =
sourceCell.Style.Borders[BordersLineType.EdgeRight].LineStyle;
targetCell.Style.Borders[BordersLineType.EdgeTop].LineStyle =
sourceCell.Style.Borders[BordersLineType.EdgeTop].LineStyle;
targetCell.Style.Borders[BordersLineType.EdgeBottom].LineStyle =
sourceCell.Style.Borders[BordersLineType.EdgeBottom].LineStyle;
}
// Copy row height
sheet.SetRowHeight(
targetRowIndex,
sheet.GetRowHeight(sourceRowIndex));
}
public static MemoryStream customInvoiceAsMS(ref Dictionary<string, string> CellData)
{
MemoryStream ms = new MemoryStream();
Workbook workbook = new Workbook();
string fontDirectory = AppDomain.CurrentDomain.BaseDirectory; // for non Windows systems use the .exe folder
string[] fontDirectories = { fontDirectory };
workbook = LoadEmbeddedWorkbook("BDF.Embedded.template.xlsx");
int dpi = 600;// image conversion resolution
workbook.ConverterSetting.XDpi = (dpi);
workbook.ConverterSetting.YDpi = (dpi);
workbook.ConverterSetting.JPEGQuality = 99;
workbook.CustomFontFileDirectory = fontDirectories;
foreach (var cell in CellData)
{
if ( cell.Key != "" )
workbook.Worksheets[0].Range[cell.Key].Text = cell.Value;
} // end foreach
workbook.ConverterSetting.SheetFitToPage = true;
//Load ARIAL.TTF font to working dir if needed
try
{
workbook.SaveToStream(ms, FileFormat.PDF);
}
catch (Exception e)
{
bdf.ExtractResourceToFile("BDF.Embedded.arial.ttf", (AppDomain.CurrentDomain.BaseDirectory + "./arial.ttf")); // arial.ttf is needed to render the PDF
workbook.SaveToStream(ms, FileFormat.PDF);
Logger.Log(1, "Error Rendering PDF Invoice", e.Message);
}
return ms;
}
public static void customInvoiceSaveFile(string type, string trace, MemoryStream ms)
{
ms.Position = 0;
string svc_path = bdf.upload ? bdf.base_path + "BDF_Archive" + Path.DirectorySeparatorChar : "";
string pdf_name = bdf.upload ? type.ToUpper() : "." + Path.DirectorySeparatorChar + type.ToUpper() + "_INV" + trace + ".pdf";
if (!bdf.FileIsWritable(svc_path + pdf_name)) return;
File.WriteAllBytes(svc_path + pdf_name, ms.ToArray());
Logger.Log(0, "PDF written! ({0})", svc_path + pdf_name);
}
public static void customInvoiceSFTPUpload(string type, string trace, MemoryStream ms)
{
//string pdf_name = bdf.upload ? type.ToUpper() : "." + Path.DirectorySeparatorChar + type.ToUpper() + "_INV" + trace + ".pdf";
string pdf_name = type.ToUpper() + Path.DirectorySeparatorChar + type.ToUpper() + "_INV" + trace + ".pdf";
{
Logger.Log(0, " Initiating {0}-INV upload to EFT server...", type);
try
{
//using (var ms = new MemoryStream())
{
try
{
sftp.Upload_Stream(ms, "Outbox" + Path.DirectorySeparatorChar + pdf_name, bdf.sshDetails);
}
catch (Exception e)
{
Logger.Log(0, "INV SFTP Upload Exception: {0}:{1}", e.Message, e.InnerException.Message);
return;
}
//Logger.Log(" Invoice uploaded.");
}
}
catch (Exception e)
{
Logger.Log(0, "INVSFTP Upload Exception: {0}:{1}", e.Message, e.InnerException.Message);
return;
}
}
}
public static void customInvoice_orig(string type, string trace, ref Dictionary<string, string> CellData)
{
//string fontDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "");
string fontDirectory = AppDomain.CurrentDomain.BaseDirectory; // for non Windows systems use the .exe folder
@@ -221,44 +339,14 @@ namespace bdf
//string[] fontDirectories = { fontDirectory, fontDirectory2 };
string[] fontDirectories = { fontDirectory };
/* Set the custom font file directory for the workbook instance
TextWriter originalOutput = Console.Out;
// Temporarily suppress console output
Console.SetOut(TextWriter.Null);
Workbook workbook = new Workbook(); // spews Not Implemented error
// Restore the original standard output writer
//Console.SetError(originalOutput);
//Console.SetOut(originalOutput);
/*
// Store the original listeners
var originalListeners = Debug.Listeners;
// Temporarily clear the listeners to suppress all Debug output
Debug.Listeners.Clear();
// Code here that generates unwanted debug output (e.g., a noisy library call)
Workbook workbook = new Workbook(); // spews Not Implemented error
// Re-add the original listeners (or just the DefaultTraceListener)
Debug.Listeners.Add(new DefaultTraceListener());
*/
Workbook workbook = new Workbook();
workbook = LoadEmbeddedWorkbook("BDF.Embedded.template.xlsx");
Logger.Log(" ...this will take a few seconds");
int dpi = 600;// image conversion resolution
workbook.ConverterSetting.XDpi = (dpi);
workbook.ConverterSetting.YDpi = (dpi);
workbook.ConverterSetting.JPEGQuality = 99;
//workbook.ConverterSetting.
// Create PdfSaveOptions instance
//PdfSaveOptions options = new Converter.PdfSaveOptions();
@@ -266,64 +354,69 @@ namespace bdf
// Set a higher image resolution (e.g., 300 dpi for print quality)
//options.ImageResolution = 600; // You can experiment with values like 144, 220, or 300
// Save to PDF using the options
//workbook.SaveToFile("output_high_quality.pdf", options);
/*
using (new OutputSink())
{
Console.WriteLine("a");
workbook = new Workbook(); // spews Not Implemented error
Console.WriteLine("b");
}
*/
workbook.CustomFontFileDirectory = fontDirectories;
/* 1. Create a Workbook instance
//Workbook workbook = new Workbook();
// 2. Open a FileStream from your source file
using (FileStream fileStream = System.IO.File.OpenRead("template.xlsx")) //FIXME add checking
// 4. (Optional) Work with the workbook, e.g., modify a cell
foreach (var cell in CellData)
{
// Ensure the stream position is at the beginning
fileStream.Seek(0, SeekOrigin.Begin);
// workbook.Worksheets[0].Range["A1"].Text = "Data loaded from stream!";
workbook.Worksheets[0].Range[cell.Key].Text = cell.Value;
// 3. Load the workbook from the stream
workbook.LoadFromStream(fileStream);
*/
} // end foreach
//Spire.Xls.Worksheet sheet = workbook.Worksheets[0];
//sheet.PageSetup.PrintArea = "B1:E6";
// Optional: Set worksheets to fit to page when converting
workbook.ConverterSetting.SheetFitToPage = true;
InvoiceCell ic = new InvoiceCell { };
//string prefix = CellData[ic.Invoice].Substring(0, 16).Replace(' ', '_');
//string pdf_name = bdf.output_path + type.ToUpper() + "_" + prefix + trace + ".pdf";
string svc_path = bdf.upload ? bdf.base_path + "BDF_Archive" + Path.DirectorySeparatorChar : "." + Path.DirectorySeparatorChar;
string pdf_name = bdf.upload ? type.ToUpper() : "." + Path.DirectorySeparatorChar + type.ToUpper() + "_INV" + trace + ".pdf";
if (!bdf.FileIsWritable(svc_path+pdf_name)) return;
workbook.SaveToFile(svc_path+pdf_name, FileFormat.PDF);
Logger.Log(0, "PDF written! ({0})", svc_path+pdf_name);
// are we uploading to EFT SFTP server?
if (bdf.upload)
{
// 4. (Optional) Work with the workbook, e.g., modify a cell
foreach (var cell in CellData)
Logger.Log(0, " Initiating {0}-INV upload to EFT server...", type);
try
{
// workbook.Worksheets[0].Range["A1"].Text = "Data loaded from stream!";
workbook.Worksheets[0].Range[cell.Key].Text = cell.Value;
using (var ms = new MemoryStream())
{
try
{
workbook.SaveToStream(ms, FileFormat.PDF); //Save as PDF
}
catch (Exception e)
{
Logger.Log(" Invoice failed to format for SFTP. ({0})", e.Message);
return;
}
} // end foreach
try
{
sftp.Upload_Stream(ms, "Outbox" + Path.DirectorySeparatorChar + pdf_name, bdf.sshDetails);
}
catch (Exception e)
{
Logger.Log(0, "INV SFTP Upload Exception: {0}:{1}", e.Message, e.InnerException.Message);
return;
}
//Logger.Log(" Invoice uploaded.");
}
}
catch (Exception e)
{
Logger.Log(0, "INVSFTP Upload Exception: {0}:{1}", e.Message, e.InnerException.Message);
return;
}
}
//Spire.Xls.Worksheet sheet = workbook.Worksheets[0];
// Set the print area to a specific cell range
// Comment this line out if you need to export the entire worksheet as a PDF
//sheet.PageSetup.PrintArea = "B1:E6";
// Optional: Set worksheets to fit to page when converting
workbook.ConverterSetting.SheetFitToPage = true;
// (Optional) Save the result to a new stream or file
// workbook.SaveToStream(outputStream);
// workbook.SaveToFile("Output.xlsx", ExcelVersion.Version2016);
// Save the Excel file to PDF
// string pdf_name = "Output_" + type + ".pdf";
InvoiceCell ic = new InvoiceCell { };
string prefix = CellData[ic.Invoice].Substring(0, 16).Replace(' ', '_') + "_";
string pdf_name = prefix + type.ToUpper() + trace + ".pdf";
workbook.SaveToFile(pdf_name, FileFormat.PDF);
Logger.Log(0, "PDF written! ({0})", pdf_name);
} //end using
}
public static string dateFormal(int dateInt)
@@ -350,34 +443,8 @@ namespace bdf
string outputFormat = "MMMM d, yyyy";
string result = dateTimeObject.ToString(outputFormat);
//Console.WriteLine(result);
// Output: November 30, 2025
return result;
}
}
/*
// Ensure these files are present in this directory in your application's deployment environment.
string fontDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts");
string[] fontDirectories = { fontDirectory };
// Set the custom font file directory for the workbook instance
Workbook workbook = new Workbook();
workbook.CustomFontFileDirectory = fontDirectories; //
// Load your Excel file
workbook.LoadFromFile("InputFile.xls");
// ... perform other operations ...
// When saving or converting (e.g., to PDF), the library will check the specified path for fonts
workbook.SaveToFile("OutputFile.xlsx", ExcelVersion.Version2013);
*/
}
}

Binary file not shown.

576
SFTP.cs
View File

@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Threading;
using Renci.SshNet;
using System.Linq;
using Renci.SshNet.Common;
using System.Threading.Tasks;
namespace bdf
{
@@ -34,7 +36,7 @@ namespace bdf
{
if (cd.ppkFile.Contains("Embedded"))
{
Logger.Log(1, " Processing internal PPK");
Logger.Log(2, " Processing internal PPK");
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
Stream stream = Stream.Null;
@@ -92,7 +94,7 @@ namespace bdf
if (pkFile != null)
{
auth.Add(new Renci.SshNet.PrivateKeyAuthenticationMethod(cd.username, pkFile)); //preferred
Logger.Log(0, " Added PPK method.");
Logger.Log(1, " -added PPK auth method.");
}
}
@@ -108,7 +110,7 @@ namespace bdf
auth.Add(kb);
auth.Add(new Renci.SshNet.PasswordAuthenticationMethod(cd.username, cd.password));
Logger.Log(0, " Added user/pass method.");
Logger.Log(1, " -added user/pass auth method.");
}
return new Renci.SshNet.ConnectionInfo(cd.host, cd.port, cd.username, auth.ToArray())
@@ -127,7 +129,6 @@ namespace bdf
{
Renci.SshNet.SftpClient client = null;
try
{
var task = System.Threading.Tasks.Task.Run(() =>
@@ -140,7 +141,6 @@ namespace bdf
client.KeepAliveInterval =
System.TimeSpan.FromSeconds(15);
client.Connect();
});
@@ -154,7 +154,9 @@ namespace bdf
{
client?.Dispose();
}
catch { }
catch
{
}
//return null;
}
@@ -179,7 +181,6 @@ namespace bdf
return null;
}
public static bool serverExists(string host)
{
try
@@ -232,30 +233,34 @@ namespace bdf
return;
}
string cpath = EnsureSftpDirectoryExists(sftpClient, filename);
// file upload
try
{
ms.Position = 0;
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
Logger.Log(2, $"Uploaded {Math.Round((double)uploaded / ms.Length * 100)}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, cd.host, cd.port, (ms.Length / 1024)+1);
Logger.Log(0, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, cd.host, cd.port, (ms.Length / 1024)+1);
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
(f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase)));
//Console.WriteLine("starting dir pull {0}", cpath);
var files = sftpClient.ListDirectory(cpath).Where(f => f.IsRegularFile &&
(f.Name.EndsWith(".pdf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".zip", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase)));
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
Logger.Log(1, " => {0} {1}", s.FullName, s.Attributes);
}
sftpClient.Disconnect();
@@ -276,526 +281,55 @@ namespace bdf
}
// Legacy modules
/*
public static void Upload_Stream_old(MemoryStream ms, string outfile, ConnectionDetails cd)
public static string EnsureSftpDirectoryExists(SftpClient client, string path)
{
//Logger.Log(0, "usp: file={0} host={1}:{2} user={3} pass={4}", outfile, cd.host, cd.port, cd.username, cd.password);
int attempts = 0;
while (true)
// The path needs to be absolute for reliable operation across different SFTP servers.
// Ensure the path starts with a '/' if it's meant to be absolute from the root.
if (!path.StartsWith(Path.DirectorySeparatorChar.ToString() ))
{
path = Path.DirectorySeparatorChar + path;
}
// Split the path into components, handling potential leading slash
var parts = path.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
string currentPath = Path.DirectorySeparatorChar.ToString();
Logger.Log(3, "Checking path: {0}", path);
foreach (var part in parts)
{
Logger.Log(4, " checking path part {0}", part);
if (string.IsNullOrEmpty(part)) continue;
if (parts[parts.Length-1].ToString() == part) break; // last part is the filename so skip pit. arrays are 0-based
currentPath = currentPath == Path.DirectorySeparatorChar.ToString() ? Path.DirectorySeparatorChar.ToString() + part : currentPath + Path.DirectorySeparatorChar.ToString() + part;
try
{
var valid_methods = new List<AuthenticationMethod>();
PrivateKeyFile keyFile;
if (cd.username != "" && cd.ppkFile != "")
// Attempt to get attributes of the current path component
var attrs = client.GetAttributes(currentPath);
if (!attrs.IsDirectory)
{
if (cd.ppkFile.StartsWith("BDF"))
{
Logger.Log(3, "Processing PPK");
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream(cd.ppkFile);
if (stream == null || !stream.CanRead)
throw new Exception("Private key file not found. ");
else
stream.Position = 0; // reset stream position
try
{
keyFile =
string.IsNullOrEmpty(cd.passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, cd.passPhrase);
}
catch (Renci.SshNet.Common.SshException e)
{
throw new Exception("Problems with your internal private key and/or passphrase. " + e.Message);
}
stream.Close();
}
else
{
try
{
keyFile =
string.IsNullOrEmpty(cd.passPhrase)
? new PrivateKeyFile(cd.ppkFile)
: new PrivateKeyFile(cd.ppkFile, cd.passPhrase);Console.WriteLine("b");
}
catch (Renci.SshNet.Common.SshException e)
{
throw new Exception("Problems with your private key and/or passphrase. " + e.Message);
}
}
valid_methods.Add(new PrivateKeyAuthenticationMethod(cd.username, keyFile)); //preferred
}
if (cd.username != "" && cd.password != "")
{
valid_methods.Add(new PasswordAuthenticationMethod(cd.username, cd.password)); //fallback to user/pass
}
if (valid_methods.Count == 0)
throw new Exception("No valid login credentials found.");
Logger.Log(0, " Found {0} valid methods. Using method={1}", valid_methods.Count, valid_methods[0].Name);
AuthenticationMethod[] methods = valid_methods.ToArray();
ConnectionInfo connectionInfo =
new ConnectionInfo(
cd.host,
cd.port,
cd.username,
methods ) //fallback to user/pass
{
Timeout = System.TimeSpan.FromSeconds(cd.timeOutSecs)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
//sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15); //set above in connectionInfo
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(cd.OperationTimeout);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(cd.KeepAliveInterval);
attempts++;
try
{
Logger.Log(5, "trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshAuthenticationException e)
{
Logger.Log(1, " authentication exception ({0}) : {1}", attempts, e.Message);
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
catch (Exception e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
sftpClient.UploadFile(
ms,
outfile,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", outfile, cd.host, cd.port, ((ms.Length / 1024) + 1));
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
( f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase) ) );
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
}
//if (client.Exists(path))
//{
// client.DeleteFile(path);
//}
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
// Handle the case where a file exists with the same name as a directory component
//throw new Exception($"A file exists with the same name as the directory component: {currentPath}");
Logger.Log(4, " found existing filename {0}", part);
break;
}
}
catch (Exception e)
catch (SftpPathNotFoundException)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
// If the path is not found, create the directory
client.CreateDirectory(currentPath);
Logger.Log(0, "Creating SFTP directory: {0}", currentPath);
System.Threading.Thread.Sleep(2000);
}
attempts++;
if (attempts >= cd.maxAttempts)
catch (Exception ex)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
// Handle other potential exceptions (permissions, etc.)
Logger.Log(0, "Error checking/creating directory {0}: {1}",currentPath,ex.Message);
throw; // Re-throw to propagate the error
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_dev(MemoryStream ms, string filename)
{
int attempts = 0;
int maxAttempts = 5;
int timeOut = 30; //seconds
string ppkFile = "BDF.Embedded.private_passphr.ppk";
//passPhrase = "";
string passPhrase = "Rogers1!";
string username = "DEV_APP_BDF";
string host = "dev.mft.rogers.com";
int port = 22;
Logger.Log(5, "usp: file={0} host={1}:{2} user={3} pass={4}", filename, host, port, username, passPhrase);
while (true)
{
try
{
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream(ppkFile);
//Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_nopassphr.ppk");
if (stream == null || !stream.CanRead)
throw new Exception("Private keys not found. ");
PrivateKeyFile keyFile =
string.IsNullOrEmpty(passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, passPhrase);
stream.Close();
ConnectionInfo connectionInfo =
new ConnectionInfo(
host,
port,
username,
new PrivateKeyAuthenticationMethod(username, keyFile))
{
Timeout = System.TimeSpan.FromSeconds(timeOut)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15);
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(30);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(10);
attempts++;
try
{
Logger.Log(5, "trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, ((ms.Length / 1024)+1));
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase));
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
}
//if (client.Exists(path))
//{
// client.DeleteFile(path);
//}
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
}
}
catch (Exception e)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
}
attempts++;
if (attempts >= maxAttempts)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_ppk(MemoryStream ms, string filename, string host, int port, string username)
{
int attempts = 0;
int maxAttempts = 5;
int timeOut = 30; //seconds
string passPhrase = "Rogers1!";
//passPhrase = "";
//string username = "DEV_APP_BDF";
//string host = "dev.mft.rogers.com";
//int port = 22;
Logger.Log(5,"usp: file={0} host={1}:{2} user={3} pass={4}", filename, host, port, username, passPhrase);
while (true)
{
try
{
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_passphr.ppk");
//Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_nopassphr.ppk");
if (stream == null || !stream.CanRead)
throw new Exception("Private keys not found. ");
PrivateKeyFile keyFile =
string.IsNullOrEmpty(passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, passPhrase);
stream.Close();
ConnectionInfo connectionInfo =
new ConnectionInfo(
host,
port,
username,
new PrivateKeyAuthenticationMethod(username, keyFile))
{
Timeout = System.TimeSpan.FromSeconds(timeOut)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15);
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(30);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(10);
attempts++;
try
{
Logger.Log(5,"trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
Console.WriteLine("trying to upload");
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, (ms.Length / 1024));
Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".");
foreach(var s in files)
{
Console.WriteLine("* {0}", s.FullName);
}
Console.WriteLine("disconnecting");
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
}
}
catch (Exception e)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
}
attempts++;
if (attempts >= maxAttempts)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_old( MemoryStream ms, string filename, string host, int port, string username, string password)
{
try
{
using (var sftpClient = new SftpClient(host, port, username, password))
//using (var fs = new FileStream(fileToUpload, FileMode.Open))
{
sftpClient.OperationTimeout = TimeSpan.FromSeconds(30);
sftpClient.ConnectionInfo.Timeout = TimeSpan.FromSeconds(30);
int attempts = 0;
do
{
attempts++;
try
{
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1," retrying ({0}) : {1}",attempts, e.Message);
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}
while (attempts < 10 && !sftpClient.IsConnected);
if (attempts >= 10)
{
throw new Exception("Failed to Connect after 10 attempts.");
}
else
{
Logger.Log(" SSH Connected");
try
{
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(" SSH Disconnected");
sftpClient.Disconnect();
}
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, ( ms.Length/1024) );
}
catch (Exception e)
{
Logger.Log(e.Message);
}
return currentPath;
}
public static void Upload_file(string fileToUpload, string host, int port, string username, string password)
{
try
{
using (var sftpClient = new SftpClient(host, port, username, password))
using (var fs = new FileStream(fileToUpload, FileMode.Open))
{
sftpClient.OperationTimeout = TimeSpan.FromSeconds(30);
int attempts = 0;
do
{
try
{
attempts += 1;
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " retrying in 5s ({0}) : {1}", attempts, e.Message);
Thread.Sleep(TimeSpan.FromSeconds(5));
}
} while (attempts < 10 && !sftpClient.IsConnected);
Logger.Log(" SSH Connected");
try
{
sftpClient.UploadFile(
fs,
"/Doug/" + Path.GetFileName(fileToUpload),
uploaded =>
{
Logger.Log(5,$"Uploaded {(double)uploaded / fs.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH Exception {0}:{1}", e.Message, e.InnerException.Message);
}
sftpClient.Disconnect();
}
Logger.Log(1," uploaded: {0}", fileToUpload);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
*/
}
}

Binary file not shown.

Binary file not shown.

248
Switches.cs Normal file
View File

@@ -0,0 +1,248 @@
using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using static bdf.bdf; //globals from Main.cs
namespace bdf
{
public class myArgs
{
public static void ProcessSwitches(Arguments myargs)
{
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]");
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(" basepath: -so C:\\Users\\us.er\\OneDrive\\path\\");
Logger.Log(" svc subdirs: -ldfdir .\\LDF\\ | -wavdir .\\WAV\\ | -sipdir .\\SIP\\");
Logger.Log("invoice offset: -month=x [x = +/- 6, default is coming bill cycle, ie '1']");
Logger.Log("Megatool reuse: -reuse");
Logger.Log("Megatool redo: -redo");
Logger.Log(" SFTP upload: -upload");
Logger.Log(" SIP PDF ZIP: -zip");
Logger.Log(" verbose: -v");
//Logger.Log(" debug: -debug n");
return;
}
if (!myargs.Exists("licensed"))
{
ExpirationGuard.ThrowIfExpired();
}
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.");
}
if (myargs.Exists("backbill"))
{
double amt = Double.Parse(myargs.Single("backbill"));
if ((amt >= 0) && (amt <= 1000000))
backBillAmt = amt;
}
if (myargs.Exists("upload"))
{
upload = true;
Logger.Log(0, "Files will be securely transferred to EFT");
}
if (myargs.Exists("zip"))
{
archive = true;
Logger.Log(0, "Invoices will be aggregated into a ZIP archive.");
}
// 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"))
{
output_path = myargs.Single("path");
if (output_path == "") output_path = ".";
if (!output_path.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
output_path += Path.DirectorySeparatorChar.ToString();
}
}
else
{
output_path = "." + Path.DirectorySeparatorChar.ToString();
}
Logger.Log(5, "Setting filestore root path to {0}", output_path);
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 >= -16) && (offset <= 12))
month_offset = offset;
}
}
public static class ExpirationGuard
{
// Hardcoded expiration date (UTC recommended)
private static readonly DateTime ExpirationDate = new DateTime(2027, 12, 31, 0, 0, 0, DateTimeKind.Utc);
public static void ThrowIfExpired()
{
if (DateTime.UtcNow >= ExpirationDate)
{
Console.WriteLine("It appears that Doug has left the building. Please reach out for licensing options if desired.");
throw new InvalidOperationException(
$"This software is not licensed for continued use.");
}
}
public static bool IsExpired()
{
return DateTime.UtcNow >= ExpirationDate;
}
}
}
}

214
Web.cs
View File

@@ -13,13 +13,14 @@ using System.Text;
//using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Net.Security;
using Org.BouncyCastle.Asn1.Ocsp;
namespace bdf
{
/// <summary>
/// Provides wrapper around HttpWebRequest, handling 302 redir, binary and certificate issues
/// </summary>
{
/// <summary>
/// Provides wrapper around HttpWebRequest, handling 302 redir, binary and certificate issues
/// </summary>
public class Web
{
public Web()
@@ -111,10 +112,7 @@ namespace bdf
bool success = false;
HttpWebRequest webRequest = null;
// Consider setting webRequest.KeepAlive = false; for the logout call to shut down the TCP resources.
// Set the 'Timeout' property in Milliseconds.
//webRequest.Timeout = 1000 * 60 * 3; // 3min
// Consider setting webRequest.KeepAlive = false; for the logout call to shut down the TCP resources.
if (method == "GET")
{
@@ -122,7 +120,13 @@ namespace bdf
webRequest.Method = "GET";
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 OPR/76.0.4017.123";
if (token != "")
{ // Try to outsmart Win11/Net481...keep NTLM auth alive
webRequest.Credentials = bdf.cache;
webRequest.PreAuthenticate = true; //added for Win11 .NET which fails as it does not auto-redirect
webRequest.KeepAlive = true;
}
if (token != "")
{
webRequest.PreAuthenticate = true;
//webRequest.Headers.Add("Authorization", "Bearer " + token);
@@ -140,7 +144,6 @@ namespace bdf
webRequest.Method = method;
webRequest.CookieContainer = cookie;
//webRequest.Timeout = 180000; // 3min
webRequest.Timeout = bdf.webMaxWait * 60 * 1000; // convert minutes of wait into milliseconds
if (proxy != null)
@@ -152,6 +155,14 @@ namespace bdf
{
byte[] buffer = Encoding.ASCII.GetBytes(vars);
webRequest = (HttpWebRequest)WebRequest.Create(uri);
{
webRequest.Credentials = bdf.cache;
webRequest.PreAuthenticate = true; //added for Win11 .NET which fails as it does not auto-redirect
//webRequest.UnsafeAuthenticatedConnectionSharing = true;
webRequest.KeepAlive = true;
}
if (proxy != null)
{
webRequest.Proxy = proxy;
@@ -208,7 +219,7 @@ namespace bdf
try
{
//ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192; //3072
//ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;
//ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls13;
try
{
response = (HttpWebResponse)webRequest.GetResponse();
@@ -263,7 +274,176 @@ namespace bdf
}
}
/*
// this version worked for Mono and with a proxy like Fiddler, but not instraight up .NET481 on Win11
public static bool working_MakeByteRequest(string method, bool redir, string uri, string vars, ref byte[] data, bool json, ref string token, ref CookieContainer cookie, WebProxy proxy)
{
bool success = false;
HttpWebRequest webRequest = null;
// Consider setting webRequest.KeepAlive = false; for the logout call to shut down the TCP resources.
if (method == "GET")
{
webRequest = (HttpWebRequest)WebRequest.Create(string.Format("{0}{1}", uri, vars));
webRequest.Method = "GET";
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 OPR/76.0.4017.123";
{ // Try to outsmart Win11/Net481...
webRequest.Credentials = CredentialCache.DefaultNetworkCredentials; //cache;
webRequest.UnsafeAuthenticatedConnectionSharing = true;
webRequest.UseDefaultCredentials = true;
webRequest.PreAuthenticate = true; //added for Win11 .NET which fails as it does not auto-redirect
webRequest.KeepAlive = true;
}
if (token != "")
{
webRequest.PreAuthenticate = true;
//webRequest.Headers.Add("Authorization", "Bearer " + token);
//webRequest.Headers.Add("Origin", uri); //Feb2023
//webRequest.Headers.Add("Authorization", "Negotiate " + token);
//webRequest.Headers.Add("Authorization", "Negotiate " + token);
//webRequest.Headers.Add("Upgrade-Insecure-Requests", "1");
}
if (json)
{
webRequest.Accept = "application/json";
}
webRequest.AllowAutoRedirect = redir;
webRequest.Method = method;
webRequest.CookieContainer = cookie;
webRequest.Timeout = bdf.webMaxWait * 60 * 1000; // convert minutes of wait into milliseconds
if (proxy != null)
{
webRequest.Proxy = proxy;
}
}
else if (method == "POST")
{
byte[] buffer = Encoding.ASCII.GetBytes(vars);
webRequest = (HttpWebRequest)WebRequest.Create(uri);
{
webRequest.PreAuthenticate = true; //added for Win11 .NET which fails as it does not auto-redirect
webRequest.UnsafeAuthenticatedConnectionSharing = true;
webRequest.KeepAlive = true;
}
if (proxy != null)
{
webRequest.Proxy = proxy;
}
webRequest.Method = "POST";
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 OPR/76.0.4017.123";
if (token != "") // basically is this a JSON request
{
webRequest.PreAuthenticate = true;
webRequest.Headers.Add("Authorization", "Bearer " + token);
}
if (json)
{
webRequest.Accept = "application/json";
webRequest.ContentType = "application/json";
}
else
{
webRequest.ContentType = "application/x-www-form-urlencoded";
}
webRequest.ContentLength = buffer.Length;
webRequest.AllowAutoRedirect = redir;
webRequest.Method = method;
webRequest.CookieContainer = cookie;
webRequest.Timeout = bdf.webMaxWait * 60 * 1000; // convert minutes of wait into milliseconds
if (proxy != null)
{
webRequest.Proxy = proxy;
}
//We open a stream for writing the postvars
Stream PostData = webRequest.GetRequestStream();
//Now we write, and afterwards, we close. Closing is always important!
PostData.Write(buffer, 0, buffer.Length);
PostData.Close();
}
else
{
Logger.Log("Request not understood");
Logger.Log(3, "FAIL - UNKNOWN METHOD");
return false;
}
// allows for validation of SSL conversations
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(
ValidateRemoteCertificate
);
HttpWebResponse response = null;
try
{
//ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192; //3072
//ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;
try
{
response = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException ex)
{
//string authresp = Web_Auth.HttpAuthHandler.ExtractAuthenticateHeader(ex);
//token = authresp.Split(new char[] { ' ' })[1];
Logger.Log(0, "webRequest failed. {0}", ex.Message);
}
//Let's show some information about the response
//Logger.Log(6, "YY {0}", response.StatusCode);
//Logger.Log(6, "ZZ {0}", response.GetResponseHeader("error"));
foreach (Cookie cook in response.Cookies)
{
cookie.Add(cook);
}
//DumpCookies(response.Cookies);
if ((response.StatusCode == HttpStatusCode.Found) ||
(response.StatusCode == HttpStatusCode.OK))
{
success = true;
}
using (Stream s = response.GetResponseStream())
{
//byte[] data = ReadStreamFully(s);
data = ReadStreamFully(s);
s.Close();
//System.IO.StreamWriter file = new System.IO.StreamWriter("webcs.txt"); file.BaseStream.Write(data,0,data.Length); file.Close();
//object[] ret = { success, Encoding.ASCII.GetString(data) , data };
//object[] ret = { success, data };
//return true;
}
return success;
}
catch (Exception ex)
{
Logger.Log(0, "WebRequest error: {0}", ex.Message);
//object[] ret = { false, null };
return false;
}
finally
{
if (response != null)
response.Close();
}
}
/*
public static object[] zMakeByteRequest(string method, bool redir, string uri, string vars, ref CookieContainer cookie, WebProxy proxy)
{
bool success = false;
@@ -398,9 +578,9 @@ namespace bdf
response.Close();
}
}
*/
public static byte[] ReadStreamFully (Stream stream)
*/
public static byte[] ReadStreamFully (Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())

View File

@@ -4,13 +4,12 @@ using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Spire.Xls;
namespace bdf
{
class CXLFile
{
//public static List<XLWorkbook> ServiceOrders = new List<XLWorkbook> { };
public static List<Spire.Xls.Workbook> S_ServiceOrders = new List<Spire.Xls.Workbook> { };
@@ -110,7 +109,7 @@ namespace bdf
Dictionary<string, (int version, string file)> best =
new Dictionary<string, (int, string)>();
foreach (var file in files)
foreach (var file in files) //todo should this be filtered instead?
{
string name = Path.GetFileName(file);
var match = regex.Match(name);
@@ -133,7 +132,7 @@ namespace bdf
if (!best.ContainsKey(serial)) // || ver > best[serial].version)
{
best[serial] = (ver, file);
Logger.Log(5, " Adding: {0} ver {1}", serial, ver);
Logger.Log(5, " Adding: {0} ver {1}", serial, ver); //todo open up file and verify so version from internals?
}
else if (ver > best[serial].version)
{
@@ -148,233 +147,5 @@ namespace bdf
return best.Values.Select(v => v.file).ToArray();
}
/*
public static void getXLS(string task, string dir)
{
//string folderPath = @"C:\Data\ExcelFiles"; // Folder to scan
string folderPath = dir;
string filePrefix1 = "ROGERS_";
string filePrefix2 = task + "_SO";
//List<XLWorkbook> ServiceOrders = new List<XLWorkbook> { };
try
{
// Required for ExcelDataReader in .NET 4
System.Text.Encoding.RegisterProvider(
System.Text.CodePagesEncodingProvider.Instance);
// Get all Excel files that match the prefix
//var excelFiles = Directory.GetFiles(folderPath, filePrefix1 + "*" + filePrefix2 + "*.xls*", SearchOption.TopDirectoryOnly);
var excelFiles = getLatestVersionFiles(dir, filePrefix1, filePrefix2);
if (excelFiles.Length == 0)
{
Console.WriteLine("No Excel files found with prefix: " + filePrefix1 + "*" + filePrefix2);
return;
}
DataSet _dataSet = null;
foreach (var filePath in excelFiles)
{
Logger.Log(1, "Scanning: {0}", Path.GetFileName(filePath));
// DataSet dataSet = ReadExcelFile(filePath);
// STEP 1: Read file into DataSet using ExcelDataReader
try
{
_dataSet = ReadExcelFile(filePath);
//_dataSet = LoadOneDriveDataSet(filePath);
}
catch
{
try
{
_dataSet = LoadOneDriveDataSet(filePath);
}
catch (Exception e)
{
Logger.Log(0, "Error trying to access file {0}. ({1})", filePath, e.Message);
}
}
// STEP 2: Convert DataSet into a ClosedXML workbook for manipulation
var workbook = new XLWorkbook();
//using (var workbook = new XLWorkbook())
{
foreach (DataTable table in _dataSet.Tables)
{
var worksheet = workbook.Worksheets.Add(table.TableName);
// Insert headers
for (int col = 0; col < table.Columns.Count; col++)
{
worksheet.Cell(1, col + 1).Value = table.Columns[col].ColumnName;
worksheet.Cell(1, col + 1).Style.Font.Bold = true;
}
// Insert rows
for (int row = 0; row < table.Rows.Count; row++)
{
for (int col = 0; col < table.Columns.Count; col++)
{
//Logger.Log(5, "type is {0}", table.Rows[row][col].GetType().Name);
string valuetype = table.Rows[row][col].GetType().Name;
if (valuetype == "Int32")
{
worksheet.Cell(row + 2, col + 1).Value = (Int32)table.Rows[row][col];
}
else if (valuetype == "String")
{
worksheet.Cell(row + 2, col + 1).Value = (String)table.Rows[row][col];
}
else if (valuetype == "Decimal")
{
worksheet.Cell(row + 2, col + 1).Value = (Decimal)table.Rows[row][col];
}
else if (valuetype == "Double")
{
worksheet.Cell(row + 2, col + 1).Value = (Double)table.Rows[row][col];
}
else if (valuetype == "DBNull")
{
worksheet.Cell(row + 2, col + 1).Value = "";
}
else
{
worksheet.Cell(row + 2, col + 1).Value = "fix me";
}
//worksheet.Cell(row + 2, col + 1).Value = table.Rows[row][col];
}
}
worksheet.Columns().AdjustToContents();
//Logger.Log(0, "Sheet{0} Value={1}", workbook.Worksheets.Count, workbook.Worksheet(workbook.Worksheets.Count).Cell("C2").Value);
}
// Example: Save modified workbook (optional)
string outputFile = Path.Combine(folderPath, "" + Path.GetFileName(filePath) + "x");
//workbook.SaveAs(outputFile);
Logger.Log(7, "Processed file: {0}", outputFile);
//Logger.Log(0, "Book has {0} sheets", workbook.Worksheets.Count );
CXLFile.ServiceOrders.Add(workbook);
//Logger.Log("test: " + workbook.Worksheet(1).Cell("C2").Value);
}
//Logger.Log("Finished: " + Path.GetFileName(filePath));
//Logger.Log(new string('-', 50));
}
Logger.Log("All SO Excel files processed successfully.");
}
catch (Exception ex)
{
Logger.Log(0, "SO processing error: {0}" + ex.Message);
//Logger.Log("Press any key to exit...");
//Console.ReadKey();
}
//
//return ServiceOrders;
}
/// <summary>
/// Reads an Excel file into a DataSet using ExcelDataReader.
/// Each worksheet becomes a DataTable.
/// </summary>
static DataSet ReadExcelFile(string filePath)
{
// Required for ExcelDataReader to process XLS files
System.Text.Encoding.RegisterProvider(
System.Text.CodePagesEncodingProvider.Instance);
using (var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read))
{
IExcelDataReader reader;
// Auto-detect format (XLS or XLSX)
if (Path.GetExtension(filePath).Equals(".xls", StringComparison.OrdinalIgnoreCase))
reader = ExcelReaderFactory.CreateBinaryReader(stream);
else
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
// Convert to DataSet (with first row as header)
var result = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = _ => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
reader.Close();
return result;
}
}
public static DataSet LoadOneDriveDataSet(string path)
{
if (!System.IO.File.Exists(path))
throw new FileNotFoundException("OneDrive file not found.", path);
// Required for ExcelDataReader to process XLS files
System.Text.Encoding.RegisterProvider(
System.Text.CodePagesEncodingProvider.Instance);
FileStream stream = null;
// OneDrive sync engine frequently locks files briefly:
const int maxRetries = 12;
const int retryDelayMs = 150;
for (int i = 0; i < maxRetries; i++)
{
try
{
stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite | FileShare.Delete
);
break; // opened successfully
}
catch (IOException)
{
if (i == maxRetries - 1)
throw;
System.Threading.Thread.Sleep(retryDelayMs);
}
}
// STEP 1: Read the workbook into a DataSet (ExcelDataReader)
DataSet dataSet;
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
dataSet = reader.AsDataSet(new ExcelDataSetConfiguration
{
ConfigureDataTable = _ => new ExcelDataTableConfiguration
{
UseHeaderRow = true
}
});
}
return dataSet;
}
*/
}
}

File diff suppressed because it is too large Load Diff

1937
_Main.cs

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@
<Compile Include="MegaT.cs" />
<Compile Include="PDF.cs" />
<Compile Include="SFTP.cs" />
<Compile Include="Switches.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@@ -3,6 +3,7 @@
<package id="BouncyCastle.Cryptography" version="2.6.2" targetFramework="net48" />
<package id="FreeSpire.XLS" version="14.2.0" targetFramework="net48" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
<package id="Microsoft.CodeAnalysis.NetAnalyzers" version="10.0.101" targetFramework="net48" developmentDependency="true" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="8.0.2" targetFramework="net48" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="8.0.3" targetFramework="net48" />
<package id="SSH.NET" version="2025.1.0" targetFramework="net48" />

BIN
template.xlsx Executable file

Binary file not shown.

BIN
template_orig.xlsx Executable file

Binary file not shown.

193
xsip.cs
View File

@@ -1,193 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
class Program
{
static void Main(string[] args)
{
string sampleHtml = @"
<html>
<head>
<title>Insis Revenue</title>
<link rel=""stylesheet"" type=""text/css"" href=""../Images/OutputStyle.css"" />
<link rel=""stylesheet"" type=""text/css"" href=""../Images/TopHeadingStyle.css"" />
<script type=""text/javascript"" language=""javascript"" src=""../Includes/HighLightRow.js""></script>
</head>
<body onload = ""init()"";>
<div id=""container"">
<div id=""rogersheader""><center><font class=""header"">Revenue Details (<font class='name'>SSCGPAS001</font>)</font></center></div>
</div>
<center>
<form name=""myForm"" method =""post"" action="""">
<div align=""right"">
<font color=""#B22222""><b>Revision:</b>&nbsp;</font>
<select name=""revision"" class =""entry"" onchange =""revisionOnChange()"";>
<option value=""03"">03&nbsp;&nbsp;&nbsp;NS&nbsp;&nbsp;&nbsp;7/31/2025&nbsp;&nbsp;&nbsp;APPR</option>
<option value=""02"">02&nbsp;&nbsp;&nbsp;NS&nbsp;&nbsp;&nbsp;7/31/2025&nbsp;&nbsp;&nbsp;ARCH</option>
<option value=""01"">01&nbsp;&nbsp;&nbsp;NS&nbsp;&nbsp;&nbsp;7/31/2024&nbsp;&nbsp;&nbsp;ARCH</option>
</select>
</div>
<br />
<table class=""normal"" border=""1"" cellspacing=""0"" cellpadding=""0"">
<tr>
<td>
<table class=""line"" cellspacing=""0"" cellpadding=""6"">
<tr class=""heading2"">
<td class=""heading2"">Item</td>
<td class=""heading2"">Code</td>
<td class=""heading2"">Description</td>
<td class=""heading2"">Period</td>
<td class=""heading2"" align=""right"">Unit Price</td>
<td class=""heading2"" align=""center"">Qty</td>
<td class=""heading2"" align=""right"">Amount</td>
<td class=""heading2"" align=""center"">Billing Type</td>
<td class=""heading2"" align=""center"">Currency</td>
</tr>
<tr id=""R0"" onclick=""Highlight_Row(R0)"">
<td nowrap=""nowrap"">01 &nbsp;</td>
<td nowrap=""nowrap"">ACH&nbsp;</td>
<td nowrap=""nowrap"">100M Ethernet Fiber Access-BRE&nbsp;</td>
<td nowrap=""nowrap"">Monthly&nbsp;</td>
<td nowrap=""nowrap"" align=""right"">$200.00&nbsp;</td>
<td nowrap=""nowrap"" align=""center"">1&nbsp;</td>
<td nowrap=""nowrap"" align=""right"">$200.00&nbsp;</td>
<td nowrap=""nowrap"" align=""center""> &nbsp;</td>
<td nowrap=""nowrap"" align=""center"">CD&nbsp;</td>
</tr>
<tr id=""R1"" onclick=""Highlight_Row(R1)"">
<td nowrap=""nowrap"">04 &nbsp;</td>
<td nowrap=""nowrap"">VSS&nbsp;</td>
<td nowrap=""nowrap"">Voice Session Service-BRE &nbsp;</td>
<td nowrap=""nowrap"">Monthly&nbsp;</td>
<td nowrap=""nowrap"" align=""right"">$9.80&nbsp;</td>
<td nowrap=""nowrap"" align=""center"">14&nbsp;</td>
<td nowrap=""nowrap"" align=""right"">$137.20&nbsp;</td>
<td nowrap=""nowrap"" align=""center""> &nbsp;</td>
<td nowrap=""nowrap"" align=""center"">CD&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</center>
<script type=""text/javascript"" language =""javascript"">
function init() {
myForm.revision.value = ""03""
}
function revisionOnChange(){
window.location.href=""revenue.asp?serv_id=SSCGPAS001&revision="" + myForm.revision.value
}
</script>
<p></p>
<center>
<input class=""button2"" type=""button"" onclick=""top.close()"" value=""Close"" title=""Close"" />
</center>
</body>
</html>";
List<TableDataExtractor.RowData> data = TableDataExtractor.ExtractSpecificTableData(sampleHtml);
foreach (var row in data)
{
Console.WriteLine(row.ToString());
}
}
}
public class TableDataExtractor
{
// A class to hold the extracted data for a single row
public class RowData
{
public string Item { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public string Period { get; set; }
public string UnitPrice { get; set; }
public string Qty { get; set; }
public string Amount { get; set; }
public string BillingType { get; set; }
public string Currency { get; set; }
public override string ToString()
{
return $"Item: {Item}, Description: {Description}, Unit Price: {UnitPrice}, Qty: {Qty}, Amount: {Amount}";
}
}
public static List<RowData> ExtractSpecificTableData(string htmlContent)
{
var extractedData = new List<RowData>();
// Regex to find table rows (<tr>) within a specific table structure (adjust if needed, e.g., using a table ID)
// The pattern uses capturing groups for each <td> content
// It assumes <td> tags might have extra spaces or attributes, but the content inside is the target.
// It specifically looks for rows with exactly 5 data cells.
string rowPattern = @"<tr\s*[^>]*?\bid=[^>]*?>(.*?)</tr\s*>"; //@"<tr\s*[^>]*>(.*?)</tr\s*>";
string cellPattern = @"<td\s*[^>]*>(.*?)</td>";
// Find all rows in the HTML
MatchCollection rows = Regex.Matches(htmlContent, rowPattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
foreach (Match rowMatch in rows)
{
string rowHtml = rowMatch.Groups[1].Value;
// Find all cells in the current row
MatchCollection cells = Regex.Matches(rowHtml, cellPattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
// Check if the row has exactly 5 columns of data (Item, Description, Unit Price, Qty, Amount)
if (cells.Count >= 9)
{
// Extract the inner text and clean up whitespace
string item = cells[0].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string code = cells[1].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string description = cells[2].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string period = cells[3].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string unitPrice = cells[4].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string qty = cells[5].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string amount = cells[6].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string billingType = cells[7].Groups[1].Value.Replace("&nbsp;", " ").Trim();
string currency = cells[8].Groups[1].Value.Replace("&nbsp;", " ").Trim();
// Add to the list
extractedData.Add(new RowData
{
Item = item,
Code = code,
Description = description,
Period = period,
UnitPrice = unitPrice,
Qty = qty,
Amount = amount,
BillingType = billingType,
Currency = currency
});
}
}
return extractedData;
}
}

BIN
xsip.exe

Binary file not shown.