Files
Print_server/EpsonTest.Templates/TestHelpers.cs
2026-02-03 14:27:13 +01:00

580 lines
20 KiB
C#

using Inspectron.Epson;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace EpsonTest.Templates;
public static class TestHelpers
{
// Default connection settings
public const string DefaultEpsonIp = "127.0.0.1";
public const int DefaultEpsonPort = 8888;
public const string DefaultHtmlPath = @".\test.html";
public const int DefaultPaperWidth = 384;
public const int KitchenPaperWidth = 258;
#region Printer Creation
public static async Task<EpsonPrinter> CreateEpsonPrinterAsync(
string ip = DefaultEpsonIp,
int port = DefaultEpsonPort, int paperWidth = DefaultPaperWidth)
{
var printer = new EpsonPrinter();
await printer.ConnectAsync(ip, port);
return printer;
}
public static async Task<HtmlPrinter> CreateHtmlPrinterAsync(
string path = DefaultHtmlPath,
int paperWidth = DefaultPaperWidth)
{
var printer = new HtmlPrinter(path, paperWidth: paperWidth);
await printer.ConnectAsync("");
return printer;
}
#endregion
#region Print Helpers
public static async Task PrintCommandsToHtmlPrinterAsync(
HtmlPrinter printer,
IEnumerable<PrintCommand> commands,
string? logoPath = null,
int logoWidth = 300,
int logoXPosition = 42)
{
if (logoPath != null)
{
await printer.SetAbsolutePrintPosition(logoXPosition);
await printer.LoadImageAsync(logoPath, logoWidth);
await printer.PrintLoadedImage();
await printer.SetAbsolutePrintPosition(0);
}
await printer.SetCustomLineSpacing(22);
foreach (var command in commands)
{
if (command.IsBig)
await printer.SetFontSizeAsync(2, 1);
else
await printer.SetFontSizeAsync(1, 1);
await printer.SetEmphasized(command.IsBold);
await printer.PrintTextAsync(command.Text + "\n");
}
}
public static async Task PrintCommandsToEpsonPrinterAsync(
EpsonPrinter printer,
IEnumerable<PrintCommand> commands,
bool useDelay = true,
int delayMs = 200)
{
await printer.FeedLinesAsync(1);
await printer.SetCustomLineSpacing(22);
foreach (var command in commands)
{
if (command.IsCut)
{
await printer.FeedLinesAsync(10);
if (useDelay) await Task.Delay(delayMs * 5);
await printer.CutAsync(false);
if (useDelay) await Task.Delay(delayMs);
continue;
}
await printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig, secondaryFont: false);
if (useDelay) await Task.Delay(delayMs);
await printer.SetRedColor(command.IsRed);
if (useDelay) await Task.Delay(delayMs);
await printer.SetEmphasized(command.IsBold);
if (useDelay) await Task.Delay(delayMs);
await printer.PrintTextAsync(command.Text + "\n");
if (useDelay) await Task.Delay(delayMs);
}
await printer.FeedLinesAsync(10);
if (useDelay) await Task.Delay(delayMs * 5);
await printer.CutAsync();
}
public static async Task PrintKitchenCommandsToHtmlPrinterAsync(
HtmlPrinter printer,
IEnumerable<PrintCommand> commands)
{
await printer.FeedLinesAsync(1);
await printer.SetCustomLineSpacing(22);
foreach (var command in commands)
{
if (command.IsCut)
{
await printer.CutAsync(false);
continue;
}
if (command.IsBig)
await printer.SetFontSizeAsync(2, 1);
else
await printer.SetFontSizeAsync(1, 1);
await printer.SetRedColor(command.IsRed);
await printer.SetEmphasized(command.IsBold);
await printer.PrintTextAsync(command.Text + "\n");
}
}
#endregion
#region Console Output
public static void PrintCommandsToConsole(IEnumerable<PrintCommand> commands)
{
Console.WriteLine("=== PRINT COMMANDS ===\n");
foreach (var command in commands)
{
string attributes = "";
if (command.IsBig) attributes += "[BIG] ";
if (command.IsBold) attributes += "[BOLD] ";
if (command.IsRed) attributes += "[RED] ";
Console.WriteLine($"{attributes}{command.Text}");
}
}
#endregion
#region JSON Data Builders
public static string BuildKitchenReceiptJson()
{
var receipt = new KitchenReceipt
{
Title = "Warme Küche",
TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
ReceiptNumber = "132018166",
WaiterName = "Mariano Amato",
WaiterId = "32 (VK Restaurant)",
TableNumber = "22"
};
receipt.Gangs.Add(new Gang(1, "Gang"));
receipt.Gangs.Add(new Gang(2, "Gang"));
receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")
{
Modifications = new DishModifications
{
Removed = new List<string> { "Wasabi" },
Added = new List<string> { "Extra Ginger" }
},
Comment = "No soy sauce",
GuestId = 1
});
receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi") { GuestId = 1 });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
return SerializeWithComputedProps(receipt);
}
public static string BuildKitchenReceiptNextDishJson()
{
var receipt = new KitchenReceipt
{
Title = "Warme Küche",
TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
ReceiptNumber = "132018166",
WaiterName = "Mariano Amato",
WaiterId = "32 (VK Restaurant)",
TableNumber = "22",
SpecialInstruction = "Gang schicken"
};
receipt.Gangs.Add(new Gang(2, "Gang"));
return SerializeWithComputedProps(receipt);
}
public static string BuildFinalReceiptJson(bool includeTax = true)
{
var receipt = new FinalReceipt
{
CompanyName = "Klingler Gastro AG",
Address1 = "Münzplatz 3",
Address2 = "CH-8001 Zürich",
Phone = "043 321 22 22",
ReceiptNumber = null,
DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
Guests = 2,
Total = 160.00m,
Currency = "CHF",
TotalInAlternateCurrency = 172.80m,
AlternateCurrency = "EUR",
PaymentMethod = "MASTER",
PaymentAmount = 160.00m,
WaiterName = "Yves",
Terminal = "Hauptkasse ZH",
TableNumber = "12",
VatNumber = "CHE-449.635.880 MWST",
ThankYouMessage = "Das Team bedankt sich herzlich für Ihren",
GoodbyeMessageLine1 = "Besuch.",
GoodbyeMessageLine2 = "Auf Wiedersehen.",
IsDebtor = true,
SplitPayments = new List<SplitPaymentInfo>
{
new() { PaymentMethod = "Cash", Amount = 50.00m, Currency = "CHF" },
new() { PaymentMethod = "Card", Amount = 110.00m, Currency = "CHF" }
},
TerminalReceipts = new List<PaymentTerminalReceipt>
{
new()
{
ReceiptType = "*** Kundenbeleg ***",
BookingType = "Buchung",
PaymentSystem = "TWINT",
TransactionNumber = "XXXXXXXXXXXXXXX1494",
TransactionDateTime = new DateTime(2025, 11, 11, 12, 34, 49),
TerminalId = "31108834",
AID = "A0000015749E",
TransactionSeqCount = "6127",
TransactionRefNo = "99036644599",
AuthCode = "0d3396",
AcquirerId = "2",
EftAmount = 67.00m,
TipAmount = 6.70m,
TotalEftAmount = 73.70m,
Currency = "CHF"
},
new()
{
ReceiptType = "*** Kundenbeleg ***",
BookingType = "Buchung",
PaymentSystem = "MASTER",
TransactionNumber = "XXXXXXXXXXXXXXX2587",
TransactionDateTime = new DateTime(2025, 11, 11, 12, 36, 12),
TerminalId = "31108834",
AID = "A0000000041010",
TransactionSeqCount = "6128",
TransactionRefNo = "99036644600",
AuthCode = "1a4b2c",
AcquirerId = "1",
EftAmount = 93.00m,
TipAmount = 0.00m,
TotalEftAmount = 93.00m,
Currency = "CHF"
}
},
DiscountInfo = new DiscountInfo()
{
Amount = -50.00m,
Currency = "CHF",
Description = "Fine Dine",
}
};
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 1, Description = "San Pellegrino 50cl",
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 1, Description = "Panna 50cl",
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 1, Description = "An item with really long description that should wrap",
UnitPrice = 5.50m, TotalPrice = 5.50m, TaxCategory = "A"
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 2, Description = "Business Lunch Menu Seco",
UnitPrice = 44.00m, TotalPrice = 88.00m, TaxCategory = "A",
SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 2, Description = "Brunello di Montalcino 1",
UnitPrice = 16.00m, TotalPrice = 32.00m, TaxCategory = "A"
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 2, Description = "Espresso",
UnitPrice = 5.50m, TotalPrice = 11.00m, TaxCategory = "A"
});
receipt.Items.Add(new FinalReceiptItem
{
Quantity = 1, Description = "Tip",
UnitPrice = 10.50m, TotalPrice = 10.50m, TaxCategory = "B"
});
if (includeTax)
{
receipt.TaxBreakdown.Add(new TaxInfo
{
Category = "A", Rate = 8.1m, Gross = 149.50m,
Net = 138.30m, TaxAmount = 11.20m, Currency = "CHF"
});
receipt.TaxBreakdown.Add(new TaxInfo
{
Category = "B", Rate = 0m, Gross = 10.50m,
Net = 10.50m, TaxAmount = 0.00m, Currency = "CHF"
});
}
return SerializeWithComputedProps(receipt);
}
public static string BuildInvoiceReceiptJson()
{
var receipt = new InvoiceReceipt
{
CompanyName = "Klingler Gastro AG",
Address1 = "Münzplatz 3",
Address2 = "CH-8001 Zürich",
Phone = "043 321 22 22",
ReceiptNumber = null,
DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
Guests = 2,
Total = 160.00m,
Currency = "CHF",
TableNumber = "12",
ThankYouMessage = "Thank you!"
};
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 1, Description = "San Pellegrino 50cl",
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 1, Description = "Panna 50cl",
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 1, Description = "Granini Tomatensaft",
UnitPrice = 5.50m, TotalPrice = 5.50m, TaxCategory = "A"
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 2, Description = "Business Lunch Menu Seco",
UnitPrice = 44.00m, TotalPrice = 88.00m, TaxCategory = "A",
SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 2, Description = "Brunello di Montalcino 1",
UnitPrice = 16.00m, TotalPrice = 32.00m, TaxCategory = "A"
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 2, Description = "Espresso",
UnitPrice = 5.50m, TotalPrice = 11.00m, TaxCategory = "A"
});
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
{
Quantity = 1, Description = "Tip",
UnitPrice = 10.50m, TotalPrice = 10.50m, TaxCategory = "B"
});
return SerializeWithComputedProps(receipt);
}
public static string BuildOrderItemsJson()
{
var receipt = new OrderItemsReceipt
{
OrderNumber = "1",
QRInfo = "Margherita Pizza Classic longer text",
DateTime = new DateTime(2026, 1, 14, 14, 35, 47),
ClientNotes = "Some main note",
Items = new List<OrderItem>
{
new()
{
Number = 1, Name = "pappara", Quantity = 1,
SubItems = new List<string> { "pizza", "cola" },
Comment = "Cola zero please"
},
new()
{
Number = 2, Name = "Classic Beef Burger", Quantity = 1,
Modifications = new ItemModifications
{
Removed = new List<string> { "Onion" },
Added = new List<string> { "butter" }
},
Comment = "Medium rare please"
},
new()
{
Number = 3, Name = "Margherita Pizza Classic",
Quantity = 2, Size = "L"
}
}
};
return SerializeWithComputedProps(receipt);
}
#endregion
#region Computed Properties
private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true };
private static string SerializeWithComputedProps(object receipt)
{
var json = JsonSerializer.Serialize(receipt, SerializerOptions);
var node = JsonNode.Parse(json)!;
switch (receipt)
{
case KitchenReceipt kr:
AddKitchenComputedProps(node, kr);
break;
case FinalReceipt fr:
AddFinalReceiptComputedProps(node, fr);
break;
case InvoiceReceipt ir:
AddInvoiceComputedProps(node, ir);
break;
case OrderItemsReceipt or:
AddOrderItemsComputedProps(node, or);
break;
}
return node.ToJsonString(SerializerOptions);
}
private static void AddKitchenComputedProps(JsonNode node, KitchenReceipt receipt)
{
node["HasGangs"] = receipt.Gangs.Count > 0;
node["HasDishes"] = receipt.Dishes.Count > 0;
// Add GuestPrefix and HasModifications to dishes in gangs
var gangsArray = node["Gangs"]?.AsArray();
if (gangsArray != null)
{
for (int g = 0; g < receipt.Gangs.Count; g++)
{
var gangDishes = gangsArray[g]?["Dishes"]?.AsArray();
if (gangDishes != null)
{
for (int d = 0; d < receipt.Gangs[g].Dishes.Count; d++)
{
var dish = receipt.Gangs[g].Dishes[d];
gangDishes[d]!["GuestPrefix"] = dish.GuestId.HasValue ? $"{dish.GuestId} " : "";
var mods = dish.Modifications;
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
if (gangDishes[d]!["Modifications"] == null)
gangDishes[d]!["Modifications"] = new JsonObject();
gangDishes[d]!["Modifications"]!["HasModifications"] = hasMods;
}
}
}
}
// Add GuestPrefix and HasModifications to top-level dishes
var dishesArray = node["Dishes"]?.AsArray();
if (dishesArray != null)
{
for (int d = 0; d < receipt.Dishes.Count; d++)
{
var dish = receipt.Dishes[d];
dishesArray[d]!["GuestPrefix"] = dish.GuestId.HasValue ? $"{dish.GuestId} " : "";
var mods = dish.Modifications;
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
if (dishesArray[d]!["Modifications"] == null)
dishesArray[d]!["Modifications"] = new JsonObject();
dishesArray[d]!["Modifications"]!["HasModifications"] = hasMods;
}
}
}
private static void AddFinalReceiptComputedProps(JsonNode node, FinalReceipt receipt)
{
node["ReceiptLabel"] = receipt.ReceiptNumber != null
? $"Rechnung Nr. {receipt.ReceiptNumber}"
: "";
node["HasSplitPayments"] = receipt.SplitPayments.Count > 0;
node["HasTaxableCategories"] = receipt.TaxBreakdown.Any(t =>
!string.Equals(t.Category, "d", StringComparison.OrdinalIgnoreCase));
var itemsArray = node["Items"]?.AsArray();
if (itemsArray != null)
{
for (int i = 0; i < receipt.Items.Count; i++)
{
var item = receipt.Items[i];
itemsArray[i]!["PriceDisplay"] =
$"{item.UnitPrice:F2}" +
$"{item.TotalPrice:F2}".PadLeft(7) +
$" {item.TaxCategory}";
}
}
}
private static void AddInvoiceComputedProps(JsonNode node, InvoiceReceipt receipt)
{
node["ReceiptLabel"] = receipt.ReceiptNumber != null
? $"Rechnung Nr. {receipt.ReceiptNumber}"
: "";
var itemsArray = node["Items"]?.AsArray();
if (itemsArray != null)
{
for (int i = 0; i < receipt.Items.Count; i++)
{
var item = receipt.Items[i];
itemsArray[i]!["PriceDisplay"] =
$"{item.UnitPrice:F2}" +
$"{item.TotalPrice:F2}".PadLeft(7) +
$" {item.TaxCategory}";
}
}
}
private static void AddOrderItemsComputedProps(JsonNode node, OrderItemsReceipt receipt)
{
var itemsArray = node["Items"]?.AsArray();
if (itemsArray != null)
{
for (int i = 0; i < receipt.Items.Count; i++)
{
var item = receipt.Items[i];
itemsArray[i]!["SizePart"] = !string.IsNullOrEmpty(item.Size)
? item.Size + " "
: "";
var mods = item.Modifications;
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
if (itemsArray[i]!["Modifications"] == null)
itemsArray[i]!["Modifications"] = new JsonObject();
itemsArray[i]!["Modifications"]!["HasModifications"] = hasMods;
}
}
}
#endregion
}