test run works

This commit is contained in:
EugeneTes
2026-01-20 10:11:04 +01:00
parent 4720ca2d57
commit 6f5116736c
22 changed files with 351 additions and 441 deletions

View File

@@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Inspectron.Epson.PrintServer.Printers;
using Inspectron.Epson.PrintServer.Printers.Utils;
namespace Inspectron.Epson.PrintServer.PrintServices;
@@ -10,13 +10,15 @@ public class EpsonPrintService: IPrintService
private readonly IPrinterFactory _printerFactory;
private readonly IWrapperPrinterFactory _wrapperPrinterFactory;
private readonly IPrinterConfigurationSource _printerConfigurationSource;
private readonly IReceiptConverterFactory _receiptConverterFactory;
public EpsonPrintService(ILogger logger, IPrinterFactory printerFactory, IWrapperPrinterFactory wrapperPrinterFactory, IPrinterConfigurationSource printerConfigurationSource)
public EpsonPrintService(ILogger logger, IPrinterFactory printerFactory, IWrapperPrinterFactory wrapperPrinterFactory, IPrinterConfigurationSource printerConfigurationSource, IReceiptConverterFactory receiptConverterFactory)
{
_logger = logger;
_printerFactory = printerFactory;
_wrapperPrinterFactory = wrapperPrinterFactory;
_printerConfigurationSource = printerConfigurationSource;
_receiptConverterFactory = receiptConverterFactory;
}
public async Task<bool> PrintAsync(string printerIp, PrintJob job)
@@ -25,19 +27,8 @@ public class EpsonPrintService: IPrintService
{
var configuration = _printerConfigurationSource.GetConfiguration(printerIp);
await using var epsonPrinter = _printerFactory.CreatePrinter();
string address;
string address = printerIp;
int port = 9100;
var printerAddress = configuration.Address;
if (printerAddress.Contains(":"))
{
var parts = printerAddress.Split(':');
address = parts[0];
port = int.Parse(parts[1]);
}
else
{
address = printerAddress;
}
await epsonPrinter.ConnectAsync(address, port);
@@ -90,7 +81,10 @@ public class EpsonPrintService: IPrintService
await printerAdapter.SetFontSizeAsync(configuration.FontSize);
await printerAdapter.PrintTextAsync(job.Document.Content);
// Convert receipt content to print commands using the factory
var converter = _receiptConverterFactory.Create(job.Document.ReceiptType, lineWidth: 48, bigFontLineWidth: 24);
var commands = converter.Convert(job.Document.Content);
await printerAdapter.PrintAsync(commands);
await Task.Delay(200);
status = await epsonPrinter.GetPrinterStatusAsync();
if (!status.IsOnline)

View File

@@ -1,10 +1,12 @@
namespace Inspectron.Epson.PrintServer.PrintServices;
using Inspectron.Epson.PrintServer.Printers.Utils;
namespace Inspectron.Epson.PrintServer.PrintServices;
public interface IPrinter
{
public Task InitAsync();
public Task PrintImageAsync(string path);
public Task SetFontSizeAsync(int fontSize);
public Task PrintTextAsync(string text);
public Task PrintAsync(List<PrintCommand> commands);
public Task Cut();
}

View File

@@ -1,10 +1,9 @@
using Inspectron.Epson.PrintServer.PrintServices;
using System.Net.NetworkInformation;
using System.Reflection;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.PrintServices;
namespace Inspectron.Epson.PrintServer.Printers;
public class TM_T30III:IPrinter
public class TM_T30III : IPrinter
{
private readonly EpsonPrinter _printer;
@@ -33,11 +32,25 @@ public class TM_T30III:IPrinter
await _printer.SetFontSizeAsync(fontSize, fontSize);
}
public async Task PrintTextAsync(string text)
public async Task PrintAsync(List<PrintCommand> commands)
{
await _printer.PrintTextAsync(text);
foreach (var command in commands)
{
if (command.IsBig)
{
await _printer.SetFontSizeAsync(2, 2);
}
else
{
await _printer.SetFontSizeAsync(1, 1);
}
await _printer.SetRedColor(command.IsRed);
await _printer.SetEmphasized(command.IsBold);
await _printer.PrintTextAsync(command.Text + "\n");
}
await _printer.FeedLinesAsync(5);
var status = await _printer.GetPrinterStatusAsync();
}
public async Task Cut()

View File

@@ -1,13 +1,9 @@
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.PrintServices;
using System.Reflection;
using System.Text.Json;
using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt;
namespace Inspectron.Epson.PrintServer.Printers;
public class TM_T30IIITranslated:IPrinter
public class TM_T30IIITranslated : IPrinter
{
private readonly IEpsonPrinter _printer;
@@ -40,31 +36,12 @@ public class TM_T30IIITranslated:IPrinter
//await _printer.SetFontSizeAsync(fontSize, fontSize);
}
public async Task PrintTextAsync(string text)
public async Task PrintAsync(List<PrintCommand> commands)
{
FinalReceipt? receipt;
try
{
receipt = JsonSerializer.Deserialize<FinalReceipt>(text);
}
catch
{
// Fallback to kitchen receipt
await PrintKitchen(text);
return;
}
var converter = new ReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
var printCommands = converter.ConvertToPrintCommands(receipt);
await _printer.SetCustomLineSpacing(22);
foreach (var command in printCommands)
foreach (var command in commands)
{
string attributes = "";
if (command.IsBig) attributes += "[BIG]\n";
if (command.IsBold) attributes += "[BOLD]\n";
Console.WriteLine($"{attributes}{command.Text}");
if (command.IsBig)
{
await _printer.SetFontSizeAsync(2, 1);
@@ -73,11 +50,11 @@ public class TM_T30IIITranslated:IPrinter
{
await _printer.SetFontSizeAsync(1, 1);
}
await _printer.SetEmphasized(command.IsBold);
await _printer.PrintTextAsync(command.Text + "\n");
await _printer.SetRedColor(command.IsRed);
await _printer.SetEmphasized(command.IsBold);
await _printer.PrintTextAsync(command.Text + "\n");
}
await _printer.SetDefaultLineSpacing();
@@ -85,37 +62,6 @@ public class TM_T30IIITranslated:IPrinter
await Task.Delay(200);
}
private async Task PrintKitchen(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)
{
if (command.IsBig)
{
await _printer.SetFontSizeAsync(2,2);
}
else
{
await _printer.SetFontSizeAsync(1, 1);
}
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.FeedLinesAsync(10);
await Task.Delay(1000);
}
public async Task Cut()
{
await _printer.CutAsync();

View File

@@ -1,9 +1,9 @@
using Inspectron.Epson.PrintServer.PrintServices;
using System.Reflection;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.PrintServices;
namespace Inspectron.Epson.PrintServer.Printers;
public class TM_U220II:IPrinter
public class TM_U220II : IPrinter
{
private readonly EpsonPrinter _printer;
@@ -31,14 +31,20 @@ public class TM_U220II:IPrinter
await Task.Delay(200);
}
public async Task PrintTextAsync(string text)
public async Task PrintAsync(List<PrintCommand> commands)
{
await _printer.PrintTextAsync(text);
var lines = text.Split('\n').Length;
for (int i = 0; i < lines; i++)
foreach (var 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.FeedLinesAsync(5);
await Task.Delay(200);
}

View File

@@ -1,12 +1,9 @@
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.PrintServices;
using System.Reflection;
using System.Text.Json;
namespace Inspectron.Epson.PrintServer.Printers;
public class TM_U220IITranslated:IPrinter
public class TM_U220IITranslated : IPrinter
{
private readonly IEpsonPrinter _printer;
@@ -34,11 +31,8 @@ public class TM_U220IITranslated:IPrinter
//await Task.Delay(200);
}
public async Task PrintTextAsync(string text)
public async Task PrintAsync(List<PrintCommand> commands)
{
var deserializedReceipt = JsonSerializer.Deserialize<KitchenReceipt>(text);
KitchenReceiptConverter translator = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth: 33);
var commands = translator.ConvertToPrintCommands(deserializedReceipt);
foreach (var command in commands)
{
await _printer.SetBiggerFontTM220(command.IsBig);
@@ -50,7 +44,7 @@ public class TM_U220IITranslated:IPrinter
await _printer.PrintTextAsync(command.Text + "\n");
await Task.Delay(200);
}
await _printer.FeedLinesAsync(10);
await Task.Delay(1000);
}

View File

@@ -0,0 +1,22 @@
using System.Text.Json;
namespace Inspectron.Epson.PrintServer.Printers.Utils.FinalReceipt;
public class FinalReceiptConverter : IReceiptConverter
{
private readonly int _lineWidth;
private readonly int _bigFontLineWidth;
public FinalReceiptConverter(int lineWidth, int bigFontLineWidth)
{
_lineWidth = lineWidth;
_bigFontLineWidth = bigFontLineWidth;
}
public List<PrintCommand> Convert(string jsonContent)
{
var receipt = JsonSerializer.Deserialize<FinalRecipe.FinalReceipt>(jsonContent);
var converter = new FinalRecipe.ReceiptConverter(_lineWidth, _bigFontLineWidth);
return converter.ConvertToPrintCommands(receipt);
}
}

View File

@@ -0,0 +1,6 @@
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public interface IReceiptConverter
{
List<PrintCommand> Convert(string jsonContent);
}

View File

@@ -0,0 +1,6 @@
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public interface IReceiptConverterFactory
{
IReceiptConverter Create(int receiptType, int lineWidth, int bigFontLineWidth);
}

View File

@@ -1,9 +0,0 @@
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public class KitchenPrintCommand
{
public bool IsBig { get; set; }
public bool IsBold { get; set; }
public bool IsRed { get; set; }
public string Text { get; set; }
}

View File

@@ -33,6 +33,13 @@ public class KitchenReceiptConverter
string tableLine = $"Tisch: {kitchenReceipt.TableNumber}";
commands.Add(new PrintCommand(Center(tableLine, true), true, true));
if (!string.IsNullOrEmpty(kitchenReceipt.SpecialInstruction))
{
commands.Add(new PrintCommand(""));
commands.Add(new PrintCommand(Center(kitchenReceipt.SpecialInstruction, true), true,true));
commands.Add(new PrintCommand(""));
}
commands.Add(new PrintCommand(CreateDashedLine()));
@@ -46,8 +53,7 @@ public class KitchenReceiptConverter
commands.Add(new PrintCommand(Center($"{gang.Id}. {gang.Name}", false)) { IsRed = true });
foreach (var dish in gang.Dishes)
{
string dishLine = $"{dish.Number}x {dish.Name}";
commands.Add(new PrintCommand(dishLine));
PrintDish(dish, commands);
}
}
@@ -58,15 +64,17 @@ public class KitchenReceiptConverter
foreach (var dish in kitchenReceipt.Dishes)
{
string dishLine = $"{dish.Number}x {dish.Name}";
commands.Add(new PrintCommand(dishLine));
PrintDish(dish, commands);
}
if (kitchenReceipt.Dishes != null && kitchenReceipt.Dishes.Any())
{
commands.Add(new PrintCommand(""));
commands.Add(new PrintCommand(CreateDashedLine()));
commands.Add(new PrintCommand(""));
}
commands.Add(new PrintCommand(""));
commands.Add(new PrintCommand(CreateDashedLine()));
commands.Add(new PrintCommand(""));
//// Additional info section
//if (kitchenReceipt.AdditionalInfo != null && kitchenReceipt.AdditionalInfo.Count > 0)
//{
@@ -85,6 +93,33 @@ public class KitchenReceiptConverter
return commands;
}
private static void PrintDish(Dish dish, List<PrintCommand> commands)
{
string dishLine = $"{dish.Number}x {dish.Name}";
commands.Add(new PrintCommand(dishLine));
// Modifications
if (dish.Modifications != null && (dish.Modifications.Removed.Any() || dish.Modifications.Added.Any()))
{
foreach (var removed in dish.Modifications.Removed)
{
commands.Add(new PrintCommand($" - {removed}", isBold:true));
}
foreach (var added in dish.Modifications.Added)
{
commands.Add(new PrintCommand($" + {added}", isBold: true));
}
}
// SpecialInstruction
if (!string.IsNullOrEmpty(dish.Comment))
{
commands.Add(new PrintCommand($" Comment: {dish.Comment}", isBold: true));
}
//commands.Add(new PrintCommand($""));
}
private string Center(string text, bool isBigFont)
{
var actualLineWidth = isBigFont ? _BigLineWidth : _lineWidth;

View File

@@ -0,0 +1,22 @@
using System.Text.Json;
namespace Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
public class KitchenReceiptConverterAdapter : IReceiptConverter
{
private readonly int _lineWidth;
private readonly int _bigFontLineWidth;
public KitchenReceiptConverterAdapter(int lineWidth, int bigFontLineWidth)
{
_lineWidth = lineWidth;
_bigFontLineWidth = bigFontLineWidth;
}
public List<PrintCommand> Convert(string jsonContent)
{
var receipt = JsonSerializer.Deserialize<KitchenReceipt>(jsonContent);
var converter = new KitchenReceiptConverter(_lineWidth, _bigFontLineWidth);
return converter.ConvertToPrintCommands(receipt);
}
}

View File

@@ -33,8 +33,9 @@
/// <summary>
/// Table number
/// </summary>
public int TableNumber { get; set; }
public string TableNumber { get; set; }
public string SpecialInstruction { get; set; }
public List<Gang> Gangs { get; set; } = new List<Gang>();
@@ -77,12 +78,22 @@
/// </summary>
public string Name { get; set; }
public Dish(){}
public Dish(int number, string name)
{
Number = number;
Name = name;
}
public DishModifications Modifications { get; set; } = new DishModifications();
public string? Comment { get; set; }
}
public class DishModifications
{
public List<string> Removed { get; set; } = new List<string>();
public List<string> Added { get; set; } = new List<string>();
}
}

