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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
        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);
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
        }