public async Task<ActionResult> Order(int id)
        {
            OrdersProvider ordersProvider = new OrdersProvider();
            SimpleOrderModel order = await ordersProvider.GetOrder(id);

            if (order.PaymentMethodId == 1)
            {
                return this.View("Epay", order);
            }

            return this.Redirect("/order-accepted");
        }
        public void SendNewOrderMail(int orderId)
        {
            HostingEnvironmentPolyfills.QueueBackgroundWorkItemPf(async ct =>
            {
                NewOrderEmailModel emailModel = new NewOrderEmailModel();

                OrdersProvider ordersProvider = new OrdersProvider();
                Order order = await ordersProvider.GetFullOrderData(orderId);

                string toEmailAddress;
                using (ApplicationDbContext appContext = new ApplicationDbContext())
                {
                    string userId = order.UserId.ToString();
                    Address userAddress = await appContext.AddressInfos.FirstOrDefaultAsync(a => a.UserId == userId);

                    emailModel.Country = userAddress.Country;
                    emailModel.City = userAddress.City;
                    emailModel.District = userAddress.District;
                    emailModel.PostCode = userAddress.PostCode;
                    emailModel.Commune = userAddress.Commune;
                    emailModel.AddresDetails = userAddress.AddresDetails;
                    emailModel.FullName = string.Format("{0} {1} {2}", userAddress.FirstName, userAddress.MiddleName, userAddress.LastName);
                    emailModel.Phone = userAddress.Phone;
                    toEmailAddress = userAddress.Email;
                }

                emailModel.BaseUrl = ConfigurationManager.AppSettings["Site.BaseUrl"];
                emailModel.ContactUsFormUrl = string.Concat(emailModel.BaseUrl, ConfigurationManager.AppSettings["Site.ContactUsFormUrl"].TrimStart('/'));
                emailModel.OrdersPageUrl = string.Concat(emailModel.BaseUrl, ConfigurationManager.AppSettings["Site.OrdersPageUrl"].TrimStart('/'));

                emailModel.OrderNumber = order.Id;
                emailModel.CommissionPercents = order.HasCommission ? order.CommissionPercents : 0;
                emailModel.DeliveryMerchant = order.DeliveryMerchant;
                emailModel.ShippingPrice = order.ShippingPrice.ToString("N2") + "лв";
                emailModel.TotalPrice = order.TotalPrice.ToString("N2") + "лв";
                emailModel.Items = order.OrderDetails.Select(od => new Item()
                {
                    Title = od.Article.Title,
                    Quantity = od.Quantity,
                    Price = od.ItemPrice.ToString("N2") + "лв"
                }).ToList();

                string emailContent = templateEngine.RenderTemplate("NewOrder", emailModel);

                await this.mailSender.SendEmail(toEmailAddress, string.Format("{0}: Поръчка #{1}", emailModel.BaseUrl, emailModel.OrderNumber), emailContent);
            });
        }
        public void SendOrderStatusChangedMail(int orderId, int oldStatusId, int newStatusId)
        {
            if (oldStatusId == newStatusId)
            {
                return;
            }

            HostingEnvironmentPolyfills.QueueBackgroundWorkItemPf(async ct =>
            {
                OrdersProvider ordersProvider = new OrdersProvider();
                Task<OrderStatusModel> getNewStatusTask = ordersProvider.GetStatus(newStatusId);
                Task<OrderStatusModel> getOldStatusTask = ordersProvider.GetStatus(oldStatusId);

                OrderStatusChangedEmailModel emailModel = new OrderStatusChangedEmailModel();
                emailModel.OrderNumber = orderId;

                SimpleOrderModel orderModel = await ordersProvider.GetOrder(orderId);

                string toEmailAddress;
                using (ApplicationDbContext appContext = new ApplicationDbContext())
                {
                    string userId = orderModel.UserId.ToString();
                    Address userAddress = await appContext.AddressInfos.FirstOrDefaultAsync(a => a.UserId == userId);
                    emailModel.FullName = string.Format("{0} {1} {2}", userAddress.FirstName, userAddress.MiddleName, userAddress.LastName);

                    toEmailAddress = userAddress.Email;
                }

                emailModel.BaseUrl = ConfigurationManager.AppSettings["Site.BaseUrl"];

                OrderStatusModel newOrderStatus = await getNewStatusTask;
                OrderStatusModel oldOrderStatus = await getOldStatusTask;

                emailModel.NewOrderStatus = newOrderStatus.Name;
                emailModel.OldOrderStatus = oldOrderStatus.Name;

                string emailContent = templateEngine.RenderTemplate("OrderStatusChanged", emailModel);

                await this.mailSender.SendEmail(toEmailAddress, string.Format("{0}: Статусът на поръчка #{1} беше променен", emailModel.BaseUrl, orderId), emailContent);
            });
        }
        public async Task<IHttpActionResult> GetOrderHistory(int orderId)
        {
            Guid userId = new Guid(this.User.Identity.GetUserId());

            OrdersProvider ordersProvider = new OrdersProvider();
            IEnumerable<StatusHistoryModel> orderItems = await ordersProvider.GetOrderHistory(orderId, userId);

            return this.Ok(orderItems);
        }
        public async Task<IHttpActionResult> GetCurrentUserOrders()
        {
            Guid userId = new Guid(this.User.Identity.GetUserId());

            OrdersProvider ordersProvider = new OrdersProvider();
            IEnumerable<OrderModel> userOrders = await ordersProvider.GetOrdersByUserId(userId);

            return this.Ok(userOrders);
        }
        public async Task<IHttpActionResult> ValidateAndSaveOrder(FullOrderModel order)
        {
            if (!this.ModelState.IsValid)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: invalid model state");

                return this.BadRequest(this.ModelState);
            }

            if (order.Items.Count() == 0)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: no items");

                return this.BadRequest("Empty order");
            }

            OrderItemsGrouper itemsGrouper = new OrderItemsGrouper();
            IList<OrderedItemModel> normalizedItems = itemsGrouper.NormalizeOrderedItems(order.Items.ToList());
            if (normalizedItems == null)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: grouping error");

                return this.BadRequest("Different prices of the same item");
            }

            OrderValidator orderValidator = new OrderValidator();
            bool areOrderItemsValid = await orderValidator.ValidateOrderItems(normalizedItems);

            if (!areOrderItemsValid)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: invalid quantities");

                return this.BadRequest("Invalid quantities");
            }

            bool freeShipping = order.Coupones != null && order.Coupones.Any(c => c.FreeShipping.Value);

            IModelTracker<DeliveryMethodModel> deliveryMethodModelTracker = new DeliveryMethodsTrackerFactory().GetDeliveryMethodsTracker(freeShipping);
            IModelTracker<PaymentMethodModel> paymentMethodModelTracker = new PaymentMethodsTrackerFactory().GetPaymentMethodsTracker(freeShipping);
            bool isLoyal = deliveryMethodModelTracker is FreeShippingDeliveryMethodsTracker;
            DeliveryMethodsProvider deliveryMethodsProvider = new DeliveryMethodsProvider(deliveryMethodModelTracker);
            PaymentMethodsProvider paymentMethodsProvider = new PaymentMethodsProvider(paymentMethodModelTracker);

            if (order.Coupones != null)
            {
                bool areCouponesValid = await orderValidator.ValidateCoupones(this.User.Identity.GetUserId(), order);
                if (!areCouponesValid)
                {
                    Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: invalid coupones");

                    return this.BadRequest("Invalid coupones");
                }
            }

            bool areOrderPricesValid = await orderValidator.ValidatePrices(order, deliveryMethodsProvider, paymentMethodsProvider);
            if (!areOrderPricesValid)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: invalid prive");

                return this.BadRequest("Invalid price");
            }

            StocksProvider stocksProvider = new StocksProvider();
            bool stockQuantitiesUpdatedSuccessfully = await stocksProvider.UpdateStocks(
                normalizedItems.Select(o => new StockChangeModel(o.ArticleId.Value, o.SizeId.Value, o.ColorId, -o.Quantity.Value)),
                Logger.Current);
            if (!stockQuantitiesUpdatedSuccessfully)
            {
                Logger.Current.LogWarning("Orders.ValidateAndSaveOrder: invalid quantities (update stocks)");

                return this.BadRequest("Invalid quantities");
            }

            
            Task<DeliveryMethodModel> getDeliveryMethodTask = deliveryMethodsProvider.GetDeliveryMethodById(order.DeliveryMethodId.Value);
            Task<PaymentMethodModel> getPaymentMethodTask = paymentMethodsProvider.GetPaymentMethodById(order.PaymentMethodId.Value);

            DeliveryMethodModel deliveryMethod = await getDeliveryMethodTask;
            PaymentMethodModel paymentMethod = await getPaymentMethodTask;

            Order newOrder = new Order();
            newOrder.UserId = new Guid(this.User.Identity.GetUserId());
            newOrder.DeliveryMerchant = deliveryMethod.Name;
            newOrder.DeliveryPrice = deliveryMethod.DeliveryPrice;
            newOrder.PaymentMethodId = paymentMethod.Id;
            newOrder.HasCommission = paymentMethod.ApplyDeliveryTax;
            newOrder.CommissionPercents = deliveryMethod.CODTax;
            newOrder.ShippingPrice = order.Total.Shipping.Value;
            newOrder.ItemsPrice = order.Total.Order.Value;
            newOrder.TotalPrice = order.Total.Full.Value;
            newOrder.StatusId = 1;
            newOrder.DateCreated = DateTime.UtcNow;

            List<OrderDetail> orderDetails = new List<OrderDetail>();
            foreach (OrderedItemModel orderedItem in normalizedItems)
            {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.ItemId = orderedItem.ArticleId.Value;
                orderDetail.SizeId = orderedItem.SizeId.Value;
                orderDetail.ColorId = orderedItem.ColorId;
                orderDetail.Quantity = orderedItem.Quantity.Value;
                orderDetail.ItemPrice = orderedItem.Price.Value;

                orderDetails.Add(orderDetail);
            }

            OrdersProvider ordersProvider = new OrdersProvider();
            int newOrderId = await ordersProvider.SaveOrder(newOrder, orderDetails);

            MailSendingFacade mailSender = new MailSendingFacade();
            mailSender.SendNewOrderMail(newOrderId);

            return this.Ok(newOrderId);
        }