diff --git a/EpsonPrintService/EpsonPrintService.csproj b/EpsonPrintService/EpsonPrintService.csproj index 6b5d985..3e07211 100644 --- a/EpsonPrintService/EpsonPrintService.csproj +++ b/EpsonPrintService/EpsonPrintService.csproj @@ -5,6 +5,7 @@ net8.0 enable enable + 1.0.0 diff --git a/EpsonTemplatesTest/Templates/final-receipt.template b/EpsonTemplatesTest/Templates/final-receipt.template index f0cfece..4ead507 100644 --- a/EpsonTemplatesTest/Templates/final-receipt.template +++ b/EpsonTemplatesTest/Templates/final-receipt.template @@ -4,24 +4,27 @@ #center# {Phone} # @row bold -|24|Rechnung Nr. {ReceiptNumber}|24,right|{DateTime:HH:mm dd.MM.yyyy} +|24,left|Rechnung Nr. {ReceiptNumber}|24,right|{DateTime:HH:mm dd.MM.yyyy} # +@endrow Guests: {Guests} - - @foreach item in Items -{item.Quantity}x {item.Description} {right:{item.UnitPrice:F2} {item.TotalPrice:F2} {item.TaxCategory}} +@row +|30|{item.Quantity}x {item.Description}|18,right|{item.UnitPrice:F2} {item.TotalPrice:F2} {item.TaxCategory} +@endrow @end +#right# --------- -{right:---------} #big,bold,center# Summe: {Total:F2} {Currency} # @if TotalInAlternateCurrency -{right:{TotalInAlternateCurrency:F2} {AlternateCurrency}} +#right#{TotalInAlternateCurrency:F2} {AlternateCurrency} @end -#bold# {PaymentMethod} {right:{PaymentAmount:F2} {Currency}} # +@row bold +|24|{PaymentMethod}|25,right|{PaymentAmount:F2} {Currency} +@endrow @if TaxBreakdown.count > 0 MwSt % Brutto Netto MwSt diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs index 278fc2a..7458e1d 100644 --- a/EpsonTest/Program.cs +++ b/EpsonTest/Program.cs @@ -1,688 +1,201 @@ -using Inspectron.Epson; -using Inspectron.Epson.PrintServer.Printers.Utils; +using EpsonTest; +using Inspectron.Epson; using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe; -using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; -using Inspectron.Epson.SOAP; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; -using System.Text; -using System.Text.Json; -using System.Xml.Linq; using Inspectron.Epson.PrintServer.Printers.Utils.FinalReceipt; +using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; +using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems; -using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt; +using System.Text.Json; + +// ============================================================================ +// FINAL RECEIPT - HTML PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleFinalReceipt(); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); + +//var converter = new FinalReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +//var printCommands = converter.Convert(serializedReceipt); + +//TestHelpers.PrintCommandsToConsole(printCommands); + +//var printer = await TestHelpers.CreateHtmlPrinterAsync(); +//await TestHelpers.PrintCommandsToHtmlPrinterAsync( +// printer, +// printCommands, +// logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); -//SoapEpsonPrinter printer = new SoapEpsonPrinter("localhost:8888"); -//var print = new SoapEpsonPrint(); -//print -// .AddText("123") -// .AddFeed() -// .AddFeed() -// .AddCut(SoapEpsonPrint.CUT_FEED); +// ============================================================================ +// FINAL RECEIPT - EPSON PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleFinalReceipt(); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); -//var task = await printer.Send(print); -//var status = await printer.GetStatus(print); +//var converter = new FinalReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +//var printCommands = converter.Convert(serializedReceipt); -//HttpClient httpClient = new HttpClient(new HttpClientHandler -//{ -// ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true -//}); +//TestHelpers.PrintCommandsToConsole(printCommands); -//var requestText = @" -// -// -// Hello, World! -// -// -//"; +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); +//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); -//var request = new HttpRequestMessage(HttpMethod.Post, -// "https://localhost:8888/cgi-bin/epos/service.cgi?devid=local_printer&timeout=10000"); -//var response = httpClient.Send(request); -//var responseText = await response.Content.ReadAsStringAsync(); -//Console.WriteLine(responseText); - - - -//var printer = new EpsonPrinter(); -//await printer.ConnectAsync("127.0.0.1",8888); -//for (int i = 0; i < 20; i++) -//{ -// await printer.PrintTextAsync("Hello\n"); -//} - -//await printer.FeedLinesAsync(5); -//await printer.CutAsync(); - -//var status = await printer.GetPrinterStatusAsync(); -//Console.ReadLine(); - - -var receipt = new FinalReceipt -{ - CompanyName = "Klingler Gastro AG", - Address1 = "Münzplatz 3", - Address2 = "CH-8001 Zürich", - Phone = "043 321 22 22", - ReceiptNumber = "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.", - SplitPayments = new List - { - new SplitPaymentInfo { PaymentMethod = "Cash", Amount = 50.00m, Currency = "CHF"}, - new SplitPaymentInfo { PaymentMethod = "Card", Amount = 110.00m, Currency = "CHF" } - }, - TerminalReceipts = new List - { - new PaymentTerminalReceipt - { - 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 PaymentTerminalReceipt - { - 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" - } - } -}; - -// Add items -receipt.Items.Add(new ReceiptItem -{ - Quantity = 1, - Description = "San Pellegrino 50cl", - UnitPrice = 6.50m, - TotalPrice = 6.50m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 1, - Description = "Panna 50cl", - UnitPrice = 6.50m, - TotalPrice = 6.50m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 1, - Description = "Granini Tomatensaft", - UnitPrice = 5.50m, - TotalPrice = 5.50m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 2, - Description = "Business Lunch Menu Seco", - UnitPrice = 44.00m, - TotalPrice = 88.00m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 2, - Description = "Brunello di Montalcino 1", - UnitPrice = 16.00m, - TotalPrice = 32.00m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 2, - Description = "Espresso", - UnitPrice = 5.50m, - TotalPrice = 11.00m, - TaxCategory = "A" -}); - -receipt.Items.Add(new ReceiptItem -{ - Quantity = 1, - Description = "Tip", - UnitPrice = 10.50m, - TotalPrice = 10.50m, - TaxCategory = "B" -}); - -// 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" -}); - +// ============================================================================ +// INVOICE RECEIPT - HTML PRINTER +// ============================================================================ +var receipt = TestHelpers.BuildSampleInvoiceReceipt(); var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); -var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); -// Convert to print commands -var converter = new FinalReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); + +var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); var printCommands = converter.Convert(serializedReceipt); +TestHelpers.PrintCommandsToConsole(printCommands); + +var printer = await TestHelpers.CreateHtmlPrinterAsync(); +await TestHelpers.PrintCommandsToHtmlPrinterAsync( + printer, + printCommands, + logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); +// ============================================================================ +// INVOICE RECEIPT - EPSON PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleInvoiceReceipt(); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); -// Print the commands -Console.WriteLine("=== PRINT COMMANDS ===\n"); -var printer = new HtmlPrinter(@".\test.html", paperWidth: 384); -await printer.ConnectAsync(""); -await printer.SetAbsolutePrintPosition(42); -await printer.LoadImageAsync("ristorante-klinglers.ch-logo_white_bg.png", 300); -await printer.PrintLoadedImage(); -await printer.SetAbsolutePrintPosition(0); -await Task.Delay(200); -//await printer.FeedLinesAsync(1); -await printer.SetCustomLineSpacing(22); -foreach (var command in printCommands) -{ - string attributes = ""; - if (command.IsBig) attributes += "[BIG] "; - if (command.IsBold) attributes += "[BOLD] "; +//var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +//var printCommands = converter.Convert(serializedReceipt); - Console.WriteLine($"{attributes}{command.Text}"); +//TestHelpers.PrintCommandsToConsole(printCommands); - if (command.IsBig) - { - await printer.SetFontSizeAsync(2, 1); - } - else - { - await printer.SetFontSizeAsync(1, 1); - } - //await Task.Delay(200); - - await printer.SetEmphasized(command.IsBold); - //await Task.Delay(200); - - await printer.PrintTextAsync(command.Text + "\n"); - //await Task.Delay(200); - -} +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); +//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); -//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 -//}; - -//// Add dishes (this section can be empty if no dishes were ordered) - -//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 { "Wasabi" }, -// Added = new List { "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 { "Onion" }, -// Added = new List { "Extra Sauce" } -// }, -// Comment = "Medium rare" -//}); -//receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") -//{ -// Modifications = new DishModifications -// { -// Added = new List { "Extra Lime" } -// } -//}); - - -//receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi")); -//receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); -//receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki")); -//receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco")); - -//receipt.Dishes.Add(new Dish(1, "Avocado Sashimi")); -//receipt.Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); -//receipt.Dishes.Add(new Dish(1, "Beef Tataki")); -//receipt.Dishes.Add(new Dish(1, "Salmon Taco")); - - -//// Add additional info - +// ============================================================================ +// KITCHEN RECEIPT - HTML PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleKitchenReceipt(); //var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); //var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); -//KitchenReceiptConverter converter = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth: 33); + +//var converter = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth: 33); //var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); -//Console.WriteLine("=== PRINT COMMANDS ===\n"); -//var printer = new HtmlPrinter(@".\test.html", paperWidth: 258); -//await printer.ConnectAsync(""); -//await Task.Delay(200); -//await printer.FeedLinesAsync(1); -//await printer.SetCustomLineSpacing(22); -//foreach (var command in printCommands) -//{ -// string attributes = ""; -// if (command.IsBig) attributes += "[BIG] "; -// if (command.IsBold) attributes += "[BOLD] "; -// if (command.IsRed) attributes += "[RED] "; +//TestHelpers.PrintCommandsToConsole(printCommands); -// Console.WriteLine($"{attributes}{command.Text}"); - -// if (command.IsBig) -// { -// await printer.SetFontSizeAsync(2, 1); -// } -// else -// { -// await printer.SetFontSizeAsync(1, 1); -// } - -// await printer.SetRedColor(command.IsRed); - -// //await Task.Delay(200); - -// await printer.SetEmphasized(command.IsBold); -// //await Task.Delay(200); - -// await printer.PrintTextAsync(command.Text + "\n"); -// //await Task.Delay(200); - -//} +//var printer = await TestHelpers.CreateHtmlPrinterAsync( +// path: @".\kitchen_test.html", +// paperWidth: TestHelpers.KitchenPaperWidth); +//await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands); -//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 = "Next dish" -//}; - -//// Add dishes (this section can be empty if no dishes were ordered) - -//receipt.Gangs.Add(new Gang(2, "Gang")); - -//receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi") -//{ -// Modifications = new DishModifications -// { -// Removed = new List { "Wasabi" }, -// Added = new List { "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 { "Onion" }, -// Added = new List { "Extra Sauce" } -// }, -// Comment = "Medium rare" -//}); -//receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") -//{ -// Modifications = new DishModifications -// { -// Added = new List { "Extra Lime" } -// } -//}); - -//// Add additional info - +// ============================================================================ +// KITCHEN RECEIPT (NEXT DISH) - HTML PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleKitchenReceiptNextDish(); //var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); //var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); -//KitchenReceiptConverter converter = new KitchenReceiptConverter(bigLineWidth: 18, lineWidth: 33); + +//var converter = new KitchenReceiptConverter(bigLineWidth: 18, lineWidth: 33); //var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); -//Console.WriteLine("=== PRINT COMMANDS ===\n"); -////var printer = new HtmlPrinter(@".\test.html", paperWidth: 258); -////await printer.ConnectAsync(""); -//bool useDelay=true; -//var printer = new EpsonPrinter(); -//await printer.ConnectAsync("127.0.0.1", 8888); -//if (useDelay)await Task.Delay(200); -//await printer.FeedLinesAsync(1); -//await printer.SetCustomLineSpacing(22); -//foreach (var command in printCommands) -//{ -// string attributes = ""; -// if (command.IsBig) attributes += "[BIG] "; -// if (command.IsBold) attributes += "[BOLD] "; -// if (command.IsRed) attributes += "[RED] "; +//TestHelpers.PrintCommandsToConsole(printCommands); -// Console.WriteLine($"{attributes}{command.Text}"); -// await printer.SetBiggerFontTM220(command.IsBig, command.IsTall| command.IsBig, secondaryFont: false); +//var printer = await TestHelpers.CreateHtmlPrinterAsync( +// path: @".\kitchen_next_dish.html", +// paperWidth: TestHelpers.KitchenPaperWidth); +//await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands); +// ============================================================================ +// KITCHEN RECEIPT - EPSON PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleKitchenReceiptNextDish(); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); +//var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); -// if (useDelay) await Task.Delay(200); +//var converter = new KitchenReceiptConverter(bigLineWidth: 18, lineWidth: 33); +//var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); -// await printer.SetRedColor(command.IsRed); +//TestHelpers.PrintCommandsToConsole(printCommands); -// if (useDelay) await Task.Delay(200); +//var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth:TestHelpers.KitchenPaperWidth); +//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true); -// await printer.SetEmphasized(command.IsBold); -// if (useDelay) await Task.Delay(200); -// await printer.PrintTextAsync(command.Text + "\n"); -// if (useDelay) await Task.Delay(200); +// ============================================================================ +// ORDER ITEMS RECEIPT - HTML PRINTER +// ============================================================================ +//var receipt = TestHelpers.BuildSampleOrderItemsReceipt(); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); +//Console.WriteLine(serializedReceipt); +//var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); -//} +//var converter = new ReceiptConverter(lineWidth: 50, bigFontLineWidth: 21); +//var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); +//TestHelpers.PrintCommandsToConsole(printCommands); + +//var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\order_items.html"); +//await TestHelpers.PrintCommandsToHtmlPrinterAsync(printer, printCommands); + + +// ============================================================================ +// BASIC PRINTER STATUS CHECK +// ============================================================================ +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); +//var status = await printer.GetPrinterStatusAsync(); +//Console.WriteLine($"Printer Status: {status}"); +//var paperStatus = await printer.GetPaperSensorStatusAsync(); +//Console.WriteLine($"Paper Sensor Status: {paperStatus}"); + + +// ============================================================================ +// SIMPLE TEXT PRINT TEST +// ============================================================================ +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); +//await printer.InitAsync(); +//await printer.PrintTextAsync("Hello, World!\n"); //await printer.FeedLinesAsync(5); -//if (useDelay) await Task.Delay(200*5); //await printer.CutAsync(); -//await printer.SetDefaultLineSpacing(); -//await printer.PrintTextAsync( -// "1x San Pellegrino 50cl 6.50 6.50 A\n1x Panna 50cl 6.50 6.50 A"); -//// Order Items Receipt Test -//var orderItemsReceipt = 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 -// { -// new OrderItem -// { -// Number = 1, -// Name = "pappara", -// Quantity = 1, -// SubItems = new List { "pizza", "cola" }, -// Comment = "Cola zero please" -// }, -// new OrderItem -// { -// Number = 2, -// Name = "Classic Beef Burger", -// Quantity = 1, -// Modifications = new ItemModifications -// { -// Removed = new List { "Onion" }, -// Added = new List { "butter" } -// }, -// Comment = "Medium rare please" -// }, -// new OrderItem -// { -// Number = 3, -// Name = "Margherita Pizza Classic", -// Quantity = 2, -// Size = "L" -// } -// } -//}; - -//var serializedOrderItems = JsonSerializer.Serialize(orderItemsReceipt, new JsonSerializerOptions { WriteIndented = true }); -//Console.WriteLine(serializedOrderItems); -//var deserializedOrderItems = JsonSerializer.Deserialize(serializedOrderItems); - -//var orderItemsConverter = new Inspectron.Epson.PrintServer.Printers.Utils.OrderItems.ReceiptConverter(lineWidth: 50, bigFontLineWidth: 21); -//var printCommands = orderItemsConverter.ConvertToPrintCommands(deserializedOrderItems); - -//Console.WriteLine("=== PRINT COMMANDS ===\n"); -//var printer = new HtmlPrinter(@".\order_items.html", paperWidth: 384); -//await printer.ConnectAsync(""); -//await Task.Delay(200); -////await printer.FeedLinesAsync(1); -//await printer.SetCustomLineSpacing(22); -//foreach (var command in printCommands) -//{ -// string attributes = ""; -// if (command.IsBig) attributes += "[BIG] "; -// if (command.IsBold) attributes += "[BOLD] "; - -// Console.WriteLine($"{attributes}{command.Text}"); - -// if (command.IsBig) -// { -// await printer.SetFontSizeAsync(2, 1); -// } -// else -// { -// await printer.SetFontSizeAsync(1, 1); -// } -// //await Task.Delay(200); - -// await printer.SetEmphasized(command.IsBold); -// //await Task.Delay(200); - -// await printer.PrintTextAsync(command.Text + "\n"); -// //await Task.Delay(200); - -//} - - - - - - - -// clear printer buffer -//await printer.SendRawCommandAsync([0x10, 0x14, 0x08, 0x01, 0x03, 0x14, 0x01, 0x06, 0x02, 0x08]); -// -//for (int i = 0; i < 10; i++) -//{ -// await printer.SendRawCommandAsync(EpsonCommands.LineFeed); -// await Task.Delay(200); -//} - -//await printer.InitAsync(); -//await Task.Delay(200); - -//KitchenReceiptPrinter krp = new KitchenReceiptPrinter(33); -//var receipt = new TranslatedKitchenReceipt( -// Location: "Warme Küche", -// Date: "23-Okt-25 12:18 Nr.:13201B166", -// Owner: "Mariano Amato\n32 (VK Restaurant)", -// Tisch: "22", -// items: new List -// { -// new KitchenGang("1. Gang"), -// new KitchenProduct(1, "Avocado Sashimi"), -// new KitchenProduct(1, "Baby Spinach Salad with Truffl"), -// new KitchenGang("2. Gang"), -// new KitchenProduct(1, "Beef Tataki"), -// new KitchenProduct(1, "Salmon Taco") -// } -//); - -//var test = JsonSerializer.Serialize(receipt, new JsonSerializerOptions() { WriteIndented = true }); -//Console.WriteLine(test); - -////// Create printer with 42 character line width (default) -//var commands = krp.ConvertToCommands(receipt); - -//foreach (PrintCommand command in commands) -//{ -// await printer.SetBiggerFontTM220(command.IsBig); -// await Task.Delay(200); -// await printer.SetRedColor(command.IsRed); -// await Task.Delay(200); -// await printer.SetEmphasized(command.IsBold); -// await Task.Delay(200); -// await printer.PrintTextAsync(command.Text + "\n"); -// await Task.Delay(200); -//} - - - -//await printer.SetBiggerFontTM220(true); -// 24 -//await printer.SetFontSizeAsync(2,2); -//await Task.Delay(200); -//await printer.SelectFont(EpsonCommands.PrinterFont.A); -//await Task.Delay(200); -//await printer.PrintTextAsync("HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_\n"); -//await Task.Delay(200); - -//// 48 -//await printer.SetFontSizeAsync(1, 1); -//await Task.Delay(200); -//await printer.SelectFont(EpsonCommands.PrinterFont.A); -//await Task.Delay(200); -//await printer.PrintTextAsync("HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_\n"); -//await Task.Delay(200); -//await printer.SetBiggerFontTM220(false); -//await Task.Delay(200); -//await printer.SelectFont(EpsonCommands.PrinterFont.A); -//await Task.Delay(200); -//await printer.PrintTextAsync("HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_\n"); -//await Task.Delay(200); - - - -//await printer.FeedLinesAsync(10); -//await Task.Delay(1000); - - -//await printer.SetQuadrupleMode(false); -//await printer.PrintImageBitModeAsync("test.png",maxWidth:24); +// ============================================================================ +// IMAGE PRINT TEST +// ============================================================================ +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); //await printer.LoadImageAsync("test.png", 100); //await printer.PrintLoadedImage(); - -//for (int i = 1; i < 5; i++) -//{ -// List lineBytes = new List(); - -// for (int j = 0; j < i; j++) -// { -// lineBytes.AddRange([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,]); -// lineBytes.AddRange([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,]); - -// } -// var bytes = EpsonCommands.CreateBitImageCommand(EpsonCommands.BitImageMode.SingleDensity8Dot, -// lineBytes.ToArray(), i*16); -// await printer.SendRawCommandAsync(bytes); -// await printer.SendRawCommandAsync(EpsonCommands.LineFeed); -//} - - -//await printer.SetAbsolutePrintPosition(50); -//await printer.SetFontSizeAsync(2, 2); -//await printer.PrintTextAsync("Hello!"); -//await printer.SendRawCommandAsync(EpsonCommands.LineFeed); -//await printer.FeedLinesAsync(7); - -//await printer.PrintImageBitModeAsync("test.png"); -//var bytes = EpsonCommands.CreateBitImageCommand(EpsonCommands.BitImageMode.SingleDensity8Dot, -// [ -// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], 32); -//await printer.SendRawCommandAsync(bytes); -//await Task.Delay(2000); -//await printer.PrintBuffer(); - -//var printer = new EpsonPrinter(); -//await printer.ConnectAsync("127.0.0.1", 8888); -//await printer.InitAsync(); - -//await printer.PrintTextAsync("Hello!"); //await printer.FeedLinesAsync(5); - //await printer.CutAsync(); +// ============================================================================ +// FONT SIZE TEST +// ============================================================================ +//var printer = await TestHelpers.CreateEpsonPrinterAsync(); +//await printer.InitAsync(); -////await CheckStatus(20); +//// Double size (24 chars per line) +//await printer.SetFontSizeAsync(2, 2); +//await printer.SelectFont(EpsonCommands.PrinterFont.A); +//await printer.PrintTextAsync("HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_\n"); -//Task CheckStatus(int iterations) -//{ -// return Task.Run(async () => -// { -// for (int i = 0; i < iterations; i++) -// { -// var status = await printer.GetPrinterStatusAsync(); -// Console.WriteLine($"Printer Status: {status}"); -// var paperStatus = await printer.GetPaperSensorStatusAsync(); -// Console.WriteLine($"Paper Sensor Status: {paperStatus}"); -// await Task.Delay(100); -// } -// }); +//// Normal size (48 chars per line) +//await printer.SetFontSizeAsync(1, 1); +//await printer.SelectFont(EpsonCommands.PrinterFont.A); +//await printer.PrintTextAsync("HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_HHHH_\n"); -//} +//await printer.FeedLinesAsync(5); +//await printer.CutAsync(); -//SoapEpsonPrinter printer = new SoapEpsonPrinter("10.0.20.11"); -//SoapEpsonPrinter printer = new SoapEpsonPrinter("localhost:8888"); +// ============================================================================ +// SOAP PRINTER TEST +// ============================================================================ +//var printer = new SoapEpsonPrinter("localhost:8888"); //var print = new SoapEpsonPrint(); //print // .AddTextAlign(SoapEpsonPrint.ALIGN_CENTER) @@ -695,5 +208,4 @@ foreach (var command in printCommands) //var task = await printer.Send(print); //var status = await printer.GetStatus(print); - -//Console.WriteLine($"Printer Status: {status}"); \ No newline at end of file +//Console.WriteLine($"Printer Status: {status}"); diff --git a/EpsonTest/TestHelpers.cs b/EpsonTest/TestHelpers.cs new file mode 100644 index 0000000..028d37b --- /dev/null +++ b/EpsonTest/TestHelpers.cs @@ -0,0 +1,520 @@ +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; + +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 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 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() + { + var receipt = new FinalReceipt + { + CompanyName = "Klingler Gastro AG", + Address1 = "Münzplatz 3", + Address2 = "CH-8001 Zürich", + Phone = "043 321 22 22", + ReceiptNumber = "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.", + SplitPayments = new List + { + new() { PaymentMethod = "Cash", Amount = 50.00m, Currency = "CHF" }, + new() { PaymentMethod = "Card", Amount = 110.00m, Currency = "CHF" } + }, + TerminalReceipts = new List + { + 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" + } + } + }; + + // 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 = "Granini Tomatensaft", + 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" + }); + + 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" + }); + + // 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 = "1-81-202", + DateTime = new DateTime(2025, 12, 16, 14, 58, 0), + Guests = 2, + Total = 160.00m, + Currency = "CHF" + }; + + // 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", + 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" + }); + + 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 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 { "Wasabi" }, + Added = new List { "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 { "Onion" }, + Added = new List { "Extra Sauce" } + }, + Comment = "Medium rare" + }); + receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") + { + Modifications = new DishModifications + { + Added = new List { "Extra Lime" } + } + }); + + receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi")); + receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); + receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki")); + receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco")); + + 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 = "Next dish" + }; + + receipt.Gangs.Add(new Gang(2, "Gang")); + + receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi") + { + Modifications = new DishModifications + { + Removed = new List { "Wasabi" }, + Added = new List { "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 { "Onion" }, + Added = new List { "Extra Sauce" } + }, + Comment = "Medium rare" + }); + receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") + { + Modifications = new DishModifications + { + Added = new List { "Extra Lime" } + } + }); + + 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 + { + new() + { + Number = 1, + Name = "pappara", + Quantity = 1, + SubItems = new List { "pizza", "cola" }, + Comment = "Cola zero please" + }, + new() + { + Number = 2, + Name = "Classic Beef Burger", + Quantity = 1, + Modifications = new ItemModifications + { + Removed = new List { "Onion" }, + Added = new List { "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 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 commands, + bool useDelay = true, + int delayMs = 500) + { + await printer.FeedLinesAsync(1); + await printer.SetCustomLineSpacing(22); + + foreach (var command in commands) + { + 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(5); + if (useDelay) await Task.Delay(delayMs * 5); + await printer.CutAsync(); + } + + public static async Task PrintKitchenCommandsToHtmlPrinterAsync( + HtmlPrinter printer, + IEnumerable commands) + { + await printer.FeedLinesAsync(1); + 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.SetRedColor(command.IsRed); + await printer.SetEmphasized(command.IsBold); + await printer.PrintTextAsync(command.Text + "\n"); + } + } + + #endregion + + #region Console Output + + public static void PrintCommandsToConsole(IEnumerable 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 +} diff --git a/Inspectron.Epson.Templates.Tests/Language/ParserTests.cs b/Inspectron.Epson.Templates.Tests/Language/ParserTests.cs index a079aea..4e74997 100644 --- a/Inspectron.Epson.Templates.Tests/Language/ParserTests.cs +++ b/Inspectron.Epson.Templates.Tests/Language/ParserTests.cs @@ -134,7 +134,7 @@ public class ParserTests var result = Parse("line1\n\nline2"); Assert.False(result.HasErrors); - Assert.Contains(result.Template.ChildNodes, n => n is EmptyLineNode); + Assert.Contains(result.Template.ChildNodes, n => n is NewLineNode); } [Fact] diff --git a/Inspectron.Epson.Templates/Interpreter/TemplateInterpreter.cs b/Inspectron.Epson.Templates/Interpreter/TemplateInterpreter.cs index b5fd544..49bb967 100644 --- a/Inspectron.Epson.Templates/Interpreter/TemplateInterpreter.cs +++ b/Inspectron.Epson.Templates/Interpreter/TemplateInterpreter.cs @@ -73,38 +73,38 @@ public class TemplateInterpreter // Styled text - flush buffer, emit styled content, continue accumulating case StyledTextNode styledNode: - FlushLineBuffer(); + InterpretStyledText(styledNode, context, commands, style); break; // Block nodes - flush buffer first, then process case SeparatorNode separatorNode: - FlushLineBuffer(); + InterpretSeparator(separatorNode, commands, style); break; - case EmptyLineNode: + case NewLineNode: FlushLineBuffer(); commands.Add(CreateCommand(string.Empty, style)); break; case IfNode ifNode: - FlushLineBuffer(); + InterpretIf(ifNode, context, commands, style); break; case ForeachNode foreachNode: - FlushLineBuffer(); + InterpretForeach(foreachNode, context, commands, style); break; case RowNode rowNode: - FlushLineBuffer(); + InterpretRow(rowNode, context, commands, style); break; case ColumnNode columnNode: - FlushLineBuffer(); + InterpretColumn(columnNode, context, commands, style); break; } diff --git a/Inspectron.Epson.Templates/Language/Nodes/EmptyLineNode.cs b/Inspectron.Epson.Templates/Language/Nodes/NewLineNode.cs similarity index 66% rename from Inspectron.Epson.Templates/Language/Nodes/EmptyLineNode.cs rename to Inspectron.Epson.Templates/Language/Nodes/NewLineNode.cs index 13565c1..624b372 100644 --- a/Inspectron.Epson.Templates/Language/Nodes/EmptyLineNode.cs +++ b/Inspectron.Epson.Templates/Language/Nodes/NewLineNode.cs @@ -1,6 +1,6 @@ namespace Inspectron.Epson.Templates.Language.Nodes; -public record EmptyLineNode(SourcePosition Position) : ITemplateNode +public record NewLineNode(SourcePosition Position) : ITemplateNode { public IReadOnlyList Children => Array.Empty(); } diff --git a/Inspectron.Epson.Templates/Language/Parser.cs b/Inspectron.Epson.Templates/Language/Parser.cs index e13eb7d..b2a95c6 100644 --- a/Inspectron.Epson.Templates/Language/Parser.cs +++ b/Inspectron.Epson.Templates/Language/Parser.cs @@ -46,12 +46,10 @@ public class Parser { case TokenType.NewLine: Advance(); - // Check if this was an empty line (previous was also newline or start) - if (_position >= 2 && _tokens[_position - 2].Type == TokenType.NewLine) - { - return new EmptyLineNode(token.Position); - } - return null; + if(token.Position.Column==1) + return new NewLineNode(token.Position); + else + return null; case TokenType.Text: return ParseText(); diff --git a/Inspectron.Epson.Templates/Validation/TemplateValidator.cs b/Inspectron.Epson.Templates/Validation/TemplateValidator.cs index 0ebed22..46b7a72 100644 --- a/Inspectron.Epson.Templates/Validation/TemplateValidator.cs +++ b/Inspectron.Epson.Templates/Validation/TemplateValidator.cs @@ -139,7 +139,7 @@ public class TemplateValidator case TextNode: case SeparatorNode: - case EmptyLineNode: + case NewLineNode: // No additional validation needed break; } diff --git a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs index 3d1d89c..e1a2248 100644 --- a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs +++ b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs @@ -35,7 +35,7 @@ public class TM_U220IITranslated : IPrinter { foreach (var command in commands) { - await _printer.SetBiggerFontTM220(command.IsBig); + await _printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig); await Task.Delay(200); await _printer.SetRedColor(command.IsRed); await Task.Delay(200); diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs index d37457a..c07299e 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs @@ -9,7 +9,7 @@ public class FinalReceipt public string ReceiptNumber { get; set; } public DateTime DateTime { get; set; } public int Guests { get; set; } - public List Items { get; set; } = new List(); + public List Items { get; set; } = new List(); public decimal Total { get; set; } public string Currency { get; set; } public decimal? TotalInAlternateCurrency { get; set; } @@ -28,7 +28,7 @@ public class FinalReceipt public List TerminalReceipts { get; set; } = new List(); } -public class ReceiptItem +public class FinalReceiptItem { public int Quantity { get; set; } public string Description { get; set; } diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/InvoiceReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/InvoiceReceiptConverter.cs new file mode 100644 index 0000000..f8e174b --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/InvoiceReceiptConverter.cs @@ -0,0 +1,22 @@ +using System.Text.Json; + +namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; + +public class InvoiceReceiptConverter : IReceiptConverter +{ + private readonly int _lineWidth; + private readonly int _bigFontLineWidth; + + public InvoiceReceiptConverter(int lineWidth, int bigFontLineWidth) + { + _lineWidth = lineWidth; + _bigFontLineWidth = bigFontLineWidth; + } + + public List Convert(string jsonContent) + { + var receipt = JsonSerializer.Deserialize(jsonContent); + var converter = new ReceiptConverter(_lineWidth, _bigFontLineWidth); + return converter.ConvertToPrintCommands(receipt); + } +} diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/Models.cs new file mode 100644 index 0000000..e9e114e --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/Models.cs @@ -0,0 +1,24 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; + +public class InvoiceReceipt +{ + public string CompanyName { get; set; } + public string Address1 { get; set; } + public string Address2 { get; set; } + public string Phone { get; set; } + public string ReceiptNumber { get; set; } + public DateTime DateTime { get; set; } + public int Guests { get; set; } + public List Items { get; set; } = new List(); + public decimal Total { get; set; } + public string Currency { get; set; } +} + +public class ReceiptItem +{ + public int Quantity { get; set; } + public string Description { get; set; } + public decimal UnitPrice { get; set; } + public decimal TotalPrice { get; set; } + public string TaxCategory { get; set; } +} diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs new file mode 100644 index 0000000..833bdf0 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs @@ -0,0 +1,69 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; + +public class ReceiptConverter +{ + private readonly int _lineWidth; + private readonly int _bigFontLineWidth; + + public ReceiptConverter(int lineWidth = 42, int bigFontLineWidth = 21) + { + _lineWidth = lineWidth; + _bigFontLineWidth = bigFontLineWidth; + } + + public List ConvertToPrintCommands(InvoiceReceipt invoiceReceipt) + { + var commands = new List(); + + // Header - Company info + commands.Add(new PrintCommand(Center(invoiceReceipt.CompanyName, false))); + commands.Add(new PrintCommand(Center(invoiceReceipt.Address1, false))); + commands.Add(new PrintCommand(Center(invoiceReceipt.Address2, false))); + commands.Add(new PrintCommand(Center(invoiceReceipt.Phone, false))); + commands.Add(new PrintCommand("")); + commands.Add(new PrintCommand("")); + + // InvoiceReceipt info + string receiptLine = $"Rechnung Nr. {invoiceReceipt.ReceiptNumber}".PadRight(_lineWidth/2)+$"{invoiceReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth/2); + commands.Add(new PrintCommand(receiptLine,isBold:true)); + commands.Add(new PrintCommand($"Guests: {invoiceReceipt.Guests}")); + commands.Add(new PrintCommand("")); + + // Items + foreach (var item in invoiceReceipt.Items) + { + string quantityDesc = $"{item.Quantity}x {item.Description}"; + string prices = $"{item.UnitPrice:F2}"+$"{item.TotalPrice:F2}".PadLeft(7)+$" {item.TaxCategory}"; + + // Calculate spacing to align prices to the right + int spacesNeeded = _lineWidth - quantityDesc.Length - prices.Length; + if (spacesNeeded < 1) spacesNeeded = 1; + + string itemLine = quantityDesc + new string(' ', spacesNeeded) + prices; + commands.Add(new PrintCommand(itemLine)); + } + + commands.Add(new PrintCommand("")); + commands.Add(new PrintCommand("---------".PadLeft(_lineWidth))); + commands.Add(new PrintCommand("")); + + // Total + string totalLine = $"Summe: {invoiceReceipt.Total:F2} {invoiceReceipt.Currency}"; + commands.Add(new PrintCommand(Center(totalLine, true), true, true)); + + return commands; + } + + private string Center(string text, bool isBigFont) + { + int effectiveLineWidth = isBigFont ? _bigFontLineWidth : _lineWidth; + + if (string.IsNullOrEmpty(text) || text.Length >= effectiveLineWidth) + return text; + + int totalPadding = effectiveLineWidth - text.Length; + int leftPadding = totalPadding / 2; + + return new string(' ', leftPadding) + text; + } +} diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs index 085ae5e..e6c7c18 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs @@ -1,4 +1,5 @@ using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt; +using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems; namespace Inspectron.Epson.PrintServer.Printers.Utils; @@ -17,14 +18,17 @@ public class ReceiptConverterFactory : IReceiptConverterFactory }, EReceiptType.NextCourse => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20), EReceiptType.OrdersOverview => new OrderItemsReceiptConverter(48, 24), + EReceiptType.Invoice => new InvoiceReceiptConverter(48, 24), _ => throw new ArgumentException($"Unknown receipt type: {receiptType}") }; } + public enum EReceiptType { Receipt, WorkareaTicket, NextCourse, - OrdersOverview + OrdersOverview, + Invoice } }