new receipt formats

This commit is contained in:
EugeneTes
2026-01-26 14:29:37 +01:00
parent 53cf40c5e3
commit 1125222cbe
13 changed files with 132 additions and 68 deletions

View File

@@ -43,19 +43,19 @@ using System.Text.Json;
// ============================================================================ // ============================================================================
// INVOICE RECEIPT - HTML PRINTER // INVOICE RECEIPT - HTML PRINTER
// ============================================================================ // ============================================================================
var receipt = TestHelpers.BuildSampleInvoiceReceipt(); //var receipt = TestHelpers.BuildSampleInvoiceReceipt();
var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); //var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });
var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); //var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
var printCommands = converter.Convert(serializedReceipt); //var printCommands = converter.Convert(serializedReceipt);
TestHelpers.PrintCommandsToConsole(printCommands); //TestHelpers.PrintCommandsToConsole(printCommands);
var printer = await TestHelpers.CreateHtmlPrinterAsync(); //var printer = await TestHelpers.CreateHtmlPrinterAsync();
await TestHelpers.PrintCommandsToHtmlPrinterAsync( //await TestHelpers.PrintCommandsToHtmlPrinterAsync(
printer, // printer,
printCommands, // printCommands,
logoPath: "ristorante-klinglers.ch-logo_white_bg.png"); // logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
// ============================================================================ // ============================================================================
@@ -112,17 +112,17 @@ await TestHelpers.PrintCommandsToHtmlPrinterAsync(
// ============================================================================ // ============================================================================
// KITCHEN RECEIPT - EPSON PRINTER // KITCHEN RECEIPT - EPSON PRINTER
// ============================================================================ // ============================================================================
//var receipt = TestHelpers.BuildSampleKitchenReceiptNextDish(); var receipt = TestHelpers.BuildSampleKitchenReceipt();
//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });
//var deserializedReceipt = JsonSerializer.Deserialize<KitchenReceipt>(serializedReceipt); var deserializedReceipt = JsonSerializer.Deserialize<KitchenReceipt>(serializedReceipt);
//var converter = new KitchenReceiptConverter(bigLineWidth: 18, lineWidth: 33); var converter = new KitchenReceiptConverter(bigLineWidth: 18, lineWidth: 33);
//var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); var printCommands = converter.ConvertToPrintCommands(deserializedReceipt);
//TestHelpers.PrintCommandsToConsole(printCommands); TestHelpers.PrintCommandsToConsole(printCommands);
//var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth:TestHelpers.KitchenPaperWidth); var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true); await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
// ============================================================================ // ============================================================================

View File

@@ -48,7 +48,7 @@ public static class TestHelpers
Address1 = "Münzplatz 3", Address1 = "Münzplatz 3",
Address2 = "CH-8001 Zürich", Address2 = "CH-8001 Zürich",
Phone = "043 321 22 22", Phone = "043 321 22 22",
ReceiptNumber = "1-81-202", ReceiptNumber = null,//"1-81-202",
DateTime = new DateTime(2025, 12, 16, 14, 58, 0), DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
Guests = 2, Guests = 2,
Total = 160.00m, Total = 160.00m,
@@ -211,11 +211,14 @@ public static class TestHelpers
Address1 = "Münzplatz 3", Address1 = "Münzplatz 3",
Address2 = "CH-8001 Zürich", Address2 = "CH-8001 Zürich",
Phone = "043 321 22 22", Phone = "043 321 22 22",
ReceiptNumber = "1-81-202", ReceiptNumber = null,//"1-81-202",
DateTime = new DateTime(2025, 12, 16, 14, 58, 0), DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
Guests = 2, Guests = 2,
Total = 160.00m, Total = 160.00m,
Currency = "CHF" Currency = "CHF",
TableNumber = "12",
ThankYouMessage = "Thank you!"
}; };
// Add items // Add items
@@ -308,9 +311,10 @@ public static class TestHelpers
Removed = new List<string> { "Wasabi" }, Removed = new List<string> { "Wasabi" },
Added = new List<string> { "Extra Ginger" } Added = new List<string> { "Extra Ginger" }
}, },
Comment = "No soy sauce" Comment = "No soy sauce",
GuestId = 1
}); });
receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl"){GuestId = 2});
receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki") receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
{ {
Modifications = new DishModifications Modifications = new DishModifications
@@ -318,20 +322,22 @@ public static class TestHelpers
Removed = new List<string> { "Onion" }, Removed = new List<string> { "Onion" },
Added = new List<string> { "Extra Sauce" } Added = new List<string> { "Extra Sauce" }
}, },
Comment = "Medium rare" Comment = "Medium rare",
GuestId = 3
}); });
receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
{ {
Modifications = new DishModifications Modifications = new DishModifications
{ {
Added = new List<string> { "Extra Lime" } Added = new List<string> { "Extra Lime" }
} },
GuestId = 4
}); });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi")); receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi") { GuestId = 2 });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki")); receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki") { GuestId = 3 });
receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco")); receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco") { GuestId = 4 });
return receipt; return receipt;
} }
@@ -346,37 +352,37 @@ public static class TestHelpers
WaiterName = "Mariano Amato", WaiterName = "Mariano Amato",
WaiterId = "32 (VK Restaurant)", WaiterId = "32 (VK Restaurant)",
TableNumber = "22", TableNumber = "22",
SpecialInstruction = "Next dish" SpecialInstruction = "Gang schicken"
}; };
receipt.Gangs.Add(new Gang(2, "Gang")); receipt.Gangs.Add(new Gang(2, "Gang"));
// to dishes in next dish
receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi") //receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")
{ //{
Modifications = new DishModifications // Modifications = new DishModifications
{ // {
Removed = new List<string> { "Wasabi" }, // Removed = new List<string> { "Wasabi" },
Added = new List<string> { "Extra Ginger" } // Added = new List<string> { "Extra Ginger" }
}, // },
Comment = "No soy sauce" // 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, "Baby Spinach Salad with Truffl"));
receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki") //receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
{ //{
Modifications = new DishModifications // Modifications = new DishModifications
{ // {
Removed = new List<string> { "Onion" }, // Removed = new List<string> { "Onion" },
Added = new List<string> { "Extra Sauce" } // Added = new List<string> { "Extra Sauce" }
}, // },
Comment = "Medium rare" // Comment = "Medium rare"
}); //});
receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco") //receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
{ //{
Modifications = new DishModifications // Modifications = new DishModifications
{ // {
Added = new List<string> { "Extra Lime" } // Added = new List<string> { "Extra Lime" }
} // }
}); //});
return receipt; return receipt;
} }
@@ -459,13 +465,23 @@ public static class TestHelpers
EpsonPrinter printer, EpsonPrinter printer,
IEnumerable<PrintCommand> commands, IEnumerable<PrintCommand> commands,
bool useDelay = true, bool useDelay = true,
int delayMs = 500) int delayMs = 200)
{ {
await printer.FeedLinesAsync(1); await printer.FeedLinesAsync(1);
await printer.SetCustomLineSpacing(22); await printer.SetCustomLineSpacing(22);
foreach (var command in commands) 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); await printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig, secondaryFont: false);
if (useDelay) await Task.Delay(delayMs); if (useDelay) await Task.Delay(delayMs);
@@ -479,7 +495,7 @@ public static class TestHelpers
if (useDelay) await Task.Delay(delayMs); if (useDelay) await Task.Delay(delayMs);
} }
await printer.FeedLinesAsync(5); await printer.FeedLinesAsync(10);
if (useDelay) await Task.Delay(delayMs * 5); if (useDelay) await Task.Delay(delayMs * 5);
await printer.CutAsync(); await printer.CutAsync();
} }
@@ -493,6 +509,11 @@ public static class TestHelpers
foreach (var command in commands) foreach (var command in commands)
{ {
if (command.IsCut)
{
await printer.CutAsync(false);
continue;
}
if (command.IsBig) if (command.IsBig)
await printer.SetFontSizeAsync(2, 1); await printer.SetFontSizeAsync(2, 1);
else else

View File

@@ -394,7 +394,7 @@ public class EpsonPrinter : IEpsonPrinter
await SendRawAsync(EpsonCommands.FeedLines((byte)lines)); await SendRawAsync(EpsonCommands.FeedLines((byte)lines));
} }
public async Task CutAsync() public async Task CutAsync(bool fullCut=true)
{ {
_logger?.LogInformation("Cutting paper"); _logger?.LogInformation("Cutting paper");
await SendRawAsync(EpsonCommands.CutPaperFull); await SendRawAsync(EpsonCommands.CutPaperFull);

View File

@@ -322,11 +322,17 @@ public class HtmlPrinter : IEpsonPrinter
} }
/// <inheritdoc /> /// <inheritdoc />
public Task CutAsync() public Task CutAsync(bool fullCut = true)
{ {
EnsureConnected(); EnsureConnected();
_logger?.LogInformation("HtmlPrinter: Cutting paper"); _logger?.LogInformation("HtmlPrinter: Cutting paper");
WriteHtmlFile(); if(fullCut)
WriteHtmlFile();
else
{
// add scissors icon for partial cut
_content.AppendLine("<div class=\"cut\"><span class=\"scissors\">✂️</span></div>");
}
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@@ -122,7 +122,7 @@ public interface IEpsonPrinter : IAsyncDisposable
/// <summary> /// <summary>
/// Cut the paper /// Cut the paper
/// </summary> /// </summary>
Task CutAsync(); Task CutAsync(bool fullCut=true);
/// <summary> /// <summary>
/// Load an image from a file path into the printer buffer /// Load an image from a file path into the printer buffer

View File

@@ -35,6 +35,12 @@ public class TM_U220IITranslated : IPrinter
{ {
foreach (var command in commands) foreach (var command in commands)
{ {
if (command.IsCut)
{
await _printer.CutAsync(false);
await Task.Delay(200);
continue;
}
await _printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig); await _printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig);
await Task.Delay(200); await Task.Delay(200);
await _printer.SetRedColor(command.IsRed); await _printer.SetRedColor(command.IsRed);

View File

@@ -6,7 +6,7 @@ public class FinalReceipt
public string Address1 { get; set; } public string Address1 { get; set; }
public string Address2 { get; set; } public string Address2 { get; set; }
public string Phone { get; set; } public string Phone { get; set; }
public string ReceiptNumber { get; set; } public string? ReceiptNumber { get; set; }
public DateTime DateTime { get; set; } public DateTime DateTime { get; set; }
public int Guests { get; set; } public int Guests { get; set; }
public List<FinalReceiptItem> Items { get; set; } = new List<FinalReceiptItem>(); public List<FinalReceiptItem> Items { get; set; } = new List<FinalReceiptItem>();

View File

@@ -27,7 +27,12 @@ public class ReceiptConverter
commands.Add(new PrintCommand("Debitorenrechnung")); commands.Add(new PrintCommand("Debitorenrechnung"));
} }
// FinalReceipt info // FinalReceipt info
string receiptLine = $"Rechnung Nr. {finalReceipt.ReceiptNumber}".PadRight(_lineWidth/2)+$"{finalReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth/2); string receiptLine = "";
if (finalReceipt.ReceiptNumber != null)
receiptLine += $"Rechnung Nr. {finalReceipt.ReceiptNumber}".PadRight(_lineWidth / 2);
else
receiptLine += $"".PadRight(_lineWidth / 2);
receiptLine += $"{finalReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth / 2);
commands.Add(new PrintCommand(receiptLine,isBold:true)); commands.Add(new PrintCommand(receiptLine,isBold:true));
commands.Add(new PrintCommand($"Guests: {finalReceipt.Guests}")); commands.Add(new PrintCommand($"Guests: {finalReceipt.Guests}"));
commands.Add(new PrintCommand("")); commands.Add(new PrintCommand(""));

View File

@@ -12,6 +12,8 @@ public class InvoiceReceipt
public List<ReceiptItem> Items { get; set; } = new List<ReceiptItem>(); public List<ReceiptItem> Items { get; set; } = new List<ReceiptItem>();
public decimal Total { get; set; } public decimal Total { get; set; }
public string Currency { get; set; } public string Currency { get; set; }
public string TableNumber { get; set; }
public string ThankYouMessage { get; set; }
} }
public class ReceiptItem public class ReceiptItem

