public async Task <PurchaseModel> OrderItem(int id, string sessionId)
        {
            //by default you can buy the item
            var result = new PurchaseModel
            {
                CanBuy         = true,
                SellableItem   = _mapper.Map <SellableItemModel>(await _sellableItemRepository.Find(id)),
                InsertedTokens = await _tokenService.GetCollection(sessionId)
            };

            //always deduct only one item per purchase

            //no stock available
            if (result.SellableItem.Quantity == 0)
            {
                result.Message = "The item is out of stock";
                result.CanBuy  = false;
            }

            //define 1 to be deducted later from the stock
            result.SellableItem.Quantity = 1;


            //not enough money to buy
            if (result.InsertedTokens.Total < result.SellableItem.Price)
            {
                double remainingMoney = result.SellableItem.Price - result.InsertedTokens.Total;

                result.Message =
                    $"Insufficient money. You need to add at least {remainingMoney / 100} eur to buy this item";
                result.CanBuy = false;
            }

            if (!result.CanBuy)
            {
                return(result);
            }

            if (result.InsertedTokens.Total != result.SellableItem.Price)
            {
                var exchangeTokens = await _ledgerRepository.GetExchangeTokens();

                var giveBack         = result.InsertedTokens.Total - result.SellableItem.Price;
                var tokensToExchange = new List <ExchangeToken>();
                while (giveBack > 0 && result.CanBuy)
                {
                    foreach (var t in exchangeTokens)
                    {
                        if (giveBack / t.Value <= 0)
                        {
                            continue;
                        }
                        if (t.Quantity == 0)
                        {
                            result.CanBuy  = false;
                            result.Message = "The machine doesn't have enough exchange tokens, ask for help.";
                        }

                        giveBack -= t.Value;
                        t.Quantity--;
                        tokensToExchange.Add(t);
                        break;
                    }
                }

                result.ExchangeTokens = _mapper.Map <TokenModelCollection>(tokensToExchange);
                await _ledgerRepository.AddExchangeTokens(sessionId, tokensToExchange);
            }

            var subtracted = await _ledgerRepository.Subtract(sessionId, result.SellableItem.Price);

            var subtractedTokens = subtracted.Select(p => p.Token);
            await _sellableItemRepository.DeductStock(_mapper.Map <SellableItem>(result.SellableItem));

            result.Message          = "Thanks for your order";
            result.SubtractedTokens = _mapper.Map <TokenModelCollection>(subtractedTokens);
            return(result);
        }