diff --git a/ConfigurationPannel/Services/PrintServerHostedService.cs b/ConfigurationPannel/Services/PrintServerHostedService.cs index 12ff87c..7848941 100644 --- a/ConfigurationPannel/Services/PrintServerHostedService.cs +++ b/ConfigurationPannel/Services/PrintServerHostedService.cs @@ -42,7 +42,7 @@ public class PrintServerHostedService : IHostedService _kernel.Bind().To(); _kernel.Bind().ToConstant(_logger); _kernel.Bind().ToConstant(config); - _kernel.Bind().To().InSingletonScope(); + _kernel.Bind().To().InSingletonScope(); _kernel.Bind().ToConstant(config); _kernel.Bind().ToSelf().InSingletonScope(); diff --git a/EpsonPrintService/PrinterDiscoveryBackgroundTask.cs b/EpsonPrintService/PrinterDiscoveryBackgroundTask.cs index 9ba362d..69e41f4 100644 --- a/EpsonPrintService/PrinterDiscoveryBackgroundTask.cs +++ b/EpsonPrintService/PrinterDiscoveryBackgroundTask.cs @@ -1,4 +1,5 @@ using Inspectron.Epson; +using Inspectron.Epson.PrintServer.ConfigurationSources; using Microsoft.Extensions.Logging; namespace EpsonPrintService; @@ -20,15 +21,13 @@ public class PrinterDiscoveryBackgroundTask public PrinterDiscoveryBackgroundTask( IDiscoveryService discoveryService, IDiscoveredPrintersReceiver receiver, - ILogger logger, - TimeSpan? interval = null, - TimeSpan? discoveryTimeout = null) + ILogger logger) { _discoveryService = discoveryService; _receiver = receiver; _logger = logger; - _interval = interval ?? TimeSpan.FromSeconds(30); - _discoveryTimeout = discoveryTimeout ?? TimeSpan.FromSeconds(3); + _interval = TimeSpan.FromSeconds(30); + _discoveryTimeout = TimeSpan.FromSeconds(3); } /// @@ -68,6 +67,11 @@ public class PrinterDiscoveryBackgroundTask try { var printers = await _discoveryService.DiscoverPrintersAsync(_discoveryTimeout); + printers.Add(new DiscoveredPrinter() + { + IPAddress = "127.0.0.1", + ModelName = "TM-T30III", + }); var currentIps = printers.Select(p => p.IPAddress).ToHashSet(); if (HasConfigurationChanged(currentIps)) diff --git a/EpsonPrintService/Program.cs b/EpsonPrintService/Program.cs index 562a9c9..92e8685 100644 --- a/EpsonPrintService/Program.cs +++ b/EpsonPrintService/Program.cs @@ -23,6 +23,9 @@ kernel.Bind().To().InSingletonScope(); kernel.Bind().ToConstant(config); +//kernel.Bind().ToMethod(sp=>new HtmlPrinterFactory("TM-U220II.html", paperWidth: 258,type:0x0d, logger:sp.Kernel.Get())); +//kernel.Bind().ToMethod(sp=>new HtmlPrinterFactory("TM-T30III.html",logger:sp.Kernel.Get())); +kernel.Bind().To(); kernel.Bind().To().InSingletonScope(); kernel.Bind().To(); @@ -35,10 +38,10 @@ kernel.Bind().ToMethod(ctx => return loggerFactory.CreateLogger("EpsonPrintService"); }); kernel.Bind().ToConstant(config); -kernel.Bind().To().InSingletonScope(); +kernel.Bind().To().InSingletonScope(); kernel.Bind().To(); kernel.Bind().ToSelf().InSingletonScope(); -kernel.Bind().To().InSingletonScope(); +kernel.Bind().To().InSingletonScope(); kernel.Bind().ToSelf().InSingletonScope(); var printLoop = kernel.Get(); diff --git a/EpsonPrintService/config.json b/EpsonPrintService/config.json index 546cb75..b6ee866 100644 --- a/EpsonPrintService/config.json +++ b/EpsonPrintService/config.json @@ -1,5 +1,6 @@ { - "GroupId": "67e534f8e86e816689323023", - "RestaurantId": "63e37295bd6f26dbd36164c0", + "GroupId": "64a3d9f0876bc5d1704bce43", + "RestaurantId": "64a3d9f0876bc5d1704bce43", + "ApiKey": "LBOACMlvFEgDbZqt24uW0LjiFv0LKU5DT94g0JDoBnI=", "PrinterConfigurations": {} } \ No newline at end of file diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs index 04d2c17..575fb3d 100644 --- a/EpsonTest/Program.cs +++ b/EpsonTest/Program.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.PixelFormats; using System.Text; using System.Text.Json; using System.Xml.Linq; +using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems; using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt; @@ -58,159 +59,178 @@ using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.Fin //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." -}; +//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.", +// TerminalReceipt = 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" +// } +//}; -// Add items -receipt.Items.Add(new ReceiptItem -{ - Quantity = 1, - Description = "San Pellegrino 50cl", - UnitPrice = 6.50m, - TotalPrice = 6.50m, - TaxCategory = "A" -}); +//// 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 = "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 = 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 = "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 = "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 = 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" -}); +//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" -}); +//// 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" -}); +//receipt.TaxBreakdown.Add(new TaxInfo +//{ +// Category = "B", +// Rate = 0m, +// Gross = 10.50m, +// Net = 10.50m, +// TaxAmount = 0.00m, +// Currency = "CHF" +//}); - -// Convert to print commands -var converter = new ReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); -var printCommands = converter.ConvertToPrintCommands(receipt); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); +//var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); +//// Convert to print commands +//var converter = new ReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +//var printCommands = converter.ConvertToPrintCommands(deserializedReceipt); -// Print the commands -Console.WriteLine("=== PRINT COMMANDS ===\n"); -var printer = new HtmlPrinter(@".\test.html", paperWidth: 384); -await printer.ConnectAsync(""); -await printer.SetAbsolutePrintPosition(97); -await printer.LoadImageAsync("ristorante-klinglers.ch-logo_white_bg.png", 390); -await printer.SetAbsolutePrintPosition(0); -await printer.PrintLoadedImage(); -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] "; +//// 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] "; - Console.WriteLine($"{attributes}{command.Text}"); +// Console.WriteLine($"{attributes}{command.Text}"); - if (command.IsBig) - { - await printer.SetFontSizeAsync(2, 1); - } - else - { - await printer.SetFontSizeAsync(1, 1); - } - //await Task.Delay(200); +// 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.SetEmphasized(command.IsBold); +// //await Task.Delay(200); - await printer.PrintTextAsync(command.Text + "\n"); - //await Task.Delay(200); +// await printer.PrintTextAsync(command.Text + "\n"); +// //await Task.Delay(200); -} +//} //var receipt = new KitchenReceipt @@ -246,10 +266,11 @@ foreach (var command in printCommands) //// Add additional info -//receipt.AdditionalInfo.Add("1 x Amuse Bouche"); -//KitchenReceiptConverter converter = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth:33); -//var printCommands = converter.ConvertToPrintCommands(receipt); +//var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true }); +//var deserializedReceipt = JsonSerializer.Deserialize(serializedReceipt); +//KitchenReceiptConverter 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); @@ -291,8 +312,83 @@ foreach (var command in printCommands) //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); + +//} @@ -417,7 +513,10 @@ foreach (var command in printCommands) //await Task.Delay(2000); //await printer.PrintBuffer(); -//await printer.SendRawCommandAsync([0x1b,0x21,0x10+0x21]); +//var printer = new EpsonPrinter(); +//await printer.ConnectAsync("127.0.0.1", 8888); +//await printer.InitAsync(); + //await printer.PrintTextAsync("Hello!"); //await printer.FeedLinesAsync(5); diff --git a/Inspectron.Epson/HtmlPrinter.cs b/Inspectron.Epson/HtmlPrinter.cs index 1aa7413..7b28de8 100644 --- a/Inspectron.Epson/HtmlPrinter.cs +++ b/Inspectron.Epson/HtmlPrinter.cs @@ -4,6 +4,7 @@ using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using System.Text; +using Inspectron.Epson.PrintServer.PrintServices; namespace Inspectron.Epson; @@ -14,6 +15,7 @@ namespace Inspectron.Epson; public class HtmlPrinter : IEpsonPrinter { private readonly ILogger? _logger; + private readonly byte _id; private readonly string _outputPath; private readonly int _paperWidth; private readonly string _imageDirectory; @@ -60,11 +62,12 @@ public class HtmlPrinter : IEpsonPrinter /// Path to the output HTML file /// Paper width in pixels (default 384 for 80mm thermal printer) /// Optional logger for diagnostic output - public HtmlPrinter(string outputPath, int paperWidth = 384, ILogger? logger = null) + public HtmlPrinter(string outputPath, int paperWidth = 384, ILogger? logger = null, byte id=0x01) { _outputPath = outputPath; _paperWidth = paperWidth; _logger = logger; + _id = id; // Create image directory next to HTML file var directory = Path.GetDirectoryName(outputPath) ?? "."; @@ -174,8 +177,7 @@ public class HtmlPrinter : IEpsonPrinter /// public Task GetPrinterIdAsync() { - _logger?.LogDebug("HtmlPrinter: Returning mock printer ID (0x01 = TM-T30III)"); - return Task.FromResult(0x01); + return Task.FromResult(_id); } /// @@ -320,9 +322,6 @@ public class HtmlPrinter : IEpsonPrinter { EnsureConnected(); _logger?.LogInformation("HtmlPrinter: Cutting paper"); - - _content.AppendLine("
"); - WriteHtmlFile(); return Task.CompletedTask; } @@ -493,7 +492,7 @@ public class HtmlPrinter : IEpsonPrinter if (_isBiggerFontTM220) { - effectiveHeightMultiplier *= 2; + effectiveWidthMultiplier *= 2; } int fontSize = baseHeight * effectiveHeightMultiplier; diff --git a/Inspectron.Epson/PrintServer/ConfigurationSources/EpsonPrintServiceConfiguration.cs b/Inspectron.Epson/PrintServer/ConfigurationSources/EpsonPrintServiceConfiguration.cs index 129d8d9..0935696 100644 --- a/Inspectron.Epson/PrintServer/ConfigurationSources/EpsonPrintServiceConfiguration.cs +++ b/Inspectron.Epson/PrintServer/ConfigurationSources/EpsonPrintServiceConfiguration.cs @@ -6,6 +6,7 @@ public class EpsonPrintServiceConfiguration: IPrinterConfigurationSource, IAssig { public string GroupId { get; set; } public string RestaurantId { get; set; } + public string ApiKey { get; set; } public Dictionary PrinterConfigurations { get; set; } public PrinterConfiguration GetConfiguration(string printerAddress) diff --git a/EpsonPrintService/ConsoleDiscoveredPrintersReceiver.cs b/Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/ConsoleDiscoveredPrintersReceiver.cs similarity index 100% rename from EpsonPrintService/ConsoleDiscoveredPrintersReceiver.cs rename to Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/ConsoleDiscoveredPrintersReceiver.cs diff --git a/EpsonPrintService/IDiscoveredPrintersReceiver.cs b/Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/IDiscoveredPrintersReceiver.cs similarity index 100% rename from EpsonPrintService/IDiscoveredPrintersReceiver.cs rename to Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/IDiscoveredPrintersReceiver.cs diff --git a/Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/JamesDiscoveredPrintersReceiver.cs b/Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/JamesDiscoveredPrintersReceiver.cs new file mode 100644 index 0000000..9e8b711 --- /dev/null +++ b/Inspectron.Epson/PrintServer/DiscoveredPrintersReceiver/JamesDiscoveredPrintersReceiver.cs @@ -0,0 +1,55 @@ +using Inspectron.Epson; +using Inspectron.Epson.PrintServer.ConfigurationSources; +using System.Net.Http.Json; + +namespace EpsonPrintService; + +public class JamesDiscoveredPrintersReceiver: IDiscoveredPrintersReceiver +{ + private readonly EpsonPrintServiceConfiguration _configuration; + private readonly HttpClient _httpClient; + + public JamesDiscoveredPrintersReceiver(EpsonPrintServiceConfiguration configuration, HttpClient httpClient) + { + _configuration = configuration; + _httpClient = httpClient; + } + + public async Task OnPrintersDiscoveredAsync(IReadOnlyList printers) + { + var apiKey = _configuration.ApiKey; + + var request = new DiscoveredPrintersRequest + { + Printers = printers.Select(p => new DiscoveredPrinterDto + { + PrinterId = p.IPAddress, + Name = p.IPAddress, + Address = p.IPAddress, + Model = p.ModelName, + IsMain = false + }).ToList() + }; + + using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://api.dev.gastrojames.ch/api/printerServer/discovered-printers"); + requestMessage.Headers.Add("X-Printer-Server-Key", apiKey); + requestMessage.Content = JsonContent.Create(request); + + var response = await _httpClient.SendAsync(requestMessage); + response.EnsureSuccessStatusCode(); + } + + private class DiscoveredPrintersRequest + { + public List Printers { get; set; } = new(); + } + + private class DiscoveredPrinterDto + { + public string PrinterId { get; set; } = ""; + public string Name { get; set; } = ""; + public string Address { get; set; } = ""; + public string Model { get; set; } = ""; + public bool IsMain { get; set; } + } +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs b/Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs index 25e799b..da35bc8 100644 --- a/Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs +++ b/Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs @@ -20,7 +20,7 @@ public class SignalRPrintJobSource: IPrintJobSource _logger = logger; _connection = new HubConnectionBuilder() - .WithUrl("https://api.stage.gastrojames.ch/hubs/internal?access_token=https://api.stage.gastrojames.ch/hubs/internal") + .WithUrl("https://api.dev.gastrojames.ch/hubs/printer-servers") .WithAutomaticReconnect(new InfiniteRetryPolicy()) .Build(); @@ -92,8 +92,8 @@ public class SignalRPrintJobSource: IPrintJobSource _logger.LogInformation("Received print job for working area: {PrintJob}", JsonSerializer.Serialize(args)); _printJobChannel.Writer.TryWrite(new PrintJob { - AreaId = args.WorkingAreaId, - Document = args.Content, + IP = args.PrinterIp, + Document = args, }); } @@ -104,8 +104,15 @@ public class SignalRPrintJobSource: IPrintJobSource public class PrintJobFromSignalR { - [JsonPropertyName("workingAreaId")] - public string WorkingAreaId { get; set; } + [JsonPropertyName("printerIp")] + public string PrinterIp { get; set; } + + [JsonPropertyName("logoUrl")] + public string? LogoUrl { get; set; } + + [JsonPropertyName("receiptType")] + public int ReceiptType { get; set; } + [JsonPropertyName("content")] public string Content { get; set; } } diff --git a/Inspectron.Epson/PrintServer/PrintLoop.cs b/Inspectron.Epson/PrintServer/PrintLoop.cs index 40e08b4..483a7ed 100644 --- a/Inspectron.Epson/PrintServer/PrintLoop.cs +++ b/Inspectron.Epson/PrintServer/PrintLoop.cs @@ -34,14 +34,8 @@ public class PrintLoop while (!_cancellationSource!.Token.IsCancellationRequested) { var job = await _jobSource.GetNextJobAsync(_cancellationToken); - var assigned = _assignedPrinterRepository.GetAssignedPrinter(job.AreaId); - if (assigned == null) - { - _logger.LogWarning("Received print job for unassigned area {AreaId}, skipping", job.AreaId); - continue; - } - - _printServer.SubmitJob(assigned, job); + + _printServer.SubmitJob(job.IP, job); } } diff --git a/Inspectron.Epson/PrintServer/PrintServices/EpsonPrintService.cs b/Inspectron.Epson/PrintServer/PrintServices/EpsonPrintService.cs index b569a77..b99c65a 100644 --- a/Inspectron.Epson/PrintServer/PrintServices/EpsonPrintService.cs +++ b/Inspectron.Epson/PrintServer/PrintServices/EpsonPrintService.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using System.Reflection; +using Inspectron.Epson.PrintServer.Printers; namespace Inspectron.Epson.PrintServer.PrintServices; @@ -7,12 +8,14 @@ public class EpsonPrintService: IPrintService { private readonly ILogger _logger; private readonly IPrinterFactory _printerFactory; + private readonly IWrapperPrinterFactory _wrapperPrinterFactory; private readonly IPrinterConfigurationSource _printerConfigurationSource; - public EpsonPrintService(ILogger logger, IPrinterFactory printerFactory, IPrinterConfigurationSource printerConfigurationSource) + public EpsonPrintService(ILogger logger, IPrinterFactory printerFactory, IWrapperPrinterFactory wrapperPrinterFactory, IPrinterConfigurationSource printerConfigurationSource) { _logger = logger; _printerFactory = printerFactory; + _wrapperPrinterFactory = wrapperPrinterFactory; _printerConfigurationSource = printerConfigurationSource; } @@ -21,7 +24,7 @@ public class EpsonPrintService: IPrintService try { var configuration = _printerConfigurationSource.GetConfiguration(printerIp); - await using var epsonPrinter = new EpsonPrinter(_logger); + await using var epsonPrinter = _printerFactory.CreatePrinter(); string address; int port = 9100; var printerAddress = configuration.Address; @@ -45,19 +48,46 @@ public class EpsonPrintService: IPrintService { throw new InvalidOperationException("Printer is offline or out of paper."); } - - var printerAdapter = _printerFactory.CreatePrinterFromId(printerId.Value, epsonPrinter); + var printerAdapter = _wrapperPrinterFactory.CreatePrinterFromId(printerId.Value, epsonPrinter); await printerAdapter.InitAsync(); - if (configuration.LogoFilename != null) + if (!string.IsNullOrEmpty(job.Document.LogoUrl)) { - await printerAdapter.PrintImageAsync(configuration.LogoFilename); + // Download logo image + var logoFileName = Path.GetFileName(new Uri(job.Document.LogoUrl).LocalPath); + var logoCachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logos"); + + // Ensure logos cache directory exists + if (!Directory.Exists(logoCachePath)) + { + Directory.CreateDirectory(logoCachePath); + } + + var cachedLogoPath = Path.Combine(logoCachePath, logoFileName); + + // Download only if not already cached + if (!File.Exists(cachedLogoPath)) + { + using var httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromSeconds(10); + + var logoData = await httpClient.GetByteArrayAsync(job.Document.LogoUrl); + await File.WriteAllBytesAsync(cachedLogoPath, logoData); + + _logger.LogInformation("Downloaded logo {LogoFileName} from {LogoUrl}", logoFileName, job.Document.LogoUrl); + } + else + { + _logger.LogDebug("Using cached logo {LogoFileName}", logoFileName); + } + + await printerAdapter.PrintImageAsync(cachedLogoPath); } await printerAdapter.SetFontSizeAsync(configuration.FontSize); - await printerAdapter.PrintTextAsync(job.Document); + await printerAdapter.PrintTextAsync(job.Document.Content); await Task.Delay(200); status = await epsonPrinter.GetPrinterStatusAsync(); if (!status.IsOnline) diff --git a/Inspectron.Epson/PrintServer/PrintServices/IPrinterFactory.cs b/Inspectron.Epson/PrintServer/PrintServices/IPrinterFactory.cs deleted file mode 100644 index 8e62de6..0000000 --- a/Inspectron.Epson/PrintServer/PrintServices/IPrinterFactory.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Inspectron.Epson.PrintServer.PrintServices; - -public interface IPrinterFactory -{ - IPrinter CreatePrinterFromId(byte printerId, EpsonPrinter epsonPrinter); -} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/PrintServices/IWrapperPrinterFactory.cs b/Inspectron.Epson/PrintServer/PrintServices/IWrapperPrinterFactory.cs new file mode 100644 index 0000000..47f914e --- /dev/null +++ b/Inspectron.Epson/PrintServer/PrintServices/IWrapperPrinterFactory.cs @@ -0,0 +1,6 @@ +namespace Inspectron.Epson.PrintServer.PrintServices; + +public interface IWrapperPrinterFactory +{ + IPrinter CreatePrinterFromId(byte printerId, IEpsonPrinter epsonPrinter); +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/EpsonPrinterFactory.cs b/Inspectron.Epson/PrintServer/Printers/EpsonPrinterFactory.cs new file mode 100644 index 0000000..dd6b572 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/EpsonPrinterFactory.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.Logging; + +namespace Inspectron.Epson.PrintServer.Printers; + +public class EpsonPrinterFactory:IPrinterFactory +{ + private readonly ILogger _logger; + + public EpsonPrinterFactory(ILogger logger) + { + _logger = logger; + } + + public IEpsonPrinter CreatePrinter() + { + return new EpsonPrinter(_logger); + } +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/HtmlPrinterFactory.cs b/Inspectron.Epson/PrintServer/Printers/HtmlPrinterFactory.cs new file mode 100644 index 0000000..63db954 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/HtmlPrinterFactory.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.Logging; + +namespace Inspectron.Epson.PrintServer.Printers; + +public class HtmlPrinterFactory(string filename,int paperWidth=384, byte type=0x1, ILogger logger=null) : IPrinterFactory +{ + + public IEpsonPrinter CreatePrinter() + { + return new HtmlPrinter(filename,paperWidth: paperWidth, id:type); + } +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/IPrinterFactory.cs b/Inspectron.Epson/PrintServer/Printers/IPrinterFactory.cs new file mode 100644 index 0000000..dbb46dc --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/IPrinterFactory.cs @@ -0,0 +1,6 @@ +namespace Inspectron.Epson.PrintServer.Printers; + +public interface IPrinterFactory +{ + IEpsonPrinter CreatePrinter(); +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/PrinterFactory.cs b/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs similarity index 79% rename from Inspectron.Epson/PrintServer/Printers/PrinterFactory.cs rename to Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs index 5d8c1e9..62aa7a4 100644 --- a/Inspectron.Epson/PrintServer/Printers/PrinterFactory.cs +++ b/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs @@ -2,9 +2,9 @@ namespace Inspectron.Epson.PrintServer.Printers; -public class PrinterFactory:IPrinterFactory +public class PrinterWrapperFactory:IWrapperPrinterFactory { - public IPrinter CreatePrinterFromId(byte printerId, EpsonPrinter epsonPrinter) + public IPrinter CreatePrinterFromId(byte printerId, IEpsonPrinter epsonPrinter) { switch (printerId) { diff --git a/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs b/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs index 772ad55..aa3bd73 100644 --- a/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs +++ b/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs @@ -8,9 +8,9 @@ namespace Inspectron.Epson.PrintServer.Printers; public class TM_T30IIITranslated:IPrinter { - private readonly EpsonPrinter _printer; + private readonly IEpsonPrinter _printer; - public TM_T30IIITranslated(EpsonPrinter printer) + public TM_T30IIITranslated(IEpsonPrinter printer) { _printer = printer; } diff --git a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs index 0887143..34259c5 100644 --- a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs +++ b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs @@ -1,14 +1,16 @@ using Inspectron.Epson.PrintServer.Printers.Utils; +using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; using Inspectron.Epson.PrintServer.PrintServices; using System.Reflection; +using System.Text.Json; namespace Inspectron.Epson.PrintServer.Printers; public class TM_U220IITranslated:IPrinter { - private readonly EpsonPrinter _printer; + private readonly IEpsonPrinter _printer; - public TM_U220IITranslated(EpsonPrinter printer) + public TM_U220IITranslated(IEpsonPrinter printer) { _printer = printer; } @@ -34,11 +36,10 @@ public class TM_U220IITranslated:IPrinter public async Task PrintTextAsync(string text) { - ReceiptTranslator translator = new ReceiptTranslator(); - var ast = translator.ParseReceipt(text); - KitchenReceiptPrinter printer = new KitchenReceiptPrinter(lineWidth:33,21); - var commands = printer.ConvertToCommands((TranslatedKitchenReceipt)ast); - foreach (KitchenPrintCommand command in commands) + var deserializedReceipt = JsonSerializer.Deserialize(text); + KitchenReceiptConverter translator = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth: 33); + var commands = translator.ConvertToPrintCommands(deserializedReceipt); + foreach (var command in commands) { await _printer.SetBiggerFontTM220(command.IsBig); await Task.Delay(200); @@ -49,12 +50,7 @@ public class TM_U220IITranslated:IPrinter await _printer.PrintTextAsync(command.Text + "\n"); await Task.Delay(200); } - //await _printer.PrintTextAsync(text); - //var lines = text.Split('\n').Length; - //for (int i = 0; i < lines; i++) - //{ - // await Task.Delay(200); - //} + await _printer.FeedLinesAsync(10); await Task.Delay(1000); } diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs index 4926a88..98dbefa 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs @@ -24,6 +24,7 @@ public class FinalReceipt public string ThankYouMessage { get; set; } public string GoodbyeMessageLine1 { get; set; } public string GoodbyeMessageLine2 { get; set; } + public PaymentTerminalReceipt TerminalReceipt { get; set; } } public class ReceiptItem @@ -43,4 +44,23 @@ public class TaxInfo public decimal Net { get; set; } public decimal TaxAmount { get; set; } public string Currency { get; set; } +} + +public class PaymentTerminalReceipt +{ + public string ReceiptType { get; set; } // e.g., "*** Kundenbeleg ***" + public string BookingType { get; set; } // e.g., "Buchung" + public string PaymentSystem { get; set; } // e.g., "TWINT" + public string TransactionNumber { get; set; } + public DateTime TransactionDateTime { get; set; } + public string TerminalId { get; set; } + public string AID { get; set; } + public string TransactionSeqCount { get; set; } + public string TransactionRefNo { get; set; } + public string AuthCode { get; set; } + public string AcquirerId { get; set; } + public decimal EftAmount { get; set; } + public decimal TipAmount { get; set; } + public decimal TotalEftAmount { get; set; } + public string Currency { get; set; } } \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs index ab917ec..b02686c 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs @@ -83,9 +83,6 @@ public class ReceiptConverter commands.Add(new PrintCommand("")); // Footer info - //commands.Add(new PrintCommand(Center($"Bedient von: {finalReceipt.WaiterName}", false))); - //commands.Add(new PrintCommand(Center($"Terminal: {finalReceipt.Terminal}", false))); - //commands.Add(new PrintCommand(Center($"Tisch: {finalReceipt.TableNumber}", false))); commands.Add(new PrintCommand($"Bedient von:".PadLeft(_lineWidth / 2) + $" {finalReceipt.WaiterName}")); commands.Add(new PrintCommand($"Terminal:".PadLeft(_lineWidth / 2) + $" {finalReceipt.Terminal}")); commands.Add(new PrintCommand($"Tisch:".PadLeft(_lineWidth / 2)+$" {finalReceipt.TableNumber}")); @@ -94,6 +91,33 @@ public class ReceiptConverter // VAT number commands.Add(new PrintCommand(Center(finalReceipt.VatNumber, false))); + commands.Add(new PrintCommand("")); + + // Payment Terminal Receipt + if (finalReceipt.TerminalReceipt != null) + { + var terminal = finalReceipt.TerminalReceipt; + + commands.Add(new PrintCommand(Center(terminal.ReceiptType, false))); + commands.Add(new PrintCommand(Center(terminal.BookingType, false))); + commands.Add(new PrintCommand(Center(terminal.PaymentSystem, false))); + commands.Add(new PrintCommand(terminal.TransactionNumber)); + commands.Add(new PrintCommand($"{terminal.TransactionDateTime:dd.MM.yyyy}".PadRight(_lineWidth/2) + $"{terminal.TransactionDateTime:HH:mm:ss}".PadLeft(_lineWidth/2))); + + commands.Add(new PrintCommand($"Trm-Id:".PadRight(_lineWidth/2) + $"{terminal.TerminalId}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"AID:".PadRight(_lineWidth/2) + $"{terminal.AID}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Trx. Seq-Cnt:".PadRight(_lineWidth/2) + $"{terminal.TransactionSeqCount}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Trx. Ref-No:".PadRight(_lineWidth/2) + $"{terminal.TransactionRefNo}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Auth. Code:".PadRight(_lineWidth/2) + $"{terminal.AuthCode}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Acq-Id:".PadRight(_lineWidth/2) + $"{terminal.AcquirerId}".PadLeft(_lineWidth/2))); + + commands.Add(new PrintCommand($"EFT {terminal.Currency}:".PadRight(_lineWidth/2) + $"{terminal.EftAmount:F2}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Trinkgeld {terminal.Currency}:".PadRight(_lineWidth/2) + $"{terminal.TipAmount:F2}".PadLeft(_lineWidth/2))); + commands.Add(new PrintCommand($"Total-EFT {terminal.Currency}:".PadRight(_lineWidth/2) + $"{terminal.TotalEftAmount:F2}".PadLeft(_lineWidth/2))); + + commands.Add(new PrintCommand(new string('-', _lineWidth))); + commands.Add(new PrintCommand("")); + } // Thank you message commands.Add(new PrintCommand(Center(finalReceipt.ThankYouMessage, false))); diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs index b9dde67..2f22719 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs @@ -40,15 +40,11 @@ public List Dishes { get; set; } = new List(); - /// - /// Additional items or notes (e.g., "Amuse Bouche") - /// - public List AdditionalInfo { get; set; } - + public KitchenReceipt() { Gangs = new List(); - AdditionalInfo = new List(); + } } diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/Models.cs new file mode 100644 index 0000000..e03a202 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/Models.cs @@ -0,0 +1,27 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.OrderItems; + +public class OrderItemsReceipt +{ + public string OrderNumber { get; set; } + public string QRInfo { get; set; } + public DateTime DateTime { get; set; } + public string ClientNotes { get; set; } + public List Items { get; set; } = new List(); +} + +public class OrderItem +{ + public int Number { get; set; } + public string Name { get; set; } + public int Quantity { get; set; } + public string Size { get; set; } + public List SubItems { get; set; } = new List(); + public ItemModifications Modifications { get; set; } + public string Comment { get; set; } +} + +public class ItemModifications +{ + public List Removed { get; set; } = new List(); + public List Added { get; set; } = new List(); +} diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/ReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/ReceiptConverter.cs new file mode 100644 index 0000000..12ab320 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/OrderItems/ReceiptConverter.cs @@ -0,0 +1,183 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.OrderItems; + +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(OrderItemsReceipt receipt) + { + var commands = new List(); + + // Header box + AddHeaderBox(commands, receipt); + + // Client Notes + if (!string.IsNullOrEmpty(receipt.ClientNotes)) + { + commands.Add(new PrintCommand($"|Client Notes: {receipt.ClientNotes}")); + } + + // Separator line + commands.Add(new PrintCommand(new string('-', _lineWidth))); + + // Items + foreach (var item in receipt.Items) + { + commands.Add(new PrintCommand("")); + AddOrderItem(commands, item); + } + + return commands; + } + + private void AddHeaderBox(List commands, OrderItemsReceipt receipt) + { + // Column widths (fixed proportions) + int col1Width = 8; // Order column + int col3Width = 12; // Date/Time column + int col2Width = _lineWidth - col1Width - col3Width - 4; // QR column (4 for borders |) + + // Prepare column content with labels on first line, values on subsequent lines + var col1Lines = new List { "Order:" }; + col1Lines.AddRange(WrapText($"#{receipt.OrderNumber}", col1Width)); + + var col2Lines = new List { "QR:" }; + col2Lines.AddRange(WrapText(receipt.QRInfo, col2Width)); + + var col3Lines = new List + { + $"{receipt.DateTime:dd.MM.yyyy}", + $"{receipt.DateTime:HH:mm:ss}" + }; + + // Determine max rows needed + int maxRows = Math.Max(Math.Max(col1Lines.Count, col2Lines.Count), col3Lines.Count); + + // Pad columns to have equal rows + while (col1Lines.Count < maxRows) col1Lines.Add(""); + while (col2Lines.Count < maxRows) col2Lines.Add(""); + while (col3Lines.Count < maxRows) col3Lines.Add(""); + + // Top border + commands.Add(new PrintCommand("+" + new string('-', col1Width) + "+" + new string('-', col2Width) + "+" + new string('-', col3Width) + "+")); + + // Content rows + for (int i = 0; i < maxRows; i++) + { + string row = "|" + + CenterInWidth(col1Lines[i], col1Width) + "|" + + CenterInWidth(col2Lines[i], col2Width) + "|" + + CenterInWidth(col3Lines[i], col3Width) + "|"; + + commands.Add(new PrintCommand(row, isBold: i == 0)); + } + + // Bottom border + commands.Add(new PrintCommand("+" + new string('-', col1Width) + "+" + new string('-', col2Width) + "+" + new string('-', col3Width) + "+")); + } + + private List WrapText(string text, int maxWidth) + { + var lines = new List(); + + if (string.IsNullOrEmpty(text)) + { + lines.Add(""); + return lines; + } + + // Trim to fit within column + while (text.Length > 0) + { + if (text.Length <= maxWidth) + { + lines.Add(text); + break; + } + + // Find a good break point (prefer space) + int breakPoint = text.LastIndexOf(' ', Math.Min(maxWidth, text.Length - 1)); + if (breakPoint <= 0 || breakPoint > maxWidth) + { + breakPoint = maxWidth; + } + + lines.Add(text.Substring(0, breakPoint).TrimEnd()); + text = text.Substring(breakPoint).TrimStart(); + } + + return lines; + } + + private void AddOrderItem(List commands, OrderItem item) + { + // Main item line: "1 Item Name x1" or "3 Item Name Size: L x2" + string numberPart = $"{item.Number}"; + string namePart = item.Name; + string quantityPart = $"x{item.Quantity}"; + + string sizePart = ""; + if (!string.IsNullOrEmpty(item.Size)) + { + sizePart = $"Size: {item.Size} "; + } + + string rightPart = sizePart + quantityPart; + int spacesNeeded = _lineWidth - numberPart.Length - 1 - namePart.Length - rightPart.Length; + if (spacesNeeded < 1) spacesNeeded = 1; + + string mainLine = numberPart + " " + namePart + new string(' ', spacesNeeded) + rightPart; + commands.Add(new PrintCommand(mainLine)); + + // Sub-items + foreach (var subItem in item.SubItems) + { + commands.Add(new PrintCommand($" - {subItem}")); + } + + // Modifications + if (item.Modifications != null && (item.Modifications.Removed.Any() || item.Modifications.Added.Any())) + { + commands.Add(new PrintCommand(" Change of")); + commands.Add(new PrintCommand(" Ingredients:")); + + foreach (var removed in item.Modifications.Removed) + { + commands.Add(new PrintCommand($" - {removed}")); + } + + foreach (var added in item.Modifications.Added) + { + commands.Add(new PrintCommand($" + {added}")); + } + } + + // Comment + if (!string.IsNullOrEmpty(item.Comment)) + { + commands.Add(new PrintCommand($" Comment: {item.Comment}")); + } + } + + private string CenterInWidth(string text, int width) + { + if (string.IsNullOrEmpty(text)) + return new string(' ', width); + + if (text.Length >= width) + return text.Substring(0, width); + + int totalPadding = width - text.Length; + int leftPadding = totalPadding / 2; + int rightPadding = totalPadding - leftPadding; + + return new string(' ', leftPadding) + text + new string(' ', rightPadding); + } +} diff --git a/Inspectron.Epson/Queue/PrintJob.cs b/Inspectron.Epson/Queue/PrintJob.cs index 5adb631..3c09b4e 100644 --- a/Inspectron.Epson/Queue/PrintJob.cs +++ b/Inspectron.Epson/Queue/PrintJob.cs @@ -1,13 +1,15 @@ -public class PrintJob +using static Inspectron.Epson.PrintServer.JobSources.SignalRPrintJobSource; + +public class PrintJob { - public string AreaId { get; set; } - public string Document { get; set; } + // todo: change to ip address + public string IP { get; set; } + public PrintJobFromSignalR Document { get; set; } public DateTime QueuedAt { get; set; } public int RetryCount { get; set; } public PrintJob() { - AreaId = Guid.NewGuid().ToString(); QueuedAt = DateTime.UtcNow; RetryCount = 0; } diff --git a/Inspectron.Epson/Queue/PrinterQueue.cs b/Inspectron.Epson/Queue/PrinterQueue.cs index a574e70..1c4ff50 100644 --- a/Inspectron.Epson/Queue/PrinterQueue.cs +++ b/Inspectron.Epson/Queue/PrinterQueue.cs @@ -34,7 +34,7 @@ public class PrinterQueue { _queue.Enqueue(job); _signal.Release(); // Signal that there's work to do - _logger.LogInformation("Job {JobId} queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength); + _logger.LogInformation("Job queued for printer {PrinterId}. Queue length: {QueueLength}", PrinterIp, QueueLength); } public void Start() @@ -50,7 +50,7 @@ public class PrinterQueue { _priorityQueue.Push(job); _signal.Release(); - _logger.LogInformation("Job {JobId} priority queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength); + _logger.LogInformation("Job priority queued for printer {PrinterId}. Queue length: {QueueLength}", PrinterIp, QueueLength); } private async Task ProcessQueueAsync(CancellationToken cancellationToken) { @@ -68,7 +68,7 @@ public class PrinterQueue if (job!=null) { - _logger.LogInformation("Processing job {JobId} on printer {PrinterId}", job.AreaId, PrinterIp); + _logger.LogInformation("Processing job on printer {PrinterId}", PrinterIp); try { @@ -79,18 +79,18 @@ public class PrinterQueue { // Re-queue with retry logic job.RetryCount++; - _logger.LogWarning("Job {JobId} failed, retrying ({RetryCount}/3)", job.AreaId, job.RetryCount); + _logger.LogWarning("Job failed, retrying ({RetryCount}/3)", job.RetryCount); await Task.Delay(5000, cancellationToken); // Wait before retry EnqueuePriority(job); } else { - _logger.LogInformation("Job {JobId} completed successfully on printer {PrinterId}", job.AreaId, PrinterIp); + _logger.LogInformation("Job completed successfully on printer {PrinterId}", PrinterIp); } } catch (Exception ex) { - _logger.LogError(ex, "Error processing job {JobId}", job.AreaId); + _logger.LogError(ex, "Error processing job"); // Handle exception (retry, log, etc.) } } diff --git a/order_items.png b/order_items.png new file mode 100644 index 0000000..aead8c9 Binary files /dev/null and b/order_items.png differ diff --git a/receipt_tail.png b/receipt_tail.png new file mode 100644 index 0000000..9077854 Binary files /dev/null and b/receipt_tail.png differ