View File

@@ -1,95 +0,0 @@
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public class KitchenReceiptPrinter
{
private readonly int _lineWidth;
private readonly int _bigFontLineWidth;
public KitchenReceiptPrinter(int lineWidth = 42, int bigFontLineWidth = 21)
{
_lineWidth = lineWidth;
_bigFontLineWidth = bigFontLineWidth;
}
public List<KitchenPrintCommand> ConvertToCommands(TranslatedKitchenReceipt receipt)
{
var commands = new List<KitchenPrintCommand>();
// Header: "Warme Küche" - Big, Bold, Red, Centered
commands.Add(new KitchenPrintCommand
{
Text = Center(receipt.Location, isBigFont: true),
IsBig = true,
IsBold = true,
IsRed = true
});
commands.Add(Separator());
// Date and Owner info - Normal, Left-aligned
commands.Add(new KitchenPrintCommand { Text = Center(receipt.Date,false) });
var ownerLines = receipt.Owner.Split('\n');
foreach (var line in ownerLines)
{
commands.Add(new KitchenPrintCommand { Text = Center(line, false) });
}
// Table number - Big, Bold, Centered
commands.Add(new KitchenPrintCommand
{
Text = Center($"Tisch: {receipt.Tisch}", isBigFont: true),
IsBig = true,
IsBold = true
});
commands.Add(Separator());
// Items - Left-aligned
foreach (var item in receipt.items)
{
if (item is KitchenProduct kp)
{
commands.Add(new KitchenPrintCommand
{
Text = $"{kp.Amount}x {item.Name}"
});
}
if(item is KitchenGang kg)
{
commands.Add(new KitchenPrintCommand
{
IsRed = true,
IsBig = true,
IsBold = true,
Text = Center(item.Name,true)
});
}
}
commands.Add(Separator());
return commands;
}
private KitchenPrintCommand Separator()
{
return new KitchenPrintCommand
{
Text = new string('-', _lineWidth)
};
}
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;
}
}