View File

@@ -1,3 +1,5 @@
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt; namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
public class ReceiptConverter public class ReceiptConverter
@@ -24,7 +26,13 @@ public class ReceiptConverter
commands.Add(new PrintCommand("")); commands.Add(new PrintCommand(""));
// InvoiceReceipt info // InvoiceReceipt info
string receiptLine = $"Rechnung Nr. {invoiceReceipt.ReceiptNumber}".PadRight(_lineWidth/2)+$"{invoiceReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth/2); string receiptLine = "";
if (invoiceReceipt.ReceiptNumber != null)
receiptLine += $"Rechnung Nr. {invoiceReceipt.ReceiptNumber}".PadRight(_lineWidth / 2);
else
receiptLine += $"".PadRight(_lineWidth / 2);
receiptLine += $"{invoiceReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth / 2);
commands.Add(new PrintCommand(receiptLine,isBold:true)); commands.Add(new PrintCommand(receiptLine,isBold:true));
commands.Add(new PrintCommand($"Guests: {invoiceReceipt.Guests}")); commands.Add(new PrintCommand($"Guests: {invoiceReceipt.Guests}"));
commands.Add(new PrintCommand("")); commands.Add(new PrintCommand(""));
@@ -59,6 +67,8 @@ public class ReceiptConverter
// Total // Total
string totalLine = $"Summe: {invoiceReceipt.Total:F2} {invoiceReceipt.Currency}"; string totalLine = $"Summe: {invoiceReceipt.Total:F2} {invoiceReceipt.Currency}";
commands.Add(new PrintCommand(Center(totalLine, true), true, true)); commands.Add(new PrintCommand(Center(totalLine, true), true, true));
commands.Add(new PrintCommand(Center($"Tisch: {invoiceReceipt.TableNumber}",false), false));
commands.Add(new PrintCommand(Center(invoiceReceipt.ThankYouMessage, false)));
return commands; return commands;
} }

