public override DeviceStatus PrintReversalReceipt(ReversalReceipt reversalReceipt) { // Abort all unfinished or erroneus receipts AbortReceipt(); // Receipt header var(_, deviceStatus) = OpenReversalReceipt( reversalReceipt.Reason, reversalReceipt.ReceiptNumber, reversalReceipt.ReceiptDateTime, reversalReceipt.FiscalMemorySerialNumber, reversalReceipt.UniqueSaleNumber, reversalReceipt.Operator, reversalReceipt.OperatorPassword); if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occured while opening new fiscal reversal receipt"); return(deviceStatus); } try { return(PrintReceiptBody(reversalReceipt)); } catch (StandardizedStatusMessageException e) { AbortReceipt(); deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); return(deviceStatus); } }
protected (string, DeviceStatus) Request(string?data = null) { lock (frameSyncLock) { if (DeadLine < DateTime.Now) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E999", "User timeout occured while sending the request"); return(string.Empty, deviceStatus); } try { var response = ParseResponse(RawRequest(data == null ? null : PrinterEncoding.GetBytes(data))); if (data == "00") { return(response, new DeviceStatus()); } var rawStatus = ParseRawResponse(RawRequest(data == null ? null : PrinterEncoding.GetBytes("F80C"))); return(response, ParseStatus(rawStatus)); } catch (InvalidResponseException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E107", e.Message); return(string.Empty, deviceStatus); } catch (Exception e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E101", e.Message); return(string.Empty, deviceStatus); } } }
protected (string, DeviceStatus) Request(byte command, string?data = null) { lock (frameSyncLock) { if (DeadLine < DateTime.Now) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E999", "User timeout occured while sending the request"); return(string.Empty, deviceStatus); } try { return(ParseResponse(RawRequest(command, data == null ? null : PrinterEncoding.GetBytes(data)))); } catch (StandardizedStatusMessageException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); return(string.Empty, deviceStatus); } catch (InvalidResponseException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E107", e.Message); return(string.Empty, deviceStatus); } catch (Exception e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E101", e.Message); return(string.Empty, deviceStatus); } } }
protected (string, DeviceStatus) Request(byte command, string?data = null) { lock (frameSyncLock) { try { return(ParseResponse(RawRequest(command, data == null ? null : PrinterEncoding.GetBytes(data)))); } catch (StandardizedStatusMessageException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); return(string.Empty, deviceStatus); } catch (InvalidResponseException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E107", e.Message); return(string.Empty, deviceStatus); } catch (Exception e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E101", e.Message); return(string.Empty, deviceStatus); } } }
protected (string, DeviceStatus) Request(string?data = null) { lock (frameSyncLock) { try { System.Diagnostics.Trace.WriteLine($"Request: '{data}'"); var response = ParseResponse(RawRequest(data == null ? null : PrinterEncoding.GetBytes(data))); if (data == "00") { return(response, new DeviceStatus()); } var rawStatus = ParseRawResponse(RawRequest(data == null ? null : PrinterEncoding.GetBytes("F80C"))); return(response, ParseStatus(rawStatus)); } catch (InvalidResponseException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E107", e.Message); return(string.Empty, deviceStatus); } catch (Exception e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E101", e.Message); return(string.Empty, deviceStatus); } } }
public virtual (decimal?, DeviceStatus) GetReceiptAmount() { decimal?receiptAmount = null; var(receiptStatusResponse, deviceStatus) = Request(CommandGetReceiptStatus, "T"); if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occured while reading last receipt status"); return(null, deviceStatus); } var fields = receiptStatusResponse.Split(','); if (fields.Length < 3) { deviceStatus.AddInfo($"Error occured while parsing last receipt status"); deviceStatus.AddError("E409", "Wrong format of receipt status"); return(null, deviceStatus); } try { var amountString = fields[2]; if (amountString.Length > 0) { switch (amountString[0]) { case '+': receiptAmount = decimal.Parse(amountString.Substring(1), CultureInfo.InvariantCulture) / 100m; break; case '-': receiptAmount = -decimal.Parse(amountString.Substring(1), CultureInfo.InvariantCulture) / 100m; break; default: if (amountString.Contains(".")) { receiptAmount = decimal.Parse(amountString, CultureInfo.InvariantCulture); } else { receiptAmount = decimal.Parse(amountString, CultureInfo.InvariantCulture) / 100m; } break; } } } catch (Exception e) { deviceStatus = new DeviceStatus(); deviceStatus.AddInfo($"Error occured while parsing the amount of last receipt status"); deviceStatus.AddError("E409", e.Message); return(null, deviceStatus); } return(receiptAmount, deviceStatus); }
public virtual DeviceStatus ValidateTransferAmount(TransferAmount transferAmount) { var status = new DeviceStatus(); if (transferAmount.Amount <= 0) { status.AddError("E403", "Amount should be positive number"); } return(status); }
public override (string, DeviceStatus) GetLastDocumentNumber(string closeReceiptResponse) { var deviceStatus = new DeviceStatus(); var fields = closeReceiptResponse.Split('\t'); if (fields.Length < 2) { deviceStatus.AddInfo($"Error occured while parsing close receipt response"); deviceStatus.AddError("E409", $"Wrong format of close receipt response"); return(string.Empty, deviceStatus); } return(fields[1], deviceStatus); }
public override (decimal?, DeviceStatus) GetReceiptAmount() { decimal?receiptAmount = null; var(receiptStatusResponse, deviceStatus) = Request(CommandGetReceiptStatus); if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occured while reading last receipt status"); return(null, deviceStatus); } var fields = receiptStatusResponse.Split('\t'); if (fields.Length < 5) { deviceStatus.AddInfo($"Error occured while parsing last receipt status"); deviceStatus.AddError("E409", "Wrong format of receipt status"); return(null, deviceStatus); } try { var amountString = fields[4]; if (amountString.Length > 0) { switch (amountString[0]) { case '+': receiptAmount = decimal.Parse(amountString.Substring(1), System.Globalization.CultureInfo.InvariantCulture) / 100m; break; case '-': receiptAmount = -decimal.Parse(amountString.Substring(1), System.Globalization.CultureInfo.InvariantCulture) / 100m; break; default: receiptAmount = decimal.Parse(amountString, System.Globalization.CultureInfo.InvariantCulture); break; } } } catch (Exception e) { deviceStatus = new DeviceStatus(); deviceStatus.AddInfo($"Error occured while parsing the amount of last receipt status"); deviceStatus.AddError("E409", e.Message); return(null, deviceStatus); } return(receiptAmount, deviceStatus); }
public override DeviceStatusWithRawResponse RawRequest(RequestFrame requestFrame) { if (requestFrame.RawRequest.Length < 2) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E401", "Request length must be at least 2 characters"); return(new DeviceStatusWithRawResponse(deviceStatus)); } var(rawResponse, status) = Request(requestFrame.RawRequest); var deviceStatusWithRawResponse = new DeviceStatusWithRawResponse(status); deviceStatusWithRawResponse.RawResponse = rawResponse; return(deviceStatusWithRawResponse); }
public override DeviceStatusWithRawResponse RawRequest(RequestFrame requestFrame) { if (requestFrame.RawRequest.Length == 0) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E401", "Request length must be at least 1 character"); return(new DeviceStatusWithRawResponse(deviceStatus)); } var cmd = PrinterEncoding.GetBytes(requestFrame.RawRequest.Substring(0, 1))[0]; var data = requestFrame.RawRequest.Substring(1); var(rawResponse, status) = Request(cmd, data); var deviceStatusWithRawResponse = new DeviceStatusWithRawResponse(status); deviceStatusWithRawResponse.RawResponse = rawResponse; return(deviceStatusWithRawResponse); }
public override (ReceiptInfo, DeviceStatus) PrintReceipt(Receipt receipt) { var receiptInfo = new ReceiptInfo(); // Abort all unfinished or erroneus receipts AbortReceipt(); var(fiscalMemorySerialNumber, deviceStatus) = GetFiscalMemorySerialNumber(); if (!deviceStatus.Ok) { return(receiptInfo, deviceStatus); } receiptInfo.FiscalMemorySerialNumber = fiscalMemorySerialNumber; // Receipt header (_, deviceStatus) = OpenReceipt( receipt.UniqueSaleNumber, receipt.Operator, receipt.OperatorPassword ); if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occured while opening new fiscal receipt"); return(receiptInfo, deviceStatus); } try { deviceStatus = PrintReceiptBody(receipt); if (!deviceStatus.Ok) { return(receiptInfo, deviceStatus); } } catch (StandardizedStatusMessageException e) { AbortReceipt(); deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); return(receiptInfo, deviceStatus); } return(GetLastReceiptInfo()); }
protected override DeviceStatus ParseStatus(byte[]?rawStatus) { var deviceStatus = new DeviceStatus(); if (rawStatus == null || rawStatus.Length != 12) { deviceStatus.AddError("E401", "Invalid status"); return(deviceStatus); } byte[] status = new byte[] { 0, 0, 0, 0, 0, 0 }; for (var i = 0; i < status.Length; i++) { byte hi4 = (byte)((rawStatus[i * 2] - 0x30) << 4); byte lo4 = (byte)(rawStatus[i * 2 + 1] - 0x30); status[i] = (byte)(hi4 + lo4); } for (var i = 0; i < status.Length; i++) { byte mask = 0b10000000; byte b = status[i]; for (var j = 0; j < 8; j++) { if ((mask & b) != 0) { var(statusBitsCode, statusBitsText, statusBitStringType) = StatusBitsStrings[i * 8 + (7 - j)]; deviceStatus.AddMessage(new StatusMessage { Type = statusBitStringType, Code = statusBitsCode, Text = statusBitsText }); } mask >>= 1; } } return(deviceStatus); }
protected (string, DeviceStatus) Request(byte command, string?data = null) { lock (frameSyncLock) { try { System.Diagnostics.Trace.WriteLine($"Request({command:X}): '{data}'"); return(ParseResponse(RawRequest(command, data == null ? null : PrinterEncoding.GetBytes(data)))); } catch (InvalidResponseException e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E107", e.Message); return(string.Empty, deviceStatus); } catch (Exception e) { var deviceStatus = new DeviceStatus(); deviceStatus.AddError("E101", e.Message); return(string.Empty, deviceStatus); } } }
public virtual DeviceStatus ValidateReceipt(Receipt receipt) { var status = new DeviceStatus(); if (receipt.Items == null || receipt.Items.Count == 0) { status.AddError("E410", "Receipt is empty, no items"); return(status); } if (String.IsNullOrEmpty(receipt.UniqueSaleNumber)) { status.AddError("E405", "UniqueSaleNumber is empty"); return(status); } var uniqueSaleNumberMatch = Regex.Match(receipt.UniqueSaleNumber, "^[A-Z0-9]{8}-[A-Z0-9]{4}-[0-9]{7}$"); if (!uniqueSaleNumberMatch.Success) { status.AddError("E405", "Invalid format of UniqueSaleNumber"); return(status); } var itemsTotalAmount = 0.00m; var row = 0; foreach (var item in receipt.Items) { row++; if (String.IsNullOrEmpty(item.Text)) { status.AddError("E407", $"Item {row}: \"text\" is empty"); } // Validation of "type" : "sale" if (item.Type == ItemType.Sale) { if (item.PriceModifierValue <= 0 && item.PriceModifierType != PriceModifierType.None) { status.AddError("E403", $"Item {row}: \"priceModifierValue\" should be positive number"); } if (item.PriceModifierValue != 0 && item.PriceModifierType == PriceModifierType.None) { status.AddError("E403", $"Item {row}: \"priceModifierValue\" should'nt be \"none\" or empty. You can avoid setting priceModifier if you do not want price modification"); } if (item.Quantity <= 0) { status.AddError("E403", $"Item {row}: \"quantity\" should be positive number"); } if (item.TaxGroup == TaxGroup.Unspecified) { status.AddError("E403", $"Item {row}: \"taxGroup\" should'nt be \"unspecified\" or empty"); } try { GetTaxGroupText(item.TaxGroup); } catch (StandardizedStatusMessageException e) { status.AddError(e.Code, e.Message); } var quantity = Math.Round(item.Quantity, 3, MidpointRounding.AwayFromZero); var unitPrice = Math.Round(item.UnitPrice, 2, MidpointRounding.AwayFromZero); var itemPrice = quantity * unitPrice; switch (item.PriceModifierType) { case PriceModifierType.DiscountAmount: itemPrice -= item.PriceModifierValue; break; case PriceModifierType.DiscountPercent: itemPrice -= itemPrice * (item.PriceModifierValue / 100.0m); break; case PriceModifierType.SurchargeAmount: itemPrice += item.PriceModifierValue; break; case PriceModifierType.SurchargePercent: itemPrice += itemPrice * (item.PriceModifierValue / 100.0m); break; } itemsTotalAmount += Math.Round(itemPrice, 2, MidpointRounding.AwayFromZero); } if (!status.Ok) { return(status); } } if (receipt.Payments?.Count > 0) { var paymentAmount = 0.00m; row = 0; foreach (var payment in receipt.Payments) { row++; if (payment.Amount <= 0 && payment.PaymentType != PaymentType.Change) { status.AddError("E403", $"Payment {row}: \"amount\" should be positive number"); } if (payment.Amount >= 0 && payment.PaymentType == PaymentType.Change) { status.AddError("E403", $"Change {row}: \"amount\" should be negative number"); } try { if (payment.PaymentType != PaymentType.Change) { // Check if the payment type is supported GetPaymentTypeText(payment.PaymentType); } } catch (StandardizedStatusMessageException e) { status.AddError(e.Code, e.Message); } if (!status.Ok) { status.AddInfo($"Error occured at Payment {row}"); return(status); } var amount = Math.Round(payment.Amount, 2, MidpointRounding.AwayFromZero); paymentAmount += amount; } var difference = Math.Abs(paymentAmount - itemsTotalAmount); if (difference >= 0.01m && difference / itemsTotalAmount > 0.00001m) { status.AddError("E403", $"Payment total amount ({paymentAmount.ToString(CultureInfo.InvariantCulture)}) should be the same as the items total amount ({itemsTotalAmount.ToString(CultureInfo.InvariantCulture)})"); } } return(status); }
public virtual DeviceStatus ValidateReceipt(Receipt receipt) { var status = new DeviceStatus(); if (receipt.Items == null || receipt.Items.Count == 0) { status.AddError("E410", "Receipt is empty, no items"); return(status); } if (String.IsNullOrEmpty(receipt.UniqueSaleNumber)) { status.AddError("E405", "UniqueSaleNumber is empty"); return(status); } var uniqueSaleNumberMatch = Regex.Match(receipt.UniqueSaleNumber, "^[A-Z0-9]{8}-[A-Z0-9]{4}-[0-9]{7}$"); if (!uniqueSaleNumberMatch.Success) { status.AddError("E405", "Invalid format of UniqueSaleNumber"); return(status); } var row = 0; foreach (var item in receipt.Items) { row++; if (String.IsNullOrEmpty(item.Text)) { status.AddError("E407", $"Item {row}: \"text\" is empty"); } if (item.IsComment) { status.AddWarning("W401", $"Item {row}: \"isComment\" is deprecated in Item {row}. Use \"type\" : \"comment\" instead"); } // Validation of "type" : "sale" if (item.Type == ItemType.Sale) { if (item.PriceModifierValue <= 0 && item.PriceModifierType != PriceModifierType.None) { status.AddError("E403", $"Item {row}: \"priceModifierValue\" should be positive number"); } if (item.PriceModifierValue != 0 && item.PriceModifierType == PriceModifierType.None) { status.AddError("E403", $"Item {row}: \"priceModifierValue\" should'nt be \"none\" or empty. You can avoid setting priceModifier if you do not want price modification"); } if (item.Quantity <= 0) { status.AddError("E403", $"Item {row}: \"quantity\" should be positive number"); } if (item.TaxGroup == TaxGroup.Unspecified) { status.AddError("E403", $"Item {row}: \"taxGroup\" should'nt be \"unspecified\" or empty"); } try { GetTaxGroupText(item.TaxGroup); } catch (StandardizedStatusMessageException e) { status.AddError(e.Code, e.Message); } } if (!status.Ok) { return(status); } } if (receipt.Payments?.Count > 0) { row = 0; foreach (var payment in receipt.Payments) { row++; if (payment.Amount <= 0) { status.AddError("E403", $"Payment {row}: \"amount\" should be positive number"); } try { GetPaymentTypeText(payment.PaymentType); } catch (StandardizedStatusMessageException e) { status.AddError(e.Code, e.Message); } if (!status.Ok) { status.AddInfo($"Error occured at Payment {row}"); return(status); } } } return(status); }
public virtual (ReceiptInfo, DeviceStatus) PrintReceiptBody(Receipt receipt, bool reversalReceipt = false) { var receiptInfo = new ReceiptInfo(); var(fiscalMemorySerialNumber, deviceStatus) = GetFiscalMemorySerialNumber(); if (!deviceStatus.Ok) { return(receiptInfo, deviceStatus); } receiptInfo.FiscalMemorySerialNumber = fiscalMemorySerialNumber; if (receipt.Items == null || receipt.Items.Count == 0) { deviceStatus.AddError("E410", "Receipt.Items must be not null or empty"); return(receiptInfo, deviceStatus); } uint itemNumber = 0; // Receipt items foreach (var item in receipt.Items) { itemNumber++; if (item.Type == ItemType.Comment) { (_, deviceStatus) = AddComment(receipt.UniqueSaleNumber, item.Text); if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occurred in Item {itemNumber}"); return(receiptInfo, deviceStatus); } } else { if (item.PriceModifierValue < 0m) { throw new StandardizedStatusMessageException("PriceModifierValue amount must be positive number", "E403"); } if (item.PriceModifierValue != 0m && item.PriceModifierType == PriceModifierType.None) { throw new StandardizedStatusMessageException("PriceModifierValue must be 0 if priceModifierType is None", "E403"); } try { (_, deviceStatus) = AddItem( receipt.UniqueSaleNumber, item.Text, item.UnitPrice, item.TaxGroup, item.Quantity, item.PriceModifierValue, item.PriceModifierType, reversalReceipt); } catch (StandardizedStatusMessageException e) { deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); } if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occurred in Item {itemNumber}"); return(receiptInfo, deviceStatus); } } } // Get receipt number and amount string receiptNumber; decimal?receiptAmount; (receiptNumber, receiptAmount, deviceStatus) = GetReceiptNumberAndAmount(); if (!deviceStatus.Ok) { return(receiptInfo, deviceStatus); } receiptInfo.ReceiptNumber = receiptNumber; receiptInfo.ReceiptAmount = receiptAmount ?? 0m; // Receipt payments if (receipt.Payments == null || receipt.Payments.Count == 0) { deviceStatus = FullPayment(); if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occurred while making full payment in cash"); return(receiptInfo, deviceStatus); } } else { uint paymentNumber = 0; foreach (var payment in receipt.Payments) { paymentNumber++; if (payment.PaymentType == PaymentType.Change) { continue; } try { (_, deviceStatus) = AddPayment(payment.Amount, payment.PaymentType); } catch (StandardizedStatusMessageException e) { deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); } if (!deviceStatus.Ok) { deviceStatus.AddInfo($"Error occurred in Payment {paymentNumber}"); return(receiptInfo, deviceStatus); } } } // Get the receipt date and time (current fiscal device date and time) DateTime?dateTime; (dateTime, deviceStatus) = GetDateTime(); if (!deviceStatus.Ok) { return(receiptInfo, deviceStatus); } receiptInfo.ReceiptDateTime = dateTime ?? DateTime.Now; if (deviceStatus.Ok) { deviceStatus = FullPayment(); } return(receiptInfo, deviceStatus); }
protected virtual DeviceStatus PrintReceiptBody(Receipt receipt) { if (receipt.Items == null || receipt.Items.Count == 0) { throw new StandardizedStatusMessageException("Receipt.Items must be not null or empty", "E410"); } DeviceStatus deviceStatus; uint itemNumber = 0; // Receipt items foreach (var item in receipt.Items) { itemNumber++; if (item.Type == ItemType.Comment || item.IsComment) { (_, deviceStatus) = AddComment(item.Text); if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occurred in the comment of Item {itemNumber}"); return(deviceStatus); } } else { if (item.PriceModifierValue < 0m) { throw new StandardizedStatusMessageException("PriceModifierValue amount must be positive number", "E403"); } if (item.PriceModifierValue != 0m && item.PriceModifierType == PriceModifierType.None) { throw new StandardizedStatusMessageException("PriceModifierValue must be 0 if priceModifierType is None", "E403"); } try { (_, deviceStatus) = AddItem( item.Text, item.UnitPrice, item.TaxGroup, item.Quantity, item.PriceModifierValue, item.PriceModifierType); } catch (StandardizedStatusMessageException e) { deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); } if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occurred in Item {itemNumber}"); return(deviceStatus); } } } // Receipt payments if (receipt.Payments == null || receipt.Payments.Count == 0) { (_, deviceStatus) = FullPaymentAndCloseReceipt(); if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occurred while making full payment in cash and closing the receipt"); return(deviceStatus); } } else { uint paymentNumber = 0; foreach (var payment in receipt.Payments) { paymentNumber++; try { (_, deviceStatus) = AddPayment(payment.Amount, payment.PaymentType); } catch (StandardizedStatusMessageException e) { deviceStatus = new DeviceStatus(); deviceStatus.AddError(e.Code, e.Message); } if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occurred in Payment {paymentNumber}"); return(deviceStatus); } } (_, deviceStatus) = CloseReceipt(); if (!deviceStatus.Ok) { AbortReceipt(); deviceStatus.AddInfo($"Error occurred while closing the receipt"); return(deviceStatus); } } return(deviceStatus); }