View File

@@ -0,0 +1,22 @@
using System.Text.Json;
namespace Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
public class OrderItemsReceiptConverter : IReceiptConverter
{
private readonly int _lineWidth;
private readonly int _bigFontLineWidth;
public OrderItemsReceiptConverter(int lineWidth, int bigFontLineWidth)
{
_lineWidth = lineWidth;
_bigFontLineWidth = bigFontLineWidth;
}
public List<PrintCommand> Convert(string jsonContent)
{
var receipt = JsonSerializer.Deserialize<OrderItemsReceipt>(jsonContent);
var converter = new ReceiptConverter(_lineWidth, _bigFontLineWidth);
return converter.ConvertToPrintCommands(receipt);
}
}

View File

@@ -159,10 +159,10 @@ public class ReceiptConverter
}
}
// Comment
// SpecialInstruction
if (!string.IsNullOrEmpty(item.Comment))
{
commands.Add(new PrintCommand($" Comment: {item.Comment}"));
commands.Add(new PrintCommand($" SpecialInstruction: {item.Comment}"));
}
}

View File

@@ -0,0 +1,25 @@
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public class ReceiptConverterFactory : IReceiptConverterFactory
{
public IReceiptConverter Create(int receiptType, int lineWidth, int bigFontLineWidth)
{
return (EReceiptType)receiptType switch
{
EReceiptType.Receipt => new FinalReceipt.FinalReceiptConverter(lineWidth, bigFontLineWidth),
EReceiptType.WorkareaTicket => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20),
EReceiptType.NextCourse => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20),
EReceiptType.OrdersOverview => new OrderItemsReceiptConverter(lineWidth, bigFontLineWidth),
_ => throw new ArgumentException($"Unknown receipt type: {receiptType}")
};
}
public enum EReceiptType
{
Receipt,
WorkareaTicket,
NextCourse,
OrdersOverview
}
}