View File

@@ -46,7 +46,7 @@ public class KitchenReceiptConverter
// Gangs // Gangs
foreach (Gang gang in kitchenReceipt.Gangs) foreach (Gang gang in kitchenReceipt.Gangs)
{ {
@@ -55,6 +55,13 @@ public class KitchenReceiptConverter
{ {
PrintDish(dish, commands); PrintDish(dish, commands);
} }
if (gang != kitchenReceipt.Gangs.Last())
{
commands.Add(new PrintCommand(""){IsCut = true});
commands.Add(new PrintCommand(""));
commands.Add(new PrintCommand(""));
}
} }
if (kitchenReceipt.Gangs.Count > 0) if (kitchenReceipt.Gangs.Count > 0)
@@ -96,7 +103,11 @@ public class KitchenReceiptConverter
private static void PrintDish(Dish dish, List<PrintCommand> commands) private static void PrintDish(Dish dish, List<PrintCommand> commands)
{ {
string dishLine = $"{dish.Number}x {dish.Name}"; string dishLine = $"{dish.Number}x {dish.Name}";
commands.Add(new PrintCommand(dishLine){IsTall = true}); string guestInfo = dish.GuestId.HasValue ? $"{dish.GuestId.Value} " : "";
//todo: add word wrap if guest id is present and guestInfo + dish line too long. add spaces in front of continued lines to align with dish name start position
commands.Add(new PrintCommand(guestInfo+dishLine) {IsTall = true});
// Modifications // Modifications
if (dish.Modifications != null && (dish.Modifications.Removed.Any() || dish.Modifications.Added.Any())) if (dish.Modifications != null && (dish.Modifications.Removed.Any() || dish.Modifications.Added.Any()))
{ {

View File

@@ -80,6 +80,8 @@
public Dish(){} public Dish(){}
public int? GuestId { get; set; }
public Dish(int number, string name) public Dish(int number, string name)
{ {
Number = number; Number = number;

View File

@@ -8,6 +8,7 @@ public class PrintCommand
public bool IsBold { get; set; } public bool IsBold { get; set; }
public bool IsRed { get; set; } public bool IsRed { get; set; }
public int? SetLineSpacing { get; set; }=null; public int? SetLineSpacing { get; set; }=null;
public bool IsCut { get; set; }
public PrintCommand(string text, bool isBig = false, bool isBold = false) public PrintCommand(string text, bool isBig = false, bool isBold = false)
{ {
Text = text; Text = text;