private void PrintReceipt(PosEventSignResult result) { StringBuilder sb = new StringBuilder(); try { p.RecLetterQuality = true; p.SetBitmap(1, PrinterStation.Receipt, "..\\..\\Resources\\outpost_logo_receipt.bmp", p.RecLineWidth, PosPrinter.PrinterBitmapCenter); sb.Append(PrintCommands.bitmap_1); sb.Append(PrintCommands.center); // TODO: Address + VAT number. sb.Append(PrintCommands.double_size + "VAT RECEIPT\n"); sb.Append(PrintCommands.reset); sb.Append(string.Concat(Enumerable.Repeat("-", p.RecLineChars))); // TODO sb.Append(PrintCommands.feed_cut); p.PrintNormal(PrinterStation.Receipt, sb.ToString()); } catch (PosControlException e) { Debug.WriteLine("Point of sale control exception: {0}", e); if (e.ErrorCode == ErrorCode.Extended) { Debug.WriteLine("Extended: ", e.ErrorCodeExtended); } } }
private void HashAndSignCallback(IAsyncResult ar) { try { PosEventSignResult result = c.EndHashAndSign(ar); if (result != null) { if (result.HasErrors == true) { foreach (Error e in result.Errors) { Debug.WriteLine(e.ToString()); } } else { // The hash and sign was successful, show a receipt like form. Debug.WriteLine("The hash and sign callback was successful!"); if (result.HasSignature) { Debug.WriteLine("Signature: {0}", result.Signature); } if (result.IsClocking) { Debug.WriteLine("Clocking event: {0}", result.ClockingType); } Debug.WriteLine("Receipt printing mode: {0}", result.VATReceiptPrintingMode); foreach (VATSplit s in result.VATSplit) { Debug.WriteLine(s.ToString()); } PrintReceipt(result); } // Start the next transaction. // We allow clocking in the middle of another transaction in this example, for a real-world POS // you need to beware of transaction numbers. Don't create gaps or duplicate numbers if you do this! //if(result.IsClocking == false) InitializeTransaction(); } } catch (HashAndSignException ex) { // The InnerException of the HashAndSignException might contain information to help troubleshoot the issue. Debug.WriteLine("Error: " + ex.Message + ": " + (ex.InnerException != null ? ex.InnerException.Message : "")); // We just start a new transaction in this example. // Real world POS solutions should probably retain state and allow to try again. //InitializeTransaction(); } }
private void HashAndSignCallback(IAsyncResult ar) { PosEventSignResult result = FDMClient.EndHashAndSign(ar); if (result != null) { if (result.HasErrors) { foreach (Error e in result.Errors) { MessageBox.Show(e.ToString()); } } else { /* * string result_message = "Hash and sign result:\n"; * result_message = string.Concat( * result_message, string.Format( * "\tIsCLocking: {0}\n" + * "\tClockingType: {1}\n" + * "\tVATReceiptPrintingMode: {2}\n" + * "\tVATSplits:\n", * result.IsClocking, * result.ClockingType, * result.VATReceiptPrintingMode * ) * ); * * if(result.VATSplit != null) { * foreach(VATSplit s in result.VATSplit) { * result_message = string.Concat( * result_message, string.Format( * "\t\tPrintVatRateId: {0}\n" + * "\t\tTaxableAmount: {1}\n" + * "\t\tVATAmount: {2}\n" + * "\t\tVATRate: {3}\n" + * "\t\tVatRateId: {4}\n" + * "\n", * s.PrintVatRateId, * s.TaxableAmount, * s.VATAmount, * s.VATRate, * s.VatRateId * ) * ); * } * } * * MessageBox.Show(result_message); * * string event_message = "Event:\n"; * event_message = string.Concat( * event_message, string.Format( * "\tDrawerId: {0}\n" + * "\tDrawerName: {1}\n" + * "\tDrawerOpen: {2}\n" + * "\tInvoiceNumber: {3}\n" + * "\tIsFinalized: {4}\n" + * "\tIsRefund: {5}\n" + * "\tIsSimplifiedReceipt: {6}\n" + * "\tIsTrainingMode: {7}\n" + * "\tOperatorId: {8}\n" + * "\tOperatorName: {9}\n" + * "\tPayments:\n", * result.Event.DrawerId, * result.Event.DrawerName, * result.Event.DrawerOpen, * result.Event.InvoiceNumber, * result.Event.IsFinalized, * result.Event.IsRefund, * result.Event.IsSimplifiedReceipt, * result.Event.IsTrainingMode, * result.Event.OperatorId, * result.Event.OperatorName * ) * ); * * foreach(PaymentLine p in result.Event.Payments) { * event_message = string.Concat( * event_message, string.Format( * "\t\tForeignCurrencyAmount: {0}\n" + * "\t\tForeignCurrencyISO: {1}\n" + * "\t\tPayAmount: {2}\n" + * "\t\tPaymentId: {3}\n" + * "\t\tPaymentName: {4}\n" + * "\t\tPaymentType: {5}\n" + * "\t\tQuantity: {6}\n" + * "\t\tReference: {7}\n" + * "\n", * p.ForeignCurrencyAmount, * p.ForeignCurrencyISO, * p.PayAmount, * p.PaymentId, * p.PaymentName, * p.PaymentType, * p.Quantity, * p.Reference * ) * ); * } * * event_message = string.Concat( * event_message, string.Format( * "\tPOSSerialNumber: {0}\n" + * "\tProducts:\n", * result.Event.POSSerialNumber * ) * ); * * foreach(ProductLine p in result.Event.Products) { * event_message = string.Concat( * event_message, string.Format( * "\t\tDiscounts: {0}\n" + * "\t\tPrintVatRateId: {1}\n" + * "\t\tProductGroupId: {2}\n" + * "\t\tProductGroupName: {3}\n" + * "\t\tProductId: {4}\n" + * "\t\tProductName: {5}\n" + * "\t\tQuantity: {6}\n" + * "\t\tQuantityUnit: {7}\n" + * "\t\tSellingPrice: {8}\n" + * "\t\tVatRateId: {9}\n" + * "\n", * p.Discounts, * p.PrintVatRateId, * p.ProductGroupId, * p.ProductGroupName, * p.ProductId, * p.ProductName, * p.Quantity, * p.QuantityUnit, * p.SellingPrice, * p.VatRateId * ) * ); * } * * event_message = string.Concat( * event_message, string.Format( * "\tReference: {0}\n" + * "\tTerminalId: {1}\n" + * "\tTerminalName: {2}\n" + * "\tTransactionDateTime: {3}\n" + * "\tTransactionNumber: {4}\n" + * "\tVatRateA: {5}\n" + * "\tVatRateB: {6}\n" + * "\tVatRateC: {7}\n" + * "\tVatRateD: {8}\n", * result.Event.Reference, * result.Event.TerminalId, * result.Event.TerminalName, * result.Event.TransactionDateTime, * result.Event.TransactionNumber, * result.Event.VatRateA, * result.Event.VatRateB, * result.Event.VatRateC, * result.Event.VatRateD * ) * ); * MessageBox.Show(event_message); * * if(result.HasSignature) { * string signature_message = "Signature:\n"; * signature_message = string.Concat( * signature_message, string.Format( * "\tEventType: {0}\n" + * "\tFDMSerialNumber: {1}\n" + * "\tFullPluHash: {2}\n" + * "\tPrintEventType: {3}\n" + * "\tPrintPluHash: {4}\n" + * "\tSignature: {5}\n" + * "\tSignDateTime: {6}\n" + * "\tTicketCount: {7}\n" + * "\tTicketNumber: {8}\n" + * "\tVSCIdentificationNumber: {9}\n", * result.Signature.EventType, * result.Signature.FDMSerialNumber, * result.Signature.FullPluHash, * result.Signature.PrintEventType, * result.Signature.PrintPluHash, * result.Signature.Signature, * result.Signature.SignDateTime, * result.Signature.TicketCount, * result.Signature.TicketNumber, * result.Signature.VSCIdentificationNumber * ) * ); * MessageBox.Show(signature_message); * } */ PrintReceipt(result); } // Start the next transaction. // We allow clocking in the middle of another transaction in this example, for a real-world POS // you need to beware of transaction numbers. Don't create gaps or duplicate numbers if you do this! //if(result.IsClocking == false) InitializeTransaction(); } }
void PrintReceipt(PosEventSignResult pesr) { string tab = " "; // Necessary since the receipt printer doesn't seem to support normal tab characters. string total_label = "Total: "; StringBuilder sb = new StringBuilder(); try { // Initialization. PosPrinter.RecLetterQuality = true; PosPrinter.SetBitmap(1, PrinterStation.Receipt, "..\\..\\Resources\\outpost_logo_black.bmp", PosPrinter.RecLineWidth, PosPrinter.PrinterBitmapCenter); // Header logo. sb.Append(PrintCommands.bitmap_1); // Establishment data. Dispatcher.Invoke(() => { sb.Append( PrintCommands.center + CompanyNameLabel.Content + "\n" + CompanyStreetLabel.Content + "\n" + CompanyCityLabel.Content + "\n" + CompanyVATLabel.Content + "\n\n" ); }); // Receipt title. sb.Append(PrintCommands.double_size); if (pesr.Event.IsTrainingMode) { sb.Append("TRAINING RECEIPT\n"); } else { sb.Append("VAT RECEIPT\n"); } if (pesr.Event.IsRefund) { sb.Append("REFUND\n"); } sb.Append(PrintCommands.reset); decimal receipt_total = 0.0m; int space_count; // Product lines & total. sb.Append(PrintCommands.bold + "Products & Services:\n" + PrintCommands.reset); foreach (ProductLine l in pesr.Event.Products) { space_count = PosPrinter.RecLineChars - l.Quantity.ToString().Length - l.ProductName.ToString().Length - l.SellingPrice.ToString().Length - l.PrintVatRateId.ToString().Length - tab.Length - 3; // TODO: Handle (space_count <= 0) case. Debug.Assert(0 < space_count); sb.Append( string.Format(tab + "{0}x {1}", l.Quantity, l.ProductName) + string.Concat(Enumerable.Repeat(" ", space_count)) + string.Format("{0} {1}\n", l.SellingPrice, l.PrintVatRateId) ); receipt_total += l.SellingPrice; } sb.Append(tab + string.Concat(Enumerable.Repeat("-", PosPrinter.RecLineChars - tab.Length)) + "\n"); space_count = PosPrinter.RecLineChars - total_label.Length - receipt_total.ToString().Length - tab.Length - 2; sb.Append(tab + total_label + string.Concat(Enumerable.Repeat(" ", space_count)) + receipt_total.ToString() + "\n\n"); // Payment lines. // TODO: Add support for change & refund. sb.Append(PrintCommands.bold + "Payment:\n" + PrintCommands.reset); foreach (PaymentLine l in pesr.Event.Payments) { space_count = PosPrinter.RecLineChars - l.PaymentName.ToString().Length - l.PayAmount.ToString().Length - tab.Length - 2; sb.Append(tab + l.PaymentName + string.Concat(Enumerable.Repeat(" ", space_count)) + l.PayAmount + "\n"); } sb.Append("\n"); // VAT data. int len, taxable_max_char_count = 0, rate_max_char_count = 0, amount_max_char_count = 0; sb.Append(PrintCommands.bold + "VAT:\n" + PrintCommands.reset); // TODO: Multilingual support. foreach (VATSplit v in pesr.VATSplit) { // Calculate spacing for alignment. len = v.TaxableAmount.ToString().Length; if (taxable_max_char_count < len) { taxable_max_char_count = len; } len = v.VATRate.ToString().Length; if (rate_max_char_count < len) { rate_max_char_count = len; } len = v.VATAmount.ToString().Length; if (amount_max_char_count < len) { amount_max_char_count = len; } } foreach (VATSplit v in pesr.VATSplit) { sb.Append( tab + v.PrintVatRateId + ": " + string.Concat(Enumerable.Repeat(" ", taxable_max_char_count - v.TaxableAmount.ToString().Length)) + v.TaxableAmount + " @ " + string.Concat(Enumerable.Repeat(" ", rate_max_char_count - v.VATRate.ToString().Length)) + v.VATRate + "% = " + string.Concat(Enumerable.Repeat(" ", amount_max_char_count - v.VATAmount.ToString().Length)) + +v.VATAmount + "\n" ); } sb.Append(tab + total_label + string.Concat( Enumerable.Repeat(" ", taxable_max_char_count + rate_max_char_count + amount_max_char_count + 10 - total_label.Length - pesr.GetTotalVATAmount().ToString().Length ) ) + pesr.GetTotalVATAmount() + "\n\n" ); // Other mandatory data. sb.Append( PrintCommands.bold + "Cash Register Data:\n" + PrintCommands.reset + tab + "PLU hash: " + pesr.Signature.PrintPluHash + "\n" + tab + "POS: " + pesr.Event.POSSerialNumber + "\n" + tab + "Version: " + "~TODO~" + "\n" + // TODO tab + "Terminal: " + pesr.Event.TerminalId + "\n" + tab + "Transaction: " + pesr.Event.TransactionNumber.ToString() + "\n" + tab + "Date & time: " + pesr.Event.TransactionDateTime.ToString("dd/MM/yyyy HH:mm:ss") + "\n" + tab + "User: "******"\n" + "\n" ); // FDM control data. // Must follow specific naming conventions as dictated by the law! // See circular no. E.T. 124.747, chapter 5, points 44 & 45! sb.Append( PrintCommands.bold + "Control Data:\n" + PrintCommands.reset + tab + pesr.Signature.SignDateTime + "\n" + tab + string.Format("Receipt counter: {0}/{1} {2}\n", pesr.Signature.TicketNumber, pesr.Signature.TicketCount, pesr.Signature.EventType ) + tab + "Receipt signature:\n" + tab + tab + pesr.Signature.Signature + "\n" + tab + "Control module ID: " + pesr.Signature.FDMSerialNumber + "\n" + tab + "VAT signing card ID: " + pesr.Signature.VSCIdentificationNumber + "\n\n" ); // Invalidity footer. if (pesr.Event.IsTrainingMode) { sb.Append(PrintCommands.center + PrintCommands.double_size + "THIS IS NOT A\nVALID VAT RECEIPT\n" + PrintCommands.reset ); } sb.Append(PrintCommands.feed_cut); PosPrinter.PrintNormal(PrinterStation.Receipt, sb.ToString()); } catch (PosControlException e) { Debug.WriteLine("Point of sale control exception: {0}", e); if (e.ErrorCode == ErrorCode.Extended) { Debug.WriteLine("Extended: ", e.ErrorCodeExtended); } } }