View File

@@ -1,206 +0,0 @@
namespace Inspectron.Epson.PrintServer.Printers.Utils;
public record TranslatedKitchenReceipt(string Location, string Date, string Owner, string Tisch, List<KitchenItem> items) :ASTNode;
public record KitchenItem(string Name) : ASTNode;
public record KitchenProduct(int Amount, string Name) : KitchenItem(Name);
public record KitchenGang(string Name) : KitchenItem(Name);
public record FinalReceipt(string Location, string Phone, string URL, string Date, List<FinalReceiptItem> items, string total, string MWST, string Comment, string Thanks) : ASTNode;
public record FinalReceiptItem(string Name, int Amount, string Price, string Total) : ASTNode;
public class ReceiptTranslator
{
public ASTNode ParseReceipt(string receiptText)
{
// Determine receipt type based on content
bool isFinalReceipt = receiptText.Contains("http") ||
receiptText.Contains("+41") ||
receiptText.Contains("Summe CHF") ||
receiptText.Contains("MWST") ||
receiptText.Contains("Thank you");
bool isKitchenReceipt = receiptText.Contains("TISCH:");
if (isKitchenReceipt && !isFinalReceipt)
{
return ParseKitchenReceipt(receiptText);
}
else if (isFinalReceipt)
{
return ParseFinalReceipt(receiptText);
}
else
{
// Default to kitchen receipt if unclear
return ParseKitchenReceipt(receiptText);
}
}
public static FinalReceipt ParseFinalReceipt(string receiptText)
{
var lines = receiptText.Split('\n', StringSplitOptions.RemoveEmptyEntries)
.Select(l => l.Trim())
.ToList();
// Extract header information
string location = lines[0];
string phone = lines[1];
string url = lines[2];
// Find and extract date
var dateLine = lines.FirstOrDefault(l => l.StartsWith("Datum:"));
string date = dateLine?.Replace("Datum:", "").Trim() ?? "";
// Find total line
var totalLine = lines.FirstOrDefault(l => l.Contains("Summe CHF :"));
string total = totalLine?.Split(':').Last().Trim() ?? "";
// Find MWST line (comes after "TOTAL MWST" header)
var mwstLineIndex = lines.FindIndex(l => l.StartsWith("TOTAL") && l.Contains("MWST"));
string mwst = mwstLineIndex >= 0 && mwstLineIndex + 1 < lines.Count
? lines[mwstLineIndex + 1].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? ""
: "";
// Extract comment (line after MWST values)
string comment = mwstLineIndex >= 0 && mwstLineIndex + 2 < lines.Count
? lines[mwstLineIndex + 2]
: "";
// Extract thank you message (last non-separator line)
string thanks = lines.LastOrDefault(l => !l.Contains("--")) ?? "";
// Parse items
var items = new List<FinalReceiptItem>();
var startIndex = lines.FindIndex(l => l.StartsWith("Datum:")) + 2; // Skip date and separator
var endIndex = lines.FindIndex(l => l.Contains("Summe CHF"));
for (int i = startIndex; i < endIndex; i++)
{
var line = lines[i];
// Skip separator lines and empty lines
if (line.Contains("---") || string.IsNullOrWhiteSpace(line))
continue;
// Check if line contains item data (has * separator)
if (line.Contains("*"))
{
// Parse format: "Name Amount * Price Total"
var parts = line.Split('*');
if (parts.Length == 2)
{
var leftPart = parts[0].Trim();
var rightPart = parts[1].Trim();
// Extract name and amount from left part
var leftTokens = leftPart.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var amount = int.Parse(leftTokens.Last());
var name = string.Join(" ", leftTokens.Take(leftTokens.Length - 1));
// Extract price and total from right part
var rightTokens = rightPart.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var price = rightTokens.Length > 0 ? rightTokens[0] : "";
var itemTotal = rightTokens.Length > 1 ? rightTokens[1] : "";
items.Add(new FinalReceiptItem(name, amount, price, itemTotal));
}
}
}
return new FinalReceipt(location, phone, url, date, items, total, mwst, comment, thanks);
}
public static TranslatedKitchenReceipt ParseKitchenReceipt(string receiptText)
{
var lines = receiptText.Split('\n', StringSplitOptions.RemoveEmptyEntries)
.Select(l => l.Trim())
.ToList();
int currentIndex = 0;
// Skip optional "*** KOPIE ***" header
if (lines[currentIndex].Contains("***"))
{
currentIndex++;
}
// Extract location (can be any phrase)
string location = lines[currentIndex];
currentIndex++;
// Skip separator line
while (currentIndex < lines.Count && lines[currentIndex].Contains("---"))
{
currentIndex++;
}
// Extract date line
string date = lines[currentIndex];
currentIndex++;
// Extract owner
string owner = "";
do
{
if (owner != "")
{
owner += "/n";
}
owner += lines[currentIndex];
currentIndex++;
} while (!lines[currentIndex].ToLower().Contains("tisch:"));
// Extract table (extract text after "TISCH:")
string tisch = lines[currentIndex].Replace("TISCH:", "").Trim();
currentIndex++;
// Skip empty lines and separators until we reach items
while (currentIndex < lines.Count &&
(string.IsNullOrWhiteSpace(lines[currentIndex]) || lines[currentIndex].Contains("-")))
{
currentIndex++;
}
// Parse items
var items = new List<KitchenItem>();
while (currentIndex < lines.Count)
{
var line = lines[currentIndex];
// Stop at separator or end
if (line.Contains("---") || string.IsNullOrWhiteSpace(line))
{
break;
}
if (line.ToLower().Contains(". gang"))
{
items.Add(new KitchenGang(line.Trim()));
currentIndex++;
continue;
}
// Parse format: "1x Espresso" or " 1x Espresso"
var trimmedLine = line.Trim();
if (trimmedLine.Contains("x"))
{
var parts = trimmedLine.Split('x', 2);
if (parts.Length == 2 && int.TryParse(parts[0].Trim(), out int amount))
{
var itemName = parts[1].Trim();
items.Add(new KitchenProduct(amount, itemName));
}
}
currentIndex++;
}
return new TranslatedKitchenReceipt(location, date, owner, tisch, items);
}
}