diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs index 1b7d6ca..e679b87 100644 --- a/EpsonTest/Program.cs +++ b/EpsonTest/Program.cs @@ -44,9 +44,9 @@ using System.Text.Json; // INVOICE RECEIPT - HTML PRINTER // ============================================================================ //var receipt = TestHelpers.BuildSampleInvoiceReceipt(); -////var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); -//var fileContent = File.ReadAllText("invoice.json"); -//var serializedReceipt = JsonSerializer.Deserialize(fileContent); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); +////var fileContent = File.ReadAllText("invoice.json"); +////var serializedReceipt = JsonSerializer.Deserialize(fileContent); //var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); //var printCommands = converter.Convert(serializedReceipt); diff --git a/EpsonTest/TestHelpers.cs b/EpsonTest/TestHelpers.cs index 2a2a25c..7a6829d 100644 --- a/EpsonTest/TestHelpers.cs +++ b/EpsonTest/TestHelpers.cs @@ -251,7 +251,7 @@ public static class TestHelpers receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem { Quantity = 1, - Description = "Granini Tomatensaft", + Description = "Granini Tomatensaft with something long to cause line wrapping more and more", UnitPrice = 5.50m, TotalPrice = 5.50m, TaxCategory = "A" @@ -312,7 +312,7 @@ public static class TestHelpers receipt.Gangs.Add(new Gang(1, "Gang")); receipt.Gangs.Add(new Gang(2, "Gang")); - receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi") + receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi with some addition to cause line wrapping") { Size = "XL", Modifications = new DishModifications @@ -321,10 +321,11 @@ public static class TestHelpers Added = new List { "Extra Ginger" } }, Comment = "No soy sauce", - GuestId = 1 + GuestId = 1, + Price = 123.45m }); - receipt.Gangs[0].Dishes.Add(new Dish(2, "Avocado Sashimi") { GuestId = 2 }); - receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi") { GuestId = 3 }); + receipt.Gangs[0].Dishes.Add(new Dish(2, "Avocado Sashimi with some addition to cause line wrapping") { GuestId = 2 }); + receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi with some addition to cause line wrapping") { GuestId = 3 }); 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") //{ diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs index c911935..0cce61d 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/InvoiceReceipt/ReceiptConverter.cs @@ -43,24 +43,7 @@ public class ReceiptConverter // 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)); - - // SubItems - if (item.SubItems != null) - { - foreach (var subItem in item.SubItems) - { - commands.Add(new PrintCommand($" - {subItem}")); - } - } + PrintItem(item, commands); } commands.Add(new PrintCommand("")); @@ -70,12 +53,96 @@ public class ReceiptConverter // Total string totalLine = $"Summe: {invoiceReceipt.Total:F2} {invoiceReceipt.Currency}"; commands.Add(new PrintCommand(Center(totalLine, true), true, true)); + commands.Add(new PrintCommand("")); commands.Add(new PrintCommand(Center($"Tisch: {invoiceReceipt.TableNumber}",false), false)); commands.Add(new PrintCommand(Center(invoiceReceipt.ThankYouMessage, false))); + commands.Add(new PrintCommand("")); + commands.Add(new PrintCommand(Center("Zwischenrechnung", false),isBold:true)); return commands; } + private void PrintItem(ReceiptItem item, List commands) + { + string quantityPrefix = $"{item.Quantity}x "; + string prices = $"{item.UnitPrice:F2}" + $"{item.TotalPrice:F2}".PadLeft(7) + $" {item.TaxCategory}"; + string fullLine = quantityPrefix + item.Description; + + int spacesNeeded = _lineWidth - fullLine.Length - prices.Length; + + if (spacesNeeded >= 1 || string.IsNullOrEmpty(item.Description)) + { + if (spacesNeeded < 1) spacesNeeded = 1; + commands.Add(new PrintCommand(fullLine + new string(' ', spacesNeeded) + prices)); + } + else + { + int descriptionAvailable = _lineWidth - quantityPrefix.Length - prices.Length - 1; + + if (descriptionAvailable <= 0) + { + commands.Add(new PrintCommand(fullLine)); + } + else + { + var words = item.Description.Split(' '); + var lines = new List(); + string currentLine = ""; + + foreach (var word in words) + { + if (currentLine.Length == 0) + { + currentLine = word; + } + else if (currentLine.Length + 1 + word.Length <= descriptionAvailable) + { + currentLine += " " + word; + } + else + { + lines.Add(currentLine); + currentLine = word; + } + } + + if (currentLine.Length > 0) + { + lines.Add(currentLine); + } + + // First line with prefix and right-aligned prices + string firstLineText = quantityPrefix + lines[0]; + int firstSpaces = _lineWidth - firstLineText.Length - prices.Length; + if (firstSpaces >= 1) + { + commands.Add(new PrintCommand(firstLineText + new string(' ', firstSpaces) + prices)); + } + else + { + commands.Add(new PrintCommand(firstLineText)); + commands.Add(new PrintCommand(prices.PadLeft(_lineWidth))); + } + + // Continuation lines indented to align with description + string continuationIndent = new string(' ', quantityPrefix.Length); + for (int i = 1; i < lines.Count; i++) + { + commands.Add(new PrintCommand(continuationIndent + lines[i])); + } + } + } + + // SubItems + if (item.SubItems != null) + { + foreach (var subItem in item.SubItems) + { + commands.Add(new PrintCommand($" - {subItem}")); + } + } + } + private string Center(string text, bool isBigFont) { int effectiveLineWidth = isBigFont ? _bigFontLineWidth : _lineWidth; diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverterKlinglers.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverterKlinglers.cs index 9cc510c..23f41da 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverterKlinglers.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverterKlinglers.cs @@ -99,6 +99,7 @@ public class KitchenReceiptConverterKlinglers if (!string.IsNullOrEmpty(dish.Size)) return false; if (!string.IsNullOrEmpty(dish.Comment)) return false; if (dish.Modifications != null && (dish.Modifications.Removed.Any() || dish.Modifications.Added.Any())) return false; + if (dish.Price != null) return false; return true; } @@ -117,11 +118,11 @@ public class KitchenReceiptConverterKlinglers int totalQuantity = group.Sum(d => d.Number); var guestIds = group .Where(d => d.GuestId.HasValue) - .Select(d => d.GuestId.Value) + .SelectMany(d => Enumerable.Repeat(d.GuestId!.Value, d.Number)) .OrderBy(id => id) .ToList(); - PrintDishLine($"{totalQuantity}x ", group.Key, null, commands); + PrintDishLine($"{totalQuantity}x ", group.Key, null, null, commands); if (guestIds.Any()) { @@ -133,7 +134,7 @@ public class KitchenReceiptConverterKlinglers // Print individual dishes (have size, modifications, or comment) foreach (var dish in individual) { - PrintDishLine($"{dish.Number}x ", dish.Name, dish.Size, commands); + PrintDishLine($"{dish.Number}x ", dish.Name, dish.Size, dish.Price, commands); if (dish.GuestId.HasValue) { @@ -160,67 +161,88 @@ public class KitchenReceiptConverterKlinglers } } - private void PrintDishLine(string quantityPrefix, string dishName, string? size, List commands) + private void PrintDishLine(string quantityPrefix, string dishName, string? size, decimal? price, List commands) { - string fullLine = quantityPrefix + dishName; + string? priceStr = price != null ? price.Value.ToString("0.00") : null; + string nameWithSize = dishName; if (!string.IsNullOrEmpty(size)) { - fullLine += $" ({size})"; + nameWithSize += $" ({size})"; } - if (fullLine.Length <= _lineWidth || string.IsNullOrEmpty(dishName)) + int firstLineNameWidth = _lineWidth - quantityPrefix.Length - 6; + if (priceStr != null) { - commands.Add(new PrintCommand(fullLine) { IsTall = true }); + firstLineNameWidth -= priceStr.Length + 1; } - else + int continuationNameWidth = _lineWidth - quantityPrefix.Length - 6; + + // Simple case: name fits on first line + if (nameWithSize.Length <= firstLineNameWidth || string.IsNullOrEmpty(dishName)) { - int availableWidth = _lineWidth - quantityPrefix.Length; - if (availableWidth <= 0) + string line = quantityPrefix + nameWithSize; + if (priceStr != null) { - commands.Add(new PrintCommand(fullLine) { IsTall = true }); + int padding = _lineWidth - line.Length - priceStr.Length; + line += new string(' ', Math.Max(1, padding)) + priceStr; + } + commands.Add(new PrintCommand(line) { IsTall = true }); + return; + } + + if (firstLineNameWidth <= 0) + { + string line = quantityPrefix + nameWithSize; + if (priceStr != null) line += " " + priceStr; + commands.Add(new PrintCommand(line) { IsTall = true }); + return; + } + + // Word wrap + var words = nameWithSize.Split(' '); + var lines = new List(); + string currentLine = ""; + int currentMaxWidth = firstLineNameWidth; + + foreach (var word in words) + { + if (currentLine.Length == 0) + { + currentLine = word; + } + else if (currentLine.Length + 1 + word.Length <= currentMaxWidth) + { + currentLine += " " + word; } else { - string nameWithSize = dishName; - if (!string.IsNullOrEmpty(size)) - { - nameWithSize += $" ({size})"; - } - var words = nameWithSize.Split(' '); - var lines = new List(); - string currentLine = ""; - - foreach (var word in words) - { - if (currentLine.Length == 0) - { - currentLine = word; - } - else if (currentLine.Length + 1 + word.Length <= availableWidth) - { - currentLine += " " + word; - } - else - { - lines.Add(currentLine); - currentLine = word; - } - } - - if (currentLine.Length > 0) - { - lines.Add(currentLine); - } - - commands.Add(new PrintCommand(quantityPrefix + lines[0]) { IsTall = true }); - string indent = new string(' ', quantityPrefix.Length); - for (int i = 1; i < lines.Count; i++) - { - commands.Add(new PrintCommand(indent + lines[i]) { IsTall = true }); - } + lines.Add(currentLine); + currentLine = word; + currentMaxWidth = continuationNameWidth; } } + + if (currentLine.Length > 0) + { + lines.Add(currentLine); + } + + // First line with prefix and optional right-aligned price + string firstLine = quantityPrefix + lines[0]; + if (priceStr != null) + { + int padding = _lineWidth - firstLine.Length - priceStr.Length; + firstLine += new string(' ', Math.Max(1, padding)) + priceStr; + } + commands.Add(new PrintCommand(firstLine) { IsTall = true }); + + // Continuation lines + string indent = new string(' ', quantityPrefix.Length); + for (int i = 1; i < lines.Count; i++) + { + commands.Add(new PrintCommand(indent + lines[i]) { IsTall = true }); + } } private string Center(string text, bool isBigFont) diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs index 131f752..bb7dd98 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs @@ -84,6 +84,7 @@ public DishModifications Modifications { get; set; } = new DishModifications(); public string? Comment { get; set; } + public decimal? Price { get; set; } } public class DishModifications