add money return / credit note receipt type with HTML test
This commit is contained in:
@@ -3,9 +3,28 @@ using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt;
|
|||||||
using Inspectron.Epson.PrintServer.Printers.Utils.FinalReceipt;
|
using Inspectron.Epson.PrintServer.Printers.Utils.FinalReceipt;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
|
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
|
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
|
||||||
|
using Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
|
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
|
// Non-interactive mode: `dotnet run -- <receiptType> [html|epson]`
|
||||||
|
// receiptType: kitchen | final | invoice | bar | orderitems | moneyreturn (or 0-5)
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
int rt = ParseReceiptTypeArg(args[0]);
|
||||||
|
if (rt < 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Unknown receipt type: {args[0]}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pt = args.Length > 1 && args[1].Equals("epson", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
|
||||||
|
Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {(pt == 0 ? "HTML" : "Epson")} printer...\n");
|
||||||
|
await RunTest(rt, pt);
|
||||||
|
Console.WriteLine("\nDone.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
@@ -18,10 +37,11 @@ while (true)
|
|||||||
"InvoiceReceipt",
|
"InvoiceReceipt",
|
||||||
"BarReceipt",
|
"BarReceipt",
|
||||||
"OrderItems",
|
"OrderItems",
|
||||||
|
"MoneyReturnReceipt",
|
||||||
"Exit"
|
"Exit"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (receiptType == 5) break;
|
if (receiptType == 6) break;
|
||||||
|
|
||||||
var printerTarget = ShowMenu("Select printer target:", new[]
|
var printerTarget = ShowMenu("Select printer target:", new[]
|
||||||
{
|
{
|
||||||
@@ -96,9 +116,21 @@ static string GetReceiptTypeName(int index) => index switch
|
|||||||
2 => "InvoiceReceipt",
|
2 => "InvoiceReceipt",
|
||||||
3 => "BarReceipt",
|
3 => "BarReceipt",
|
||||||
4 => "OrderItems",
|
4 => "OrderItems",
|
||||||
|
5 => "MoneyReturnReceipt",
|
||||||
_ => "Unknown"
|
_ => "Unknown"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ParseReceiptTypeArg(string arg) => arg.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"0" or "kitchen" or "kitchenreceipt" => 0,
|
||||||
|
"1" or "final" or "finalreceipt" => 1,
|
||||||
|
"2" or "invoice" or "invoicereceipt" => 2,
|
||||||
|
"3" or "bar" or "barreceipt" => 3,
|
||||||
|
"4" or "orderitems" => 4,
|
||||||
|
"5" or "moneyreturn" or "moneyreturnreceipt" or "refund" or "creditnote" => 5,
|
||||||
|
_ => -1
|
||||||
|
};
|
||||||
|
|
||||||
static async Task RunTest(int receiptType, int printerTarget)
|
static async Task RunTest(int receiptType, int printerTarget)
|
||||||
{
|
{
|
||||||
switch (receiptType)
|
switch (receiptType)
|
||||||
@@ -108,6 +140,7 @@ static async Task RunTest(int receiptType, int printerTarget)
|
|||||||
case 2: await RunInvoiceReceiptTest(printerTarget); break;
|
case 2: await RunInvoiceReceiptTest(printerTarget); break;
|
||||||
case 3: await RunBarReceiptTest(printerTarget); break;
|
case 3: await RunBarReceiptTest(printerTarget); break;
|
||||||
case 4: await RunOrderItemsTest(printerTarget); break;
|
case 4: await RunOrderItemsTest(printerTarget); break;
|
||||||
|
case 5: await RunMoneyReturnReceiptTest(printerTarget); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,3 +268,29 @@ static async Task RunOrderItemsTest(int printerTarget)
|
|||||||
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
|
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async Task RunMoneyReturnReceiptTest(int printerTarget)
|
||||||
|
{
|
||||||
|
var receipt = TestHelpers.BuildSampleMoneyReturnReceipt();
|
||||||
|
var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
|
||||||
|
var converter = new MoneyReturnReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
|
||||||
|
var printCommands = converter.Convert(serializedReceipt);
|
||||||
|
|
||||||
|
TestHelpers.PrintCommandsToConsole(printCommands);
|
||||||
|
|
||||||
|
if (printerTarget == 0)
|
||||||
|
{
|
||||||
|
var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\money_return_test.html");
|
||||||
|
await TestHelpers.PrintCommandsToHtmlPrinterAsync(
|
||||||
|
printer,
|
||||||
|
printCommands,
|
||||||
|
logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
|
||||||
|
Console.WriteLine("Output written to: money_return_test.html");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var printer = await TestHelpers.CreateEpsonPrinterAsync();
|
||||||
|
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt;
|
|||||||
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
|
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
|
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
|
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
|
||||||
|
using Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
|
||||||
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
|
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
|
||||||
|
|
||||||
namespace EpsonTest;
|
namespace EpsonTest;
|
||||||
@@ -462,6 +463,66 @@ public static class TestHelpers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mirrors money_return_receipt_data.json plus the credit-note specific fields
|
||||||
|
// shown in money_return_receipt.jpg (original invoice reference, refund type, tip).
|
||||||
|
public static MoneyReturnReceipt BuildSampleMoneyReturnReceipt()
|
||||||
|
{
|
||||||
|
var receipt = new MoneyReturnReceipt
|
||||||
|
{
|
||||||
|
CompanyName = "Big Mac Bistro",
|
||||||
|
Address1 = "Zelena 186",
|
||||||
|
Address2 = "79000 Lviv",
|
||||||
|
Phone = "080 039 47 69",
|
||||||
|
ReceiptNumber = "25",
|
||||||
|
DateTime = new DateTime(2026, 7, 4, 11, 8, 13),
|
||||||
|
Guests = 1,
|
||||||
|
Total = 20.00m,
|
||||||
|
Currency = "CHF",
|
||||||
|
PaymentMethod = "Cash",
|
||||||
|
PaymentAmount = 13.00m,
|
||||||
|
WaiterName = "Ronald McDonald",
|
||||||
|
VatNumber = " MWST",
|
||||||
|
ThankYouMessage = "Thank you for your order!",
|
||||||
|
GoodbyeMessageLine1 = "Auf Wiedersehen.",
|
||||||
|
GoodbyeMessageLine2 = "Powered by James",
|
||||||
|
// Credit-note specific fields
|
||||||
|
OriginalInvoiceNumber = "773",
|
||||||
|
OriginalDateTime = new DateTime(2026, 7, 4, 11, 7, 0),
|
||||||
|
RefundType = "Full refund",
|
||||||
|
Tip = 7.00m
|
||||||
|
};
|
||||||
|
|
||||||
|
receipt.Items.Add(new MoneyReturnReceiptItem
|
||||||
|
{
|
||||||
|
Quantity = 1,
|
||||||
|
Description = "Cloudy Bay Sauvignon Blanc 2024",
|
||||||
|
UnitPrice = 13.00m,
|
||||||
|
TotalPrice = 13.00m,
|
||||||
|
TaxCategory = "D"
|
||||||
|
});
|
||||||
|
|
||||||
|
receipt.Items.Add(new MoneyReturnReceiptItem
|
||||||
|
{
|
||||||
|
Quantity = 1,
|
||||||
|
Description = "Trinkgeld",
|
||||||
|
UnitPrice = 7.00m,
|
||||||
|
TotalPrice = 7.00m,
|
||||||
|
TaxCategory = "D"
|
||||||
|
});
|
||||||
|
|
||||||
|
receipt.TaxBreakdown.Add(new MoneyReturnTaxInfo
|
||||||
|
{
|
||||||
|
Category = "D",
|
||||||
|
Rate = 0m,
|
||||||
|
Gross = 20.00m,
|
||||||
|
Net = 20.00m,
|
||||||
|
TaxAmount = 0.00m,
|
||||||
|
Currency = "CHF"
|
||||||
|
});
|
||||||
|
|
||||||
|
return receipt;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Print Helpers
|
#region Print Helpers
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
namespace Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data model for a refund / credit note ("money return") receipt.
|
||||||
|
/// Mirrors the sale receipt payload (see money_return_receipt_data.json) and adds
|
||||||
|
/// the credit-note specific fields that reference the original invoice being refunded.
|
||||||
|
/// </summary>
|
||||||
|
public class MoneyReturnReceipt
|
||||||
|
{
|
||||||
|
public string CompanyName { get; set; }
|
||||||
|
public string Address1 { get; set; }
|
||||||
|
public string Address2 { get; set; }
|
||||||
|
public string Phone { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Credit note number (shown as "Credit note No. {ReceiptNumber}").</summary>
|
||||||
|
public string? ReceiptNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Date/time the credit note was issued.</summary>
|
||||||
|
public DateTime DateTime { get; set; }
|
||||||
|
|
||||||
|
public int Guests { get; set; }
|
||||||
|
public List<MoneyReturnReceiptItem> Items { get; set; } = new List<MoneyReturnReceiptItem>();
|
||||||
|
|
||||||
|
/// <summary>Refunded amount (positive). Rendered negative on the receipt.</summary>
|
||||||
|
public decimal Total { get; set; }
|
||||||
|
public string Currency { get; set; }
|
||||||
|
|
||||||
|
public decimal? TotalInAlternateCurrency { get; set; }
|
||||||
|
public string AlternateCurrency { get; set; }
|
||||||
|
|
||||||
|
public List<MoneyReturnSplitPaymentInfo> SplitPayments { get; set; } = new List<MoneyReturnSplitPaymentInfo>();
|
||||||
|
|
||||||
|
/// <summary>Method the original payment was made with (e.g. "Cash").</summary>
|
||||||
|
public string PaymentMethod { get; set; }
|
||||||
|
public decimal PaymentAmount { get; set; }
|
||||||
|
|
||||||
|
public List<MoneyReturnTaxInfo> TaxBreakdown { get; set; } = new List<MoneyReturnTaxInfo>();
|
||||||
|
|
||||||
|
public bool IsDebtor { get; set; } = false;
|
||||||
|
public string WaiterName { get; set; }
|
||||||
|
public string Terminal { get; set; }
|
||||||
|
public string TableNumber { get; set; }
|
||||||
|
public string VatNumber { get; set; }
|
||||||
|
|
||||||
|
public string ThankYouMessage { get; set; }
|
||||||
|
public string GoodbyeMessageLine1 { get; set; }
|
||||||
|
public string GoodbyeMessageLine2 { get; set; }
|
||||||
|
|
||||||
|
public List<MoneyReturnPaymentTerminalReceipt> TerminalReceipts { get; set; } = new List<MoneyReturnPaymentTerminalReceipt>();
|
||||||
|
public MoneyReturnDiscountInfo? DiscountInfo { get; set; }
|
||||||
|
|
||||||
|
// --- Credit-note specific fields ---
|
||||||
|
|
||||||
|
/// <summary>Number of the original invoice this credit note refunds ("Orig. invoice No.").</summary>
|
||||||
|
public string? OriginalInvoiceNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Date/time of the original invoice ("Orig. date").</summary>
|
||||||
|
public DateTime? OriginalDateTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Refund type, e.g. "Full refund" or "Partial refund" ("Type").</summary>
|
||||||
|
public string? RefundType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Tip amount included in the refund. Shown as "incl. tip" when non-zero.</summary>
|
||||||
|
public decimal Tip { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoneyReturnReceiptItem
|
||||||
|
{
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public decimal UnitPrice { get; set; }
|
||||||
|
public decimal TotalPrice { get; set; }
|
||||||
|
public string TaxCategory { get; set; }
|
||||||
|
public List<string> SubItems { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoneyReturnTaxInfo
|
||||||
|
{
|
||||||
|
public string Category { get; set; }
|
||||||
|
public decimal Rate { get; set; }
|
||||||
|
public decimal Gross { get; set; }
|
||||||
|
public decimal Net { get; set; }
|
||||||
|
public decimal TaxAmount { get; set; }
|
||||||
|
public string Currency { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoneyReturnSplitPaymentInfo
|
||||||
|
{
|
||||||
|
public string PaymentMethod { get; set; }
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
public string Currency { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoneyReturnDiscountInfo
|
||||||
|
{
|
||||||
|
public string Description { get; set; }
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
public string Currency { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoneyReturnPaymentTerminalReceipt
|
||||||
|
{
|
||||||
|
public string ReceiptType { get; set; }
|
||||||
|
public string BookingType { get; set; }
|
||||||
|
public string PaymentSystem { get; set; }
|
||||||
|
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; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
|
||||||
|
|
||||||
|
public class MoneyReturnReceiptConverter : IReceiptConverter
|
||||||
|
{
|
||||||
|
private readonly int _lineWidth;
|
||||||
|
private readonly int _bigFontLineWidth;
|
||||||
|
|
||||||
|
public MoneyReturnReceiptConverter(int lineWidth, int bigFontLineWidth)
|
||||||
|
{
|
||||||
|
_lineWidth = lineWidth;
|
||||||
|
_bigFontLineWidth = bigFontLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PrintCommand> Convert(string jsonContent)
|
||||||
|
{
|
||||||
|
var receipt = JsonSerializer.Deserialize<MoneyReturnReceipt>(jsonContent);
|
||||||
|
var converter = new ReceiptConverter(_lineWidth, _bigFontLineWidth);
|
||||||
|
return converter.ConvertToPrintCommands(receipt);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
namespace Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the print command list for a refund / credit note receipt.
|
||||||
|
/// Layout follows money_return_receipt.jpg: company header, "Refund / Credit note"
|
||||||
|
/// title, credit note + original invoice reference block, the negative credit total,
|
||||||
|
/// the (negated) VAT breakdown and the goodbye footer.
|
||||||
|
/// </summary>
|
||||||
|
public class ReceiptConverter
|
||||||
|
{
|
||||||
|
private readonly int _lineWidth;
|
||||||
|
private readonly int _bigFontLineWidth;
|
||||||
|
|
||||||
|
public ReceiptConverter(int lineWidth = 48, int bigFontLineWidth = 24)
|
||||||
|
{
|
||||||
|
_lineWidth = lineWidth;
|
||||||
|
_bigFontLineWidth = bigFontLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PrintCommand> ConvertToPrintCommands(MoneyReturnReceipt receipt)
|
||||||
|
{
|
||||||
|
var commands = new List<PrintCommand>();
|
||||||
|
|
||||||
|
// Header - Company info
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.CompanyName, false)));
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.Address1, false)));
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.Address2, false)));
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.Phone, false)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Title between separators
|
||||||
|
commands.Add(new PrintCommand(new string('-', _lineWidth)));
|
||||||
|
commands.Add(new PrintCommand(Center("Refund / Credit note", false), isBold: true));
|
||||||
|
commands.Add(new PrintCommand(new string('-', _lineWidth)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Credit note number + issue date
|
||||||
|
string creditNoteLabel = receipt.ReceiptNumber != null
|
||||||
|
? $"Credit note No. {receipt.ReceiptNumber}"
|
||||||
|
: "Credit note";
|
||||||
|
commands.Add(new PrintCommand(Justify(creditNoteLabel, $"{receipt.DateTime:HH:mm dd.MM.yyyy}")));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Original invoice reference block
|
||||||
|
commands.Add(new PrintCommand(Justify("Orig. invoice No.:", receipt.OriginalInvoiceNumber ?? "")));
|
||||||
|
if (receipt.OriginalDateTime.HasValue)
|
||||||
|
commands.Add(new PrintCommand(Justify("Orig. date:", $"{receipt.OriginalDateTime:HH:mm dd.MM.yyyy}")));
|
||||||
|
commands.Add(new PrintCommand(Justify("Orig. payment method:", receipt.PaymentMethod ?? "")));
|
||||||
|
if (!string.IsNullOrEmpty(receipt.RefundType))
|
||||||
|
commands.Add(new PrintCommand(Justify("Type:", receipt.RefundType)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
commands.Add(new PrintCommand(new string('-', _lineWidth)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Included tip
|
||||||
|
if (receipt.Tip != 0)
|
||||||
|
{
|
||||||
|
commands.Add(new PrintCommand($"incl. tip {receipt.Currency}: {receipt.Tip:F2}".PadLeft(_lineWidth)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit total (refund is shown as a negative amount), big + bold, centered
|
||||||
|
string creditLine = $"Credit: {-receipt.Total:F2} {receipt.Currency}";
|
||||||
|
commands.Add(new PrintCommand(Center(creditLine, true), true, true));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Alternate currency
|
||||||
|
if (receipt.TotalInAlternateCurrency.HasValue)
|
||||||
|
{
|
||||||
|
string altCurrencyLine = $"{-receipt.TotalInAlternateCurrency:F2} {receipt.AlternateCurrency}";
|
||||||
|
commands.Add(new PrintCommand(altCurrencyLine.PadLeft(_lineWidth)));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund payment method line (e.g. "Cash: -20.00 CHF")
|
||||||
|
if (receipt.SplitPayments != null && receipt.SplitPayments.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var split in receipt.SplitPayments)
|
||||||
|
commands.Add(new PrintCommand($"{split.PaymentMethod}: {-split.Amount:F2} {split.Currency}".PadLeft(_lineWidth)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commands.Add(new PrintCommand($"{receipt.PaymentMethod}: {-receipt.Total:F2} {receipt.Currency}".PadLeft(_lineWidth)));
|
||||||
|
}
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Tax breakdown (amounts negated for the refund)
|
||||||
|
foreach (var tax in receipt.TaxBreakdown)
|
||||||
|
{
|
||||||
|
if (receipt.TaxBreakdown.IndexOf(tax) == 0)
|
||||||
|
{
|
||||||
|
string taxHeader = "VAT %".PadRight(_lineWidth / 4)
|
||||||
|
+ "Gross".PadLeft(_lineWidth / 4)
|
||||||
|
+ "Net".PadLeft(_lineWidth / 4)
|
||||||
|
+ "VAT".PadLeft(_lineWidth / 4);
|
||||||
|
commands.Add(new PrintCommand(taxHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
string taxDetail = ($"{tax.Category}:" + $"{tax.Rate}%".PadLeft(5)).PadRight(_lineWidth / 4)
|
||||||
|
+ $"{-tax.Gross:F2} {tax.Currency}".PadLeft(_lineWidth / 4)
|
||||||
|
+ $"{-tax.Net:F2} {tax.Currency}".PadLeft(_lineWidth / 4)
|
||||||
|
+ $"{-tax.TaxAmount:F2} {tax.Currency}".PadLeft(_lineWidth / 4);
|
||||||
|
commands.Add(new PrintCommand(taxDetail));
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
if (receipt.TaxBreakdown.Count(x => x.Category != null && x.Category.ToLower() != "d") == 0)
|
||||||
|
{
|
||||||
|
commands.Add(new PrintCommand("Not subject to value added tax"));
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
commands.Add(new PrintCommand(""));
|
||||||
|
|
||||||
|
// Footer / goodbye
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.ThankYouMessage, false)));
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.GoodbyeMessageLine1, false)));
|
||||||
|
commands.Add(new PrintCommand(Center(receipt.GoodbyeMessageLine2, false)));
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Justify(string left, string right)
|
||||||
|
{
|
||||||
|
left ??= "";
|
||||||
|
right ??= "";
|
||||||
|
|
||||||
|
int spaces = _lineWidth - left.Length - right.Length;
|
||||||
|
if (spaces < 1) spaces = 1;
|
||||||
|
|
||||||
|
return left + new string(' ', spaces) + right;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ public class ReceiptConverterFactory : IReceiptConverterFactory
|
|||||||
EReceiptType.NextCourse => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20),
|
EReceiptType.NextCourse => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20),
|
||||||
EReceiptType.OrdersOverview => new OrderItemsReceiptConverter(48, 24),
|
EReceiptType.OrdersOverview => new OrderItemsReceiptConverter(48, 24),
|
||||||
EReceiptType.Invoice => new InvoiceReceiptConverter(48, 24),
|
EReceiptType.Invoice => new InvoiceReceiptConverter(48, 24),
|
||||||
|
EReceiptType.MoneyReturn => new MoneyReturnReceipt.MoneyReturnReceiptConverter(48, 24),
|
||||||
_ => throw new ArgumentException($"Unknown receipt type: {receiptType}")
|
_ => throw new ArgumentException($"Unknown receipt type: {receiptType}")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -30,6 +31,7 @@ public class ReceiptConverterFactory : IReceiptConverterFactory
|
|||||||
WorkareaTicket,
|
WorkareaTicket,
|
||||||
NextCourse,
|
NextCourse,
|
||||||
OrdersOverview,
|
OrdersOverview,
|
||||||
Invoice
|
Invoice,
|
||||||
|
MoneyReturn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
money_return_receipt.jpg
Normal file
BIN
money_return_receipt.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
54
money_return_receipt_data.json
Normal file
54
money_return_receipt_data.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"TotalInAlternateCurrency":null,
|
||||||
|
"AlternateCurrency":"",
|
||||||
|
"SplitPayments":null,
|
||||||
|
"PaymentMethod":"Cash",
|
||||||
|
"PaymentAmount":13,
|
||||||
|
"TaxBreakdown":[
|
||||||
|
{
|
||||||
|
"Category":"D",
|
||||||
|
"Rate":0,
|
||||||
|
"Gross":20,
|
||||||
|
"Net":20,
|
||||||
|
"TaxAmount":0,
|
||||||
|
"Currency":"CHF"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"WaiterName":"Ronald McDonald",
|
||||||
|
"Terminal":null,
|
||||||
|
"VatNumber":" MWST",
|
||||||
|
"GoodbyeMessageLine1":"Auf Wiedersehen.",
|
||||||
|
"GoodbyeMessageLine2":"Powered by James",
|
||||||
|
"TerminalReceipts":null,
|
||||||
|
"IsDebtor":false,
|
||||||
|
"DiscountInfo":null,
|
||||||
|
"CompanyName":"Big Mac Bistro",
|
||||||
|
"Address1":"Zelena 186",
|
||||||
|
"Address2":"79000 Lviv",
|
||||||
|
"Phone":"080 039 47 69",
|
||||||
|
"ReceiptNumber":"25",
|
||||||
|
"DateTime":"2026-07-04T11:08:13.861",
|
||||||
|
"Guests":1,
|
||||||
|
"Items":[
|
||||||
|
{
|
||||||
|
"Quantity":1,
|
||||||
|
"Description":"Cloudy Bay Sauvignon Blanc 2024",
|
||||||
|
"UnitPrice":13,
|
||||||
|
"TotalPrice":13,
|
||||||
|
"TaxCategory":"D",
|
||||||
|
"SubItems":null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Quantity":1,
|
||||||
|
"Description":"Trinkgeld",
|
||||||
|
"UnitPrice":7,
|
||||||
|
"TotalPrice":7,
|
||||||
|
"TaxCategory":"D",
|
||||||
|
"SubItems":null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Total":20,
|
||||||
|
"Currency":"CHF",
|
||||||
|
"ThankYouMessage":"Thank you for your order!",
|
||||||
|
"TableNumber":null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user