diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs index d58c249..4db06c5 100644 --- a/EpsonTest/Program.cs +++ b/EpsonTest/Program.cs @@ -18,8 +18,8 @@ if (args.Length > 0) return; } - int pt = args.Length > 1 && args[1].Equals("epson", StringComparison.OrdinalIgnoreCase) ? 1 : 0; - Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {(pt == 0 ? "HTML" : "Epson")} printer...\n"); + int pt = ParsePrinterTargetArg(args.Length > 1 ? args[1] : "html"); + Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {GetPrinterTargetName(pt)} printer...\n"); await RunTest(rt, pt); Console.WriteLine("\nDone."); return; @@ -46,11 +46,12 @@ while (true) var printerTarget = ShowMenu("Select printer target:", new[] { "HTML Printer (local file)", - "Epson Printer (real hardware)" + "Epson Printer (real hardware)", + "POS895 (real hardware, via IPrinter adapter)" }); Console.Clear(); - Console.WriteLine($"Running {GetReceiptTypeName(receiptType)} on {(printerTarget == 0 ? "HTML" : "Epson")} printer...\n"); + Console.WriteLine($"Running {GetReceiptTypeName(receiptType)} on {GetPrinterTargetName(printerTarget)} printer...\n"); try { @@ -109,6 +110,21 @@ static int ShowMenu(string prompt, string[] options) } } +static string GetPrinterTargetName(int index) => index switch +{ + 0 => "HTML", + 1 => "Epson", + 2 => "POS895", + _ => "Unknown" +}; + +static int ParsePrinterTargetArg(string arg) => arg.ToLowerInvariant() switch +{ + "1" or "epson" => 1, + "2" or "pos895" or "pos" => 2, + _ => 0 +}; + static string GetReceiptTypeName(int index) => index switch { 0 => "KitchenReceipt", @@ -163,11 +179,19 @@ static async Task RunKitchenReceiptTest(int printerTarget) await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands); Console.WriteLine("Output written to: kitchen_test.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands); + } } static async Task RunFinalReceiptTest(int printerTarget) @@ -189,11 +213,20 @@ static async Task RunFinalReceiptTest(int printerTarget) logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); Console.WriteLine("Output written to: test.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands, + logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); + } } static async Task RunInvoiceReceiptTest(int printerTarget) @@ -215,11 +248,20 @@ static async Task RunInvoiceReceiptTest(int printerTarget) logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); Console.WriteLine("Output written to: invoice_test.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands, + logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); + } } static async Task RunBarReceiptTest(int printerTarget) @@ -239,11 +281,19 @@ static async Task RunBarReceiptTest(int printerTarget) await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands); Console.WriteLine("Output written to: bar_test.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands); + } } static async Task RunOrderItemsTest(int printerTarget) @@ -262,11 +312,19 @@ static async Task RunOrderItemsTest(int printerTarget) await TestHelpers.PrintCommandsToHtmlPrinterAsync(printer, printCommands); Console.WriteLine("Output written to: order_items.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands); + } } static async Task RunMoneyReturnReceiptTest(int printerTarget) @@ -288,9 +346,18 @@ static async Task RunMoneyReturnReceiptTest(int printerTarget) logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); Console.WriteLine("Output written to: money_return_test.html"); } - else + else if (printerTarget == 1) { var printer = await TestHelpers.CreateEpsonPrinterAsync(); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands); } + else + { + // Routes through PrinterWrapperFactory and the model adapter, the way + // EpsonPrintService does for a real job. The Epson branch above drives + // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores. + var printer = await TestHelpers.CreateEpsonPrinterAsync(); + await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands, + logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); + } } diff --git a/EpsonTest/TestHelpers.cs b/EpsonTest/TestHelpers.cs index 0209d9d..c8010b0 100644 --- a/EpsonTest/TestHelpers.cs +++ b/EpsonTest/TestHelpers.cs @@ -1,5 +1,7 @@ using System.Diagnostics; using Inspectron.Epson; +using Inspectron.Epson.PrintServer.Printers; +using Inspectron.Epson.PrintServer.PrintServices; using Inspectron.Epson.PrintServer.Printers.Utils; using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt; using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe; @@ -577,6 +579,48 @@ public static class TestHelpers await printer.CutAsync(); } + /// + /// Prints through the production IPrinter adapter chain instead of driving + /// EpsonPrinter directly: query the model byte, let PrinterWrapperFactory pick + /// the adapter from it, then print the logo and commands through that adapter. + /// This is what EpsonPrintService does for a real job, so it exercises the + /// model dispatch and the adapter's own ESC/POS dialect. + /// + /// Use this for the POS895. PrintCommandsToEpsonPrinterAsync above predates the + /// adapter layer and feeds with ESC d, which that firmware ignores - every cut + /// would slice through the last printed line. + /// + public static async Task PrintCommandsViaAdapterAsync( + EpsonPrinter printer, + IEnumerable commands, + string? logoPath = null) + { + byte? printerId = await printer.GetPrinterIdAsync(); + if (printerId is null) + { + throw new InvalidOperationException( + "Printer did not answer GS I 1, so no adapter can be chosen for it."); + } + + Console.WriteLine($"Printer reported model id 0x{printerId.Value:X2}"); + + IPrinter adapter = new PrinterWrapperFactory() + .CreatePrinterFromId(printerId.Value, printer); + + Console.WriteLine($"Using adapter {adapter.GetType().Name}"); + + await adapter.InitAsync(); + + if (logoPath is not null) + { + Console.WriteLine($"Printing logo {logoPath}"); + await adapter.PrintImageAsync(logoPath); + } + + await adapter.PrintAsync(commands.ToList()); + await adapter.Cut(); + } + public static async Task PrintKitchenCommandsToHtmlPrinterAsync( HtmlPrinter printer, IEnumerable commands) diff --git a/EpsonTest/test.html b/EpsonTest/test.html new file mode 100644 index 0000000..4b2f947 --- /dev/null +++ b/EpsonTest/test.html @@ -0,0 +1,173 @@ + + + + + + Epson Printer Output + + + +
+
Printed image
+ Klingler Gastro AG + Münzplatz 3 + CH-8001 Zürich + 043 321 22 22 + + +Debitorenrechnung + 14:58 16.12.2025 +Guests: 2 + +1x San Pellegrino 50cl 6.50 6.50 A +1x Panna 50cl 6.50 6.50 A +1x An item with really long 5.50 5.50 A + description that should wrap +2x Business Lunch Menu Seco 44.00 88.00 A + - Tomato Soup + - Grilled Salmon + - Tiramisu +2x Brunello di Montalcino 1 16.00 32.00 A +2x Espresso 5.50 11.00 A +1x Tip 10.50 10.50 B + + --------- + + Summe: 160.00 CHF + + 172.80 EUR + +Fine Dine -50.00 CHF + + Cash: 50.00 CHF + Card: 110.00 CHF + +MASTER 160.00 CHF + +MwSt % Brutto Netto MwSt +A: 8.1% 149.50 CHF 138.30 CHF 11.20 CHF +B: 0% 10.50 CHF 10.50 CHF 0.00 CHF + + Bedient von: Yves + Terminal: Hauptkasse ZH + Tisch: 12 + + + CHE-449.635.880 MWST + + *** Kundenbeleg *** + Buchung + TWINT +XXXXXXXXXXXXXXX1494 +11.11.2025 12:34:49 +Trm-Id: 31108834 +AID: A0000015749E +Trx. Seq-Cnt: 6127 +Trx. Ref-No: 99036644599 +Auth. Code: 0d3396 +Acq-Id: 2 +EFT CHF: 67.00 +Trinkgeld CHF: 6.70 +Total-EFT CHF: 73.70 +------------------------------------------------ + + *** Kundenbeleg *** + Buchung + MASTER +XXXXXXXXXXXXXXX2587 +11.11.2025 12:36:12 +Trm-Id: 31108834 +AID: A0000000041010 +Trx. Seq-Cnt: 6128 +Trx. Ref-No: 99036644600 +Auth. Code: 1a4b2c +Acq-Id: 1 +EFT CHF: 93.00 +Trinkgeld CHF: 0.00 +Total-EFT CHF: 93.00 +------------------------------------------------ + + Das Team bedankt sich herzlich für Ihren + Besuch. + Auf Wiedersehen. + + + +------------------------------------------------ +Unterschrift + +
+ + \ No newline at end of file diff --git a/EpsonTest/test_images/image_0001.png b/EpsonTest/test_images/image_0001.png new file mode 100644 index 0000000..ec48947 Binary files /dev/null and b/EpsonTest/test_images/image_0001.png differ