Use fully-qualified KitchenReceipt namespace for Gang, Dish, and DishModifications in BuildSampleKitchenReceipt and BuildSampleKitchenReceiptNextDish to resolve CS0104 errors caused by identical type names in BarReceipt and KitchenReceipt namespaces. Add global.json to pin SDK to .NET 8.0 for compatibility with .slnx. Co-Authored-By: Paperclip <noreply@paperclip.ing>
582 lines
20 KiB
C#
582 lines
20 KiB
C#
using System.Diagnostics;
|
|
using Inspectron.Epson;
|
|
using Inspectron.Epson.PrintServer.Printers.Utils;
|
|
using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt;
|
|
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;
|
|
|
|
namespace EpsonTest;
|
|
|
|
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 Receipt Builders
|
|
|
|
public static FinalReceipt BuildSampleFinalReceipt(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,//"1-81-202",
|
|
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",
|
|
|
|
}
|
|
};
|
|
|
|
// Add items
|
|
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)
|
|
{
|
|
// Add tax breakdown
|
|
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 receipt;
|
|
}
|
|
|
|
public static InvoiceReceipt BuildSampleInvoiceReceipt()
|
|
{
|
|
var receipt = new InvoiceReceipt
|
|
{
|
|
CompanyName = "Klingler Gastro AG",
|
|
Address1 = "Münzplatz 3",
|
|
Address2 = "CH-8001 Zürich",
|
|
Phone = "043 321 22 22",
|
|
ReceiptNumber = null,//"1-81-202",
|
|
DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
|
|
Guests = 2,
|
|
Total = 160.00m,
|
|
Currency = "CHF",
|
|
TableNumber = "12",
|
|
ThankYouMessage = "Thank you!"
|
|
|
|
};
|
|
|
|
// Add items
|
|
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 with something long to cause line wrapping more and more",
|
|
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 receipt;
|
|
}
|
|
|
|
public static KitchenReceipt BuildSampleKitchenReceipt()
|
|
{
|
|
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 Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Gang(1, "Gang"));
|
|
receipt.Gangs.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Gang(2, "Gang"));
|
|
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(1, "Avocado Sashimi with some addition to cause line wrapping")
|
|
{
|
|
Size = "XL",
|
|
Modifications = new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.DishModifications
|
|
{
|
|
Removed = new List<string> { "Wasabi" },
|
|
Added = new List<string> { "Extra Ginger" }
|
|
},
|
|
Comment = "No soy sauce",
|
|
GuestId = 1,
|
|
Price = 123.45m
|
|
});
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(2, "Avocado Sashimi with some addition to cause line wrapping") { GuestId = 2 });
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(1, "Avocado Sashimi with some addition to cause line wrapping") { GuestId = 3 });
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(1, "Baby Spinach Salad with Truffl"){GuestId = 2});
|
|
//receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
|
|
//{
|
|
// Modifications = new DishModifications
|
|
// {
|
|
// Removed = new List<string> { "Onion" },
|
|
// Added = new List<string> { "Extra Sauce" }
|
|
// },
|
|
// Comment = "Medium rare",
|
|
// GuestId = 3
|
|
//});
|
|
//receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
|
|
//{
|
|
// Modifications = new DishModifications
|
|
// {
|
|
// Added = new List<string> { "Extra Lime" }
|
|
// },
|
|
// GuestId = 4
|
|
//});
|
|
|
|
receipt.Gangs[1].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(1, "Avocado Sashimi") { GuestId = 1 });
|
|
receipt.Gangs[1].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
|
|
//receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki") { GuestId = 3 });
|
|
//receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco") { GuestId = 4 });
|
|
|
|
return receipt;
|
|
}
|
|
|
|
public static KitchenReceipt BuildSampleKitchenReceiptNextDish()
|
|
{
|
|
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 Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.Gang(2, "Gang"));
|
|
// to dishes in next dish
|
|
//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"
|
|
//});
|
|
//receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl"));
|
|
//receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
|
|
//{
|
|
// Modifications = new DishModifications
|
|
// {
|
|
// Removed = new List<string> { "Onion" },
|
|
// Added = new List<string> { "Extra Sauce" }
|
|
// },
|
|
// Comment = "Medium rare"
|
|
//});
|
|
//receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
|
|
//{
|
|
// Modifications = new DishModifications
|
|
// {
|
|
// Added = new List<string> { "Extra Lime" }
|
|
// }
|
|
//});
|
|
|
|
return receipt;
|
|
}
|
|
|
|
public static BarReceipt BuildSampleBarReceipt()
|
|
{
|
|
var receipt = new BarReceipt
|
|
{
|
|
Title = "Bar",
|
|
TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
|
|
ReceiptNumber = "132018166",
|
|
WaiterName = "Mariano Amato",
|
|
WaiterId = "32 (VK Restaurant)",
|
|
TableNumber = "22"
|
|
};
|
|
|
|
receipt.Gangs.Add(new Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt.Gang(1, "Gang"));
|
|
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt.Dish(2, "Aperol Spritz") { GuestId = 1 });
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt.Dish(1, "Prosecco") { GuestId = 2 });
|
|
receipt.Gangs[0].Dishes.Add(new Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt.Dish(1, "Mojito with extra mint and lime") { GuestId = 3 });
|
|
|
|
return receipt;
|
|
}
|
|
|
|
public static OrderItemsReceipt BuildSampleOrderItemsReceipt()
|
|
{
|
|
return 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"
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#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
|
|
}
|