public async Task <OperationResult> UpdateRemoteMachinePriceTableAsync(Machine machine, IEnumerable <ProductRail> products)
        {
            //if (!IPAddress.TryParse(machine.IPEndPoint, out var ipAddr))
            if (!IPEndPointHelper.TryParse(machine.IPEndPoint, out var ipAddr))
            {
                return(OperationResult.Failed(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.InvalidMachineIPEndPoint)));
            }

            var productsArr = products.ToArray();

            using (var client = new TcpClient())
            {
                _logger.LogInformationIfEnabled(() => $"Connection to machine {machine}");
                _logger.LogInformationIfEnabled(() => $"Openning TCP connection in {ipAddr.Address}:{MACHINE_TCP_PORT}");
                await client.ConnectAsync(ipAddr.Address, MACHINE_TCP_PORT);


                var stream = client.GetStream();
                _logger.LogDebug("Got stream!");

                var productsCount = productsArr.Length;
                _logger.LogDebugIfEnabled(() => $"Sending {productsCount} products update.");

                var data = new byte[OFFSET.PRODUCTS + (productsCount * PRODUCT_SIZE)];

                data[OFFSET.INTENTION] = 0x02;
                data[OFFSET.COUNT]     = (byte)productsCount;

                for (int i = 0; i < productsCount; i++)
                {
                    var p = productsArr[i];
                    ToBytes(p).CopyTo(data, OFFSET.PRODUCTS + (i * PRODUCT_SIZE));
                }

                _logger.LogInformationIfEnabled(() => $"Awaiting...");
                await Task.Delay(500);

                _logger.LogTraceIfEnabled(() => $"Sending bulk update data: '{ByteHelper.ByteArrayToString(data)}'.");
                stream.Write(data, 0, data.Length);

                _logger.LogDebug("Ignoring response....");
                // var buffer = new byte[255];
                // var result = await stream.ReadAsync(buffer, 0, 255);
            }

            _logger.LogDebug("Returning OperationResult.Success.");
            return(OperationResult.Success);
        }
        //TODO: Review floating points comparisons
        public OperationResult Sale(SaleOperation sale)
        {
            var decimalPrice = new decimal(sale.Price);
            var machine      = _machineRepository.Get(sale.MachineId);
            var client       = _clientCardRepository.Get(sale.ClientCardId);
            var products     = _productRepository.GetMany(sale.ItemsId.Select(_ => (int)_)).ToList();

            var errors = new List <OperationError>();

            if (client == null)
            {
                errors.Add(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.ClientNotFound));
            }

            if (client != null && client.Credit < decimalPrice)
            {
                errors.Add(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.ClientWithNoEnoughCredit));
            }

            if (products.Count != sale.ItemsCount)
            {
                errors.Add(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.InvalidProduct));
            }

            if (products.Sum(_ => _.Price) != decimalPrice)
            {
                errors.Add(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.InvalidPrice));
            }

            if (products.Count != sale.ItemsCount)
            {
                errors.Add(OperationErrorFactory.FromWellKnowErrors(WellKnowErrors.InvalidProduct));
            }

            if (errors.Any())
            {
                return(OperationResult.Failed(errors.ToArray()));
            }

            DoTransaction(client, machine, products, decimalPrice);
            return(OperationResult.Success);
        }