template engine
This commit is contained in:
27
EpsonTest.Templates/EpsonTest.Templates.csproj
Normal file
27
EpsonTest.Templates/EpsonTest.Templates.csproj
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Inspectron.Epson\Inspectron.Epson.csproj" />
|
||||
<ProjectReference Include="..\Inspectron.Epson.TemplateEngine\Inspectron.Epson.TemplateEngine.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Templates\*.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ristorante-klinglers.ch-logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ristorante-klinglers.ch-logo_white_bg.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
118
EpsonTest.Templates/Program.cs
Normal file
118
EpsonTest.Templates/Program.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using EpsonTest.Templates;
|
||||
using Inspectron.Epson.TemplateEngine;
|
||||
|
||||
var engine = new ReceiptTemplateEngine();
|
||||
var templatesDir = Path.Combine(AppContext.BaseDirectory, "Templates");
|
||||
|
||||
// ============================================================================
|
||||
// FINAL RECEIPT - HTML PRINTER
|
||||
// ============================================================================
|
||||
var json = TestHelpers.BuildFinalReceiptJson(includeTax: true);
|
||||
var template = File.ReadAllText(Path.Combine(templatesDir, "FinalReceipt.xml"));
|
||||
var printCommands = engine.Render(template, json, lineWidth: 48, bigFontLineWidth: 24);
|
||||
|
||||
TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
var printer = await TestHelpers.CreateHtmlPrinterAsync();
|
||||
await TestHelpers.PrintCommandsToHtmlPrinterAsync(
|
||||
printer,
|
||||
printCommands,
|
||||
logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// FINAL RECEIPT - EPSON PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildFinalReceiptJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "FinalReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 48, bigFontLineWidth: 24);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateEpsonPrinterAsync();
|
||||
//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// INVOICE RECEIPT - HTML PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildInvoiceReceiptJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "InvoiceReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 48, bigFontLineWidth: 24);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateHtmlPrinterAsync();
|
||||
//await TestHelpers.PrintCommandsToHtmlPrinterAsync(
|
||||
// printer,
|
||||
// printCommands,
|
||||
// logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// INVOICE RECEIPT - EPSON PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildInvoiceReceiptJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "InvoiceReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 48, bigFontLineWidth: 24);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateEpsonPrinterAsync();
|
||||
//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// KITCHEN RECEIPT - HTML PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildKitchenReceiptJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "KitchenReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 33, bigFontLineWidth: 20);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateHtmlPrinterAsync(
|
||||
// path: @".\kitchen_test.html",
|
||||
// paperWidth: TestHelpers.KitchenPaperWidth);
|
||||
//await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// KITCHEN RECEIPT (NEXT DISH) - HTML PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildKitchenReceiptNextDishJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "KitchenReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 33, bigFontLineWidth: 20);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateHtmlPrinterAsync(
|
||||
// path: @".\kitchen_next_dish.html",
|
||||
// paperWidth: TestHelpers.KitchenPaperWidth);
|
||||
//await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// KITCHEN RECEIPT - EPSON PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildKitchenReceiptJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "KitchenReceipt.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 33, bigFontLineWidth: 20);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
|
||||
//await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// ORDER ITEMS RECEIPT - HTML PRINTER
|
||||
// ============================================================================
|
||||
//var json = TestHelpers.BuildOrderItemsJson();
|
||||
//var template = File.ReadAllText(Path.Combine(templatesDir, "OrderItems.xml"));
|
||||
//var printCommands = engine.Render(template, json, lineWidth: 48, bigFontLineWidth: 24);
|
||||
|
||||
//TestHelpers.PrintCommandsToConsole(printCommands);
|
||||
|
||||
//var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\order_items.html");
|
||||
//await TestHelpers.PrintCommandsToHtmlPrinterAsync(printer, printCommands);
|
||||
115
EpsonTest.Templates/Templates/FinalReceipt.xml
Normal file
115
EpsonTest.Templates/Templates/FinalReceipt.xml
Normal file
@@ -0,0 +1,115 @@
|
||||
<receipt>
|
||||
<line align="center">{{CompanyName}}</line>
|
||||
<line align="center">{{Address1}}</line>
|
||||
<line align="center">{{Address2}}</line>
|
||||
<line align="center">{{Phone}}</line>
|
||||
<line />
|
||||
<line />
|
||||
|
||||
<if test="IsDebtor">
|
||||
<line>Debitorenrechnung</line>
|
||||
</if>
|
||||
|
||||
<columns left="{{ReceiptLabel}}" right="{{DateTime:HH:mm dd.MM.yyyy}}" bold="true" />
|
||||
<line>Guests: {{Guests}}</line>
|
||||
<line />
|
||||
|
||||
<foreach items="Items" var="item">
|
||||
<columns left="{{item.Quantity}}x {{item.Description}}" right="{{item.PriceDisplay}}" wrap="true" />
|
||||
<foreach items="item.SubItems" var="sub">
|
||||
<line> - {{sub}}</line>
|
||||
</foreach>
|
||||
</foreach>
|
||||
|
||||
<line />
|
||||
<line align="right">---------</line>
|
||||
<line />
|
||||
|
||||
<line align="center" big="true" bold="true">Summe: {{Total:F2}} {{Currency}}</line>
|
||||
<line />
|
||||
|
||||
<if test="TotalInAlternateCurrency">
|
||||
<line align="right">{{TotalInAlternateCurrency:F2}} {{AlternateCurrency}}</line>
|
||||
<line />
|
||||
</if>
|
||||
|
||||
<if test="DiscountInfo">
|
||||
<columns left="{{DiscountInfo.Description}}" right="{{DiscountInfo.Amount:F2}} {{DiscountInfo.Currency}}" wrap="true" />
|
||||
<line />
|
||||
</if>
|
||||
|
||||
<foreach items="SplitPayments" var="sp">
|
||||
<line align="right">{{sp.PaymentMethod}}: {{sp.Amount:F2}} {{sp.Currency}}</line>
|
||||
</foreach>
|
||||
<if test="HasSplitPayments">
|
||||
<line />
|
||||
</if>
|
||||
|
||||
<columns left="{{PaymentMethod}}" right="{{PaymentAmount:F2}} {{Currency}}" bold="true" />
|
||||
<line />
|
||||
|
||||
<foreach items="TaxBreakdown" var="tax">
|
||||
<if test="$first">
|
||||
<row>
|
||||
<col width="11" align="left">MwSt %</col>
|
||||
<col width="11" align="right">Brutto</col>
|
||||
<col width="11" align="right">Netto</col>
|
||||
<col align="right">MwSt</col>
|
||||
</row>
|
||||
</if>
|
||||
<row>
|
||||
<col width="11" align="left">{{tax.Category}}:{{tax.Rate}}%</col>
|
||||
<col width="11" align="right"> {{tax.Gross:F2}} {{tax.Currency}}</col>
|
||||
<col width="11" align="right"> {{tax.Net:F2}} {{tax.Currency}}</col>
|
||||
<col align="right"> {{tax.TaxAmount:F2}} {{tax.Currency}}</col>
|
||||
</row>
|
||||
</foreach>
|
||||
|
||||
<if test="!HasTaxableCategories">
|
||||
<line>Nicht mehrwertsteuerpflichtig</line>
|
||||
</if>
|
||||
|
||||
<line />
|
||||
|
||||
<columns left="Bedient von:" right="{{WaiterName}}" />
|
||||
<if test="Terminal">
|
||||
<columns left="Terminal:" right="{{Terminal}}" />
|
||||
</if>
|
||||
<columns left="Tisch:" right="{{TableNumber}}" />
|
||||
<line />
|
||||
<line />
|
||||
|
||||
<line align="center">{{VatNumber}}</line>
|
||||
<line />
|
||||
|
||||
<foreach items="TerminalReceipts" var="tr">
|
||||
<line align="center">{{tr.ReceiptType}}</line>
|
||||
<line align="center">{{tr.BookingType}}</line>
|
||||
<line align="center">{{tr.PaymentSystem}}</line>
|
||||
<line>{{tr.TransactionNumber}}</line>
|
||||
<columns left="{{tr.TransactionDateTime:dd.MM.yyyy}}" right="{{tr.TransactionDateTime:HH:mm:ss}}" />
|
||||
<columns left="Trm-Id:" right="{{tr.TerminalId}}" />
|
||||
<columns left="AID:" right="{{tr.AID}}" />
|
||||
<columns left="Trx. Seq-Cnt:" right="{{tr.TransactionSeqCount}}" />
|
||||
<columns left="Trx. Ref-No:" right="{{tr.TransactionRefNo}}" />
|
||||
<columns left="Auth. Code:" right="{{tr.AuthCode}}" />
|
||||
<columns left="Acq-Id:" right="{{tr.AcquirerId}}" />
|
||||
<columns left="EFT {{tr.Currency}}:" right="{{tr.EftAmount:F2}}" />
|
||||
<columns left="Trinkgeld {{tr.Currency}}:" right="{{tr.TipAmount:F2}}" />
|
||||
<columns left="Total-EFT {{tr.Currency}}:" right="{{tr.TotalEftAmount:F2}}" />
|
||||
<separator />
|
||||
<line />
|
||||
</foreach>
|
||||
|
||||
<line align="center">{{ThankYouMessage}}</line>
|
||||
<line align="center">{{GoodbyeMessageLine1}}</line>
|
||||
<line align="center">{{GoodbyeMessageLine2}}</line>
|
||||
|
||||
<if test="IsDebtor">
|
||||
<line />
|
||||
<line />
|
||||
<line />
|
||||
<separator />
|
||||
<line>Unterschrift</line>
|
||||
</if>
|
||||
</receipt>
|
||||
29
EpsonTest.Templates/Templates/InvoiceReceipt.xml
Normal file
29
EpsonTest.Templates/Templates/InvoiceReceipt.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<receipt>
|
||||
<line align="center">{{CompanyName}}</line>
|
||||
<line align="center">{{Address1}}</line>
|
||||
<line align="center">{{Address2}}</line>
|
||||
<line align="center">{{Phone}}</line>
|
||||
<line />
|
||||
<line />
|
||||
|
||||
<columns left="{{ReceiptLabel}}" right="{{DateTime:HH:mm dd.MM.yyyy}}" bold="true" />
|
||||
<if test="Guests">
|
||||
<line>Guests: {{Guests}}</line>
|
||||
</if>
|
||||
<line />
|
||||
|
||||
<foreach items="Items" var="item">
|
||||
<columns left="{{item.Quantity}}x {{item.Description}}" right="{{item.PriceDisplay}}" wrap="true" />
|
||||
<foreach items="item.SubItems" var="sub">
|
||||
<line> - {{sub}}</line>
|
||||
</foreach>
|
||||
</foreach>
|
||||
|
||||
<line />
|
||||
<line align="right">---------</line>
|
||||
<line />
|
||||
|
||||
<line align="center" big="true" bold="true">Summe: {{Total:F2}} {{Currency}}</line>
|
||||
<line align="center">Tisch: {{TableNumber}}</line>
|
||||
<line align="center">{{ThankYouMessage}}</line>
|
||||
</receipt>
|
||||
65
EpsonTest.Templates/Templates/KitchenReceipt.xml
Normal file
65
EpsonTest.Templates/Templates/KitchenReceipt.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<receipt>
|
||||
<line align="center" big="true" tall="true" red="true">{{Title}}</line>
|
||||
<separator />
|
||||
<line />
|
||||
|
||||
<line align="center">{{TransactionDateTime:dd-MMM-yy HH:mm}} Nr.:{{ReceiptNumber}}</line>
|
||||
<line align="center">{{WaiterName}}</line>
|
||||
<line align="center" big="true" bold="true">Tisch: {{TableNumber}}</line>
|
||||
|
||||
<if test="SpecialInstruction">
|
||||
<line />
|
||||
<line align="center" big="true" bold="true">{{SpecialInstruction}}</line>
|
||||
<line />
|
||||
</if>
|
||||
|
||||
<separator />
|
||||
|
||||
<foreach items="Gangs" var="gang">
|
||||
<line align="center" big="true" tall="true" red="true">{{gang.Id}}. {{gang.Name}}</line>
|
||||
<foreach items="gang.Dishes" var="dish">
|
||||
<line tall="true" wrap="true">{{dish.GuestPrefix}}{{dish.Number}}x {{dish.Name}}</line>
|
||||
<if test="dish.Modifications.HasModifications">
|
||||
<foreach items="dish.Modifications.Removed" var="removed">
|
||||
<line tall="true" bold="true"> - {{removed}}</line>
|
||||
</foreach>
|
||||
<foreach items="dish.Modifications.Added" var="added">
|
||||
<line tall="true" bold="true"> + {{added}}</line>
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="dish.Comment">
|
||||
<line tall="true" bold="true">Comment: {{dish.Comment}}</line>
|
||||
</if>
|
||||
</foreach>
|
||||
<if test="!$last">
|
||||
<cut />
|
||||
<line />
|
||||
<line />
|
||||
</if>
|
||||
</foreach>
|
||||
|
||||
<if test="HasGangs">
|
||||
<separator />
|
||||
</if>
|
||||
|
||||
<foreach items="Dishes" var="dish">
|
||||
<line tall="true" wrap="true">{{dish.GuestPrefix}}{{dish.Number}}x {{dish.Name}}</line>
|
||||
<if test="dish.Modifications.HasModifications">
|
||||
<foreach items="dish.Modifications.Removed" var="removed">
|
||||
<line tall="true" bold="true"> - {{removed}}</line>
|
||||
</foreach>
|
||||
<foreach items="dish.Modifications.Added" var="added">
|
||||
<line tall="true" bold="true"> + {{added}}</line>
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="dish.Comment">
|
||||
<line tall="true" bold="true">Comment: {{dish.Comment}}</line>
|
||||
</if>
|
||||
</foreach>
|
||||
|
||||
<if test="HasDishes">
|
||||
<line />
|
||||
<separator />
|
||||
<line />
|
||||
</if>
|
||||
</receipt>
|
||||
34
EpsonTest.Templates/Templates/OrderItems.xml
Normal file
34
EpsonTest.Templates/Templates/OrderItems.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<receipt>
|
||||
<table items="Items" var="item">
|
||||
<col width="8" align="center">Order:</col>
|
||||
<col align="center">QR:</col>
|
||||
<col width="12" align="center">{{DateTime:dd.MM.yyyy}}</col>
|
||||
</table>
|
||||
|
||||
<if test="ClientNotes">
|
||||
<line>|Client Notes: {{ClientNotes}}</line>
|
||||
</if>
|
||||
|
||||
<separator />
|
||||
|
||||
<foreach items="Items" var="item">
|
||||
<line />
|
||||
<columns left="{{item.Number}} {{item.Name}}" right="{{item.SizePart}}x{{item.Quantity}}" />
|
||||
<foreach items="item.SubItems" var="sub">
|
||||
<line> - {{sub}}</line>
|
||||
</foreach>
|
||||
<if test="item.Modifications.HasModifications">
|
||||
<line> Change of</line>
|
||||
<line> Ingredients:</line>
|
||||
<foreach items="item.Modifications.Removed" var="removed">
|
||||
<line> - {{removed}}</line>
|
||||
</foreach>
|
||||
<foreach items="item.Modifications.Added" var="added">
|
||||
<line> + {{added}}</line>
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="item.Comment">
|
||||
<line> SpecialInstruction: {{item.Comment}}</line>
|
||||
</if>
|
||||
</foreach>
|
||||
</receipt>
|
||||
579
EpsonTest.Templates/TestHelpers.cs
Normal file
579
EpsonTest.Templates/TestHelpers.cs
Normal file
@@ -0,0 +1,579 @@
|
||||
using Inspectron.Epson;
|
||||
using Inspectron.Epson.PrintServer.Printers.Utils;
|
||||
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
|
||||
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
|
||||
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
|
||||
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace EpsonTest.Templates;
|
||||
|
||||
public static class TestHelpers
|
||||
{
|
||||
// Default connection settings
|
||||
public const string DefaultEpsonIp = "127.0.0.1";
|
||||
public const int DefaultEpsonPort = 8888;
|
||||
public const string DefaultHtmlPath = @".\test.html";
|
||||
public const int DefaultPaperWidth = 384;
|
||||
public const int KitchenPaperWidth = 258;
|
||||
|
||||
#region Printer Creation
|
||||
|
||||
public static async Task<EpsonPrinter> CreateEpsonPrinterAsync(
|
||||
string ip = DefaultEpsonIp,
|
||||
int port = DefaultEpsonPort, int paperWidth = DefaultPaperWidth)
|
||||
{
|
||||
var printer = new EpsonPrinter();
|
||||
await printer.ConnectAsync(ip, port);
|
||||
return printer;
|
||||
}
|
||||
|
||||
public static async Task<HtmlPrinter> CreateHtmlPrinterAsync(
|
||||
string path = DefaultHtmlPath,
|
||||
int paperWidth = DefaultPaperWidth)
|
||||
{
|
||||
var printer = new HtmlPrinter(path, paperWidth: paperWidth);
|
||||
await printer.ConnectAsync("");
|
||||
return printer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Print Helpers
|
||||
|
||||
public static async Task PrintCommandsToHtmlPrinterAsync(
|
||||
HtmlPrinter printer,
|
||||
IEnumerable<PrintCommand> commands,
|
||||
string? logoPath = null,
|
||||
int logoWidth = 300,
|
||||
int logoXPosition = 42)
|
||||
{
|
||||
if (logoPath != null)
|
||||
{
|
||||
await printer.SetAbsolutePrintPosition(logoXPosition);
|
||||
await printer.LoadImageAsync(logoPath, logoWidth);
|
||||
await printer.PrintLoadedImage();
|
||||
await printer.SetAbsolutePrintPosition(0);
|
||||
}
|
||||
|
||||
await printer.SetCustomLineSpacing(22);
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
if (command.IsBig)
|
||||
await printer.SetFontSizeAsync(2, 1);
|
||||
else
|
||||
await printer.SetFontSizeAsync(1, 1);
|
||||
|
||||
await printer.SetEmphasized(command.IsBold);
|
||||
await printer.PrintTextAsync(command.Text + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task PrintCommandsToEpsonPrinterAsync(
|
||||
EpsonPrinter printer,
|
||||
IEnumerable<PrintCommand> commands,
|
||||
bool useDelay = true,
|
||||
int delayMs = 200)
|
||||
{
|
||||
await printer.FeedLinesAsync(1);
|
||||
await printer.SetCustomLineSpacing(22);
|
||||
|
||||
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);
|
||||
if (useDelay) await Task.Delay(delayMs);
|
||||
|
||||
await printer.SetRedColor(command.IsRed);
|
||||
if (useDelay) await Task.Delay(delayMs);
|
||||
|
||||
await printer.SetEmphasized(command.IsBold);
|
||||
if (useDelay) await Task.Delay(delayMs);
|
||||
|
||||
await printer.PrintTextAsync(command.Text + "\n");
|
||||
if (useDelay) await Task.Delay(delayMs);
|
||||
}
|
||||
|
||||
await printer.FeedLinesAsync(10);
|
||||
if (useDelay) await Task.Delay(delayMs * 5);
|
||||
await printer.CutAsync();
|
||||
}
|
||||
|
||||
public static async Task PrintKitchenCommandsToHtmlPrinterAsync(
|
||||
HtmlPrinter printer,
|
||||
IEnumerable<PrintCommand> commands)
|
||||
{
|
||||
await printer.FeedLinesAsync(1);
|
||||
await printer.SetCustomLineSpacing(22);
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
if (command.IsCut)
|
||||
{
|
||||
await printer.CutAsync(false);
|
||||
continue;
|
||||
}
|
||||
if (command.IsBig)
|
||||
await printer.SetFontSizeAsync(2, 1);
|
||||
else
|
||||
await printer.SetFontSizeAsync(1, 1);
|
||||
|
||||
await printer.SetRedColor(command.IsRed);
|
||||
await printer.SetEmphasized(command.IsBold);
|
||||
await printer.PrintTextAsync(command.Text + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Console Output
|
||||
|
||||
public static void PrintCommandsToConsole(IEnumerable<PrintCommand> commands)
|
||||
{
|
||||
Console.WriteLine("=== PRINT COMMANDS ===\n");
|
||||
foreach (var command in commands)
|
||||
{
|
||||
string attributes = "";
|
||||
if (command.IsBig) attributes += "[BIG] ";
|
||||
if (command.IsBold) attributes += "[BOLD] ";
|
||||
if (command.IsRed) attributes += "[RED] ";
|
||||
|
||||
Console.WriteLine($"{attributes}{command.Text}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Data Builders
|
||||
|
||||
public static string BuildKitchenReceiptJson()
|
||||
{
|
||||
var receipt = new KitchenReceipt
|
||||
{
|
||||
Title = "Warme Küche",
|
||||
TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
|
||||
ReceiptNumber = "132018166",
|
||||
WaiterName = "Mariano Amato",
|
||||
WaiterId = "32 (VK Restaurant)",
|
||||
TableNumber = "22"
|
||||
};
|
||||
|
||||
receipt.Gangs.Add(new Gang(1, "Gang"));
|
||||
receipt.Gangs.Add(new Gang(2, "Gang"));
|
||||
|
||||
receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")
|
||||
{
|
||||
Modifications = new DishModifications
|
||||
{
|
||||
Removed = new List<string> { "Wasabi" },
|
||||
Added = new List<string> { "Extra Ginger" }
|
||||
},
|
||||
Comment = "No soy sauce",
|
||||
GuestId = 1
|
||||
});
|
||||
receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
|
||||
|
||||
receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi") { GuestId = 1 });
|
||||
receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
|
||||
|
||||
return SerializeWithComputedProps(receipt);
|
||||
}
|
||||
|
||||
public static string BuildKitchenReceiptNextDishJson()
|
||||
{
|
||||
var receipt = new KitchenReceipt
|
||||
{
|
||||
Title = "Warme Küche",
|
||||
TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
|
||||
ReceiptNumber = "132018166",
|
||||
WaiterName = "Mariano Amato",
|
||||
WaiterId = "32 (VK Restaurant)",
|
||||
TableNumber = "22",
|
||||
SpecialInstruction = "Gang schicken"
|
||||
};
|
||||
|
||||
receipt.Gangs.Add(new Gang(2, "Gang"));
|
||||
|
||||
return SerializeWithComputedProps(receipt);
|
||||
}
|
||||
|
||||
public static string BuildFinalReceiptJson(bool includeTax = true)
|
||||
{
|
||||
var receipt = new FinalReceipt
|
||||
{
|
||||
CompanyName = "Klingler Gastro AG",
|
||||
Address1 = "Münzplatz 3",
|
||||
Address2 = "CH-8001 Zürich",
|
||||
Phone = "043 321 22 22",
|
||||
ReceiptNumber = null,
|
||||
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.",
|
||||
IsDebtor = true,
|
||||
SplitPayments = new List<SplitPaymentInfo>
|
||||
{
|
||||
new() { PaymentMethod = "Cash", Amount = 50.00m, Currency = "CHF" },
|
||||
new() { PaymentMethod = "Card", Amount = 110.00m, Currency = "CHF" }
|
||||
},
|
||||
TerminalReceipts = new List<PaymentTerminalReceipt>
|
||||
{
|
||||
new()
|
||||
{
|
||||
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"
|
||||
},
|
||||
new()
|
||||
{
|
||||
ReceiptType = "*** Kundenbeleg ***",
|
||||
BookingType = "Buchung",
|
||||
PaymentSystem = "MASTER",
|
||||
TransactionNumber = "XXXXXXXXXXXXXXX2587",
|
||||
TransactionDateTime = new DateTime(2025, 11, 11, 12, 36, 12),
|
||||
TerminalId = "31108834",
|
||||
AID = "A0000000041010",
|
||||
TransactionSeqCount = "6128",
|
||||
TransactionRefNo = "99036644600",
|
||||
AuthCode = "1a4b2c",
|
||||
AcquirerId = "1",
|
||||
EftAmount = 93.00m,
|
||||
TipAmount = 0.00m,
|
||||
TotalEftAmount = 93.00m,
|
||||
Currency = "CHF"
|
||||
}
|
||||
},
|
||||
DiscountInfo = new DiscountInfo()
|
||||
{
|
||||
Amount = -50.00m,
|
||||
Currency = "CHF",
|
||||
Description = "Fine Dine",
|
||||
}
|
||||
};
|
||||
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "San Pellegrino 50cl",
|
||||
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "Panna 50cl",
|
||||
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "An item with really long description that should wrap",
|
||||
UnitPrice = 5.50m, TotalPrice = 5.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Business Lunch Menu Seco",
|
||||
UnitPrice = 44.00m, TotalPrice = 88.00m, TaxCategory = "A",
|
||||
SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Brunello di Montalcino 1",
|
||||
UnitPrice = 16.00m, TotalPrice = 32.00m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Espresso",
|
||||
UnitPrice = 5.50m, TotalPrice = 11.00m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new FinalReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "Tip",
|
||||
UnitPrice = 10.50m, TotalPrice = 10.50m, TaxCategory = "B"
|
||||
});
|
||||
|
||||
if (includeTax)
|
||||
{
|
||||
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"
|
||||
});
|
||||
}
|
||||
|
||||
return SerializeWithComputedProps(receipt);
|
||||
}
|
||||
|
||||
public static string BuildInvoiceReceiptJson()
|
||||
{
|
||||
var receipt = new InvoiceReceipt
|
||||
{
|
||||
CompanyName = "Klingler Gastro AG",
|
||||
Address1 = "Münzplatz 3",
|
||||
Address2 = "CH-8001 Zürich",
|
||||
Phone = "043 321 22 22",
|
||||
ReceiptNumber = null,
|
||||
DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
|
||||
Guests = 2,
|
||||
Total = 160.00m,
|
||||
Currency = "CHF",
|
||||
TableNumber = "12",
|
||||
ThankYouMessage = "Thank you!"
|
||||
};
|
||||
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "San Pellegrino 50cl",
|
||||
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "Panna 50cl",
|
||||
UnitPrice = 6.50m, TotalPrice = 6.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "Granini Tomatensaft",
|
||||
UnitPrice = 5.50m, TotalPrice = 5.50m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Business Lunch Menu Seco",
|
||||
UnitPrice = 44.00m, TotalPrice = 88.00m, TaxCategory = "A",
|
||||
SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Brunello di Montalcino 1",
|
||||
UnitPrice = 16.00m, TotalPrice = 32.00m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 2, Description = "Espresso",
|
||||
UnitPrice = 5.50m, TotalPrice = 11.00m, TaxCategory = "A"
|
||||
});
|
||||
receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
|
||||
{
|
||||
Quantity = 1, Description = "Tip",
|
||||
UnitPrice = 10.50m, TotalPrice = 10.50m, TaxCategory = "B"
|
||||
});
|
||||
|
||||
return SerializeWithComputedProps(receipt);
|
||||
}
|
||||
|
||||
public static string BuildOrderItemsJson()
|
||||
{
|
||||
var receipt = 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<OrderItem>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Number = 1, Name = "pappara", Quantity = 1,
|
||||
SubItems = new List<string> { "pizza", "cola" },
|
||||
Comment = "Cola zero please"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Number = 2, Name = "Classic Beef Burger", Quantity = 1,
|
||||
Modifications = new ItemModifications
|
||||
{
|
||||
Removed = new List<string> { "Onion" },
|
||||
Added = new List<string> { "butter" }
|
||||
},
|
||||
Comment = "Medium rare please"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Number = 3, Name = "Margherita Pizza Classic",
|
||||
Quantity = 2, Size = "L"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SerializeWithComputedProps(receipt);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computed Properties
|
||||
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true };
|
||||
|
||||
private static string SerializeWithComputedProps(object receipt)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(receipt, SerializerOptions);
|
||||
var node = JsonNode.Parse(json)!;
|
||||
|
||||
switch (receipt)
|
||||
{
|
||||
case KitchenReceipt kr:
|
||||
AddKitchenComputedProps(node, kr);
|
||||
break;
|
||||
case FinalReceipt fr:
|
||||
AddFinalReceiptComputedProps(node, fr);
|
||||
break;
|
||||
case InvoiceReceipt ir:
|
||||
AddInvoiceComputedProps(node, ir);
|
||||
break;
|
||||
case OrderItemsReceipt or:
|
||||
AddOrderItemsComputedProps(node, or);
|
||||
break;
|
||||
}
|
||||
|
||||
return node.ToJsonString(SerializerOptions);
|
||||
}
|
||||
|
||||
private static void AddKitchenComputedProps(JsonNode node, KitchenReceipt receipt)
|
||||
{
|
||||
node["HasGangs"] = receipt.Gangs.Count > 0;
|
||||
node["HasDishes"] = receipt.Dishes.Count > 0;
|
||||
|
||||
// Add GuestPrefix and HasModifications to dishes in gangs
|
||||
var gangsArray = node["Gangs"]?.AsArray();
|
||||
if (gangsArray != null)
|
||||
{
|
||||
for (int g = 0; g < receipt.Gangs.Count; g++)
|
||||
{
|
||||
var gangDishes = gangsArray[g]?["Dishes"]?.AsArray();
|
||||
if (gangDishes != null)
|
||||
{
|
||||
for (int d = 0; d < receipt.Gangs[g].Dishes.Count; d++)
|
||||
{
|
||||
var dish = receipt.Gangs[g].Dishes[d];
|
||||
gangDishes[d]!["GuestPrefix"] = dish.GuestId.HasValue ? $"{dish.GuestId} " : "";
|
||||
|
||||
var mods = dish.Modifications;
|
||||
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
|
||||
if (gangDishes[d]!["Modifications"] == null)
|
||||
gangDishes[d]!["Modifications"] = new JsonObject();
|
||||
gangDishes[d]!["Modifications"]!["HasModifications"] = hasMods;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add GuestPrefix and HasModifications to top-level dishes
|
||||
var dishesArray = node["Dishes"]?.AsArray();
|
||||
if (dishesArray != null)
|
||||
{
|
||||
for (int d = 0; d < receipt.Dishes.Count; d++)
|
||||
{
|
||||
var dish = receipt.Dishes[d];
|
||||
dishesArray[d]!["GuestPrefix"] = dish.GuestId.HasValue ? $"{dish.GuestId} " : "";
|
||||
|
||||
var mods = dish.Modifications;
|
||||
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
|
||||
if (dishesArray[d]!["Modifications"] == null)
|
||||
dishesArray[d]!["Modifications"] = new JsonObject();
|
||||
dishesArray[d]!["Modifications"]!["HasModifications"] = hasMods;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddFinalReceiptComputedProps(JsonNode node, FinalReceipt receipt)
|
||||
{
|
||||
node["ReceiptLabel"] = receipt.ReceiptNumber != null
|
||||
? $"Rechnung Nr. {receipt.ReceiptNumber}"
|
||||
: "";
|
||||
|
||||
node["HasSplitPayments"] = receipt.SplitPayments.Count > 0;
|
||||
node["HasTaxableCategories"] = receipt.TaxBreakdown.Any(t =>
|
||||
!string.Equals(t.Category, "d", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var itemsArray = node["Items"]?.AsArray();
|
||||
if (itemsArray != null)
|
||||
{
|
||||
for (int i = 0; i < receipt.Items.Count; i++)
|
||||
{
|
||||
var item = receipt.Items[i];
|
||||
itemsArray[i]!["PriceDisplay"] =
|
||||
$"{item.UnitPrice:F2}" +
|
||||
$"{item.TotalPrice:F2}".PadLeft(7) +
|
||||
$" {item.TaxCategory}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddInvoiceComputedProps(JsonNode node, InvoiceReceipt receipt)
|
||||
{
|
||||
node["ReceiptLabel"] = receipt.ReceiptNumber != null
|
||||
? $"Rechnung Nr. {receipt.ReceiptNumber}"
|
||||
: "";
|
||||
|
||||
var itemsArray = node["Items"]?.AsArray();
|
||||
if (itemsArray != null)
|
||||
{
|
||||
for (int i = 0; i < receipt.Items.Count; i++)
|
||||
{
|
||||
var item = receipt.Items[i];
|
||||
itemsArray[i]!["PriceDisplay"] =
|
||||
$"{item.UnitPrice:F2}" +
|
||||
$"{item.TotalPrice:F2}".PadLeft(7) +
|
||||
$" {item.TaxCategory}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddOrderItemsComputedProps(JsonNode node, OrderItemsReceipt receipt)
|
||||
{
|
||||
var itemsArray = node["Items"]?.AsArray();
|
||||
if (itemsArray != null)
|
||||
{
|
||||
for (int i = 0; i < receipt.Items.Count; i++)
|
||||
{
|
||||
var item = receipt.Items[i];
|
||||
itemsArray[i]!["SizePart"] = !string.IsNullOrEmpty(item.Size)
|
||||
? item.Size + " "
|
||||
: "";
|
||||
|
||||
var mods = item.Modifications;
|
||||
bool hasMods = mods != null && (mods.Removed.Count > 0 || mods.Added.Count > 0);
|
||||
if (itemsArray[i]!["Modifications"] == null)
|
||||
itemsArray[i]!["Modifications"] = new JsonObject();
|
||||
itemsArray[i]!["Modifications"]!["HasModifications"] = hasMods;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
BIN
EpsonTest.Templates/ristorante-klinglers.ch-logo.png
Normal file
BIN
EpsonTest.Templates/ristorante-klinglers.ch-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
EpsonTest.Templates/ristorante-klinglers.ch-logo_white_bg.png
Normal file
BIN
EpsonTest.Templates/ristorante-klinglers.ch-logo_white_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user