/// <summary>
        /// Auto update order details
        /// </summary>
        /// <param name="context">Context parameters</param>
        public virtual void AutoUpdateOrderDetails(AutoUpdateOrderItemContext context)
        {
            var oi = context.OrderItem;

            context.RewardPointsOld = context.RewardPointsNew = oi.Order.Customer.GetRewardPointsBalance();

            if (context.UpdateTotals && oi.Order.OrderStatusId <= (int)OrderStatus.Pending)
            {
                decimal priceInclTax = Round(context.QuantityNew * oi.UnitPriceInclTax);
                decimal priceExclTax = Round(context.QuantityNew * oi.UnitPriceExclTax);

                decimal deltaPriceInclTax = priceInclTax - (context.IsNewOrderItem ? decimal.Zero : oi.PriceInclTax);
                decimal deltaPriceExclTax = priceExclTax - (context.IsNewOrderItem ? decimal.Zero : oi.PriceExclTax);

                oi.Quantity = context.QuantityNew;
                oi.PriceInclTax = Round(priceInclTax);
                oi.PriceExclTax = Round(priceExclTax);

                decimal subtotalInclTax = oi.Order.OrderSubtotalInclTax + deltaPriceInclTax;
                decimal subtotalExclTax = oi.Order.OrderSubtotalExclTax + deltaPriceExclTax;

                oi.Order.OrderSubtotalInclTax = Round(subtotalInclTax);
                oi.Order.OrderSubtotalExclTax = Round(subtotalExclTax);

                decimal discountInclTax = oi.DiscountAmountInclTax * context.QuantityChangeFactor;
                decimal discountExclTax = oi.DiscountAmountExclTax * context.QuantityChangeFactor;

                decimal deltaDiscountInclTax = discountInclTax - oi.DiscountAmountInclTax;
                decimal deltaDiscountExclTax = discountExclTax - oi.DiscountAmountExclTax;

                oi.DiscountAmountInclTax = Round(discountInclTax);
                oi.DiscountAmountExclTax = Round(discountExclTax);

                decimal total = Math.Max(oi.Order.OrderTotal + deltaPriceInclTax, 0);
                decimal tax = Math.Max(oi.Order.OrderTax + (deltaPriceInclTax - deltaPriceExclTax), 0);

                oi.Order.OrderTotal = Round(total);
                oi.Order.OrderTax = Round(tax);

                _orderService.UpdateOrder(oi.Order);
            }

            if (context.AdjustInventory && context.QuantityDelta != 0)
            {
                context.Inventory = _productService.AdjustInventory(oi, context.QuantityDelta > 0, Math.Abs(context.QuantityDelta));
            }

            if (context.UpdateRewardPoints && context.QuantityDelta < 0)
            {
                // we reduce but we do not award points subsequently. they can be awarded once per order anyway (see Order.RewardPointsWereAdded).
                // UpdateRewardPoints only visible for unpending orders (see RewardPointsSettingsValidator).
                // note: reducing can of cource only work if oi.UnitPriceExclTax has not been changed!
                decimal reduceAmount = Math.Abs(context.QuantityDelta) * oi.UnitPriceInclTax;
                ReduceRewardPoints(oi.Order, reduceAmount);
                context.RewardPointsNew = oi.Order.Customer.GetRewardPointsBalance();
            }
        }
        public ActionResult DeleteOrderItem(AutoUpdateOrderItemModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders))
                return AccessDeniedView();

            var oi = _orderService.GetOrderItemById(model.Id);

            if (oi == null)
                throw new ArgumentException("No order item found with the specified id");

            int orderId = oi.Order.Id;
            var context = new AutoUpdateOrderItemContext()
            {
                OrderItem = oi,
                QuantityOld = oi.Quantity,
                QuantityNew = 0,
                AdjustInventory = model.AdjustInventory,
                UpdateRewardPoints = model.UpdateRewardPoints,
                UpdateTotals = model.UpdateTotals
            };

            _orderProcessingService.AutoUpdateOrderDetails(context);

            _orderService.DeleteOrderItem(oi);

            TempData[AutoUpdateOrderItemContext.InfoKey] = context.ToString(_localizationService);

            return RedirectToAction("Edit", new { id = orderId });
        }
        public ActionResult EditOrderItem(AutoUpdateOrderItemModel model, FormCollection form)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders))
                return AccessDeniedView();

            var oi = _orderService.GetOrderItemById(model.Id);

            if (oi == null)
                throw new ArgumentException("No order item found with the specified id");

            int orderId = oi.Order.Id;

            if (model.NewQuantity.HasValue)
            {
                var context = new AutoUpdateOrderItemContext()
                {
                    OrderItem = oi,
                    QuantityOld = oi.Quantity,
                    QuantityNew = model.NewQuantity.Value,
                    AdjustInventory = model.AdjustInventory,
                    UpdateRewardPoints = model.UpdateRewardPoints,
                    UpdateTotals = model.UpdateTotals
                };

                oi.Quantity = model.NewQuantity.Value;
                oi.UnitPriceInclTax = model.NewUnitPriceInclTax ?? oi.UnitPriceInclTax;
                oi.UnitPriceExclTax = model.NewUnitPriceExclTax ?? oi.UnitPriceExclTax;
                oi.DiscountAmountInclTax = model.NewDiscountInclTax ?? oi.DiscountAmountInclTax;
                oi.DiscountAmountExclTax = model.NewDiscountExclTax ?? oi.DiscountAmountExclTax;
                oi.PriceInclTax = model.NewPriceInclTax ?? oi.PriceInclTax;
                oi.PriceExclTax = model.NewPriceExclTax ?? oi.PriceExclTax;

                _orderService.UpdateOrder(oi.Order);

                _orderProcessingService.AutoUpdateOrderDetails(context);

                // we do not delete order item automatically anymore.
                //if (oi.Quantity <= 0)
                //{
                //	_orderService.DeleteOrderItem(oi);
                //}

                TempData[AutoUpdateOrderItemContext.InfoKey] = context.ToString(_localizationService);
            }

            return RedirectToAction("Edit", new { id = orderId });
        }
        public ActionResult AddProductToOrderDetails(int orderId, int productId, bool adjustInventory, bool? updateTotals, FormCollection form)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders))
                return AccessDeniedView();

            var order = _orderService.GetOrderById(orderId);
            var product = _productService.GetProductById(productId);
            //save order item

            //basic properties
            var unitPriceInclTax = decimal.Zero;
            decimal.TryParse(form["UnitPriceInclTax"], out unitPriceInclTax);
            var unitPriceExclTax = decimal.Zero;
            decimal.TryParse(form["UnitPriceExclTax"], out unitPriceExclTax);
            var quantity = 1;
            int.TryParse(form["Quantity"], out quantity);
            var priceInclTax = decimal.Zero;
            decimal.TryParse(form["SubTotalInclTax"], out priceInclTax);
            var priceExclTax = decimal.Zero;
            decimal.TryParse(form["SubTotalExclTax"], out priceExclTax);

            var warnings = new List<string>();
            string attributes = "";

            if (product.ProductType != ProductType.BundledProduct)
            {
                var variantAttributes = _productAttributeService.GetProductVariantAttributesByProductId(product.Id);

                attributes = form.CreateSelectedAttributesXml(product.Id, variantAttributes, _productAttributeParser, _localizationService, _downloadService,
                    _catalogSettings, this.Request, warnings, false);
            }

            #region Gift cards

            string recipientName = "";
            string recipientEmail = "";
            string senderName = "";
            string senderEmail = "";
            string giftCardMessage = "";
            if (product.IsGiftCard)
            {
                foreach (string formKey in form.AllKeys)
                {
                    if (formKey.Equals("giftcard.RecipientName", StringComparison.InvariantCultureIgnoreCase))
                    {
                        recipientName = form[formKey];
                        continue;
                    }
                    if (formKey.Equals("giftcard.RecipientEmail", StringComparison.InvariantCultureIgnoreCase))
                    {
                        recipientEmail = form[formKey];
                        continue;
                    }
                    if (formKey.Equals("giftcard.SenderName", StringComparison.InvariantCultureIgnoreCase))
                    {
                        senderName = form[formKey];
                        continue;
                    }
                    if (formKey.Equals("giftcard.SenderEmail", StringComparison.InvariantCultureIgnoreCase))
                    {
                        senderEmail = form[formKey];
                        continue;
                    }
                    if (formKey.Equals("giftcard.Message", StringComparison.InvariantCultureIgnoreCase))
                    {
                        giftCardMessage = form[formKey];
                        continue;
                    }
                }

                attributes = _productAttributeParser.AddGiftCardAttribute(attributes,
                    recipientName, recipientEmail, senderName, senderEmail, giftCardMessage);
            }

            #endregion

            //warnings
            warnings.AddRange(_shoppingCartService.GetShoppingCartItemAttributeWarnings(order.Customer, ShoppingCartType.ShoppingCart, product, attributes, quantity));
            warnings.AddRange(_shoppingCartService.GetShoppingCartItemGiftCardWarnings(ShoppingCartType.ShoppingCart, product, attributes));

            if (warnings.Count == 0)
            {
                //attributes
                string attributeDescription = _productAttributeFormatter.FormatAttributes(product, attributes, order.Customer);

                //save item
                var orderItem = new OrderItem()
                {
                    OrderItemGuid = Guid.NewGuid(),
                    Order = order,
                    ProductId = product.Id,
                    UnitPriceInclTax = unitPriceInclTax,
                    UnitPriceExclTax = unitPriceExclTax,
                    PriceInclTax = priceInclTax,
                    PriceExclTax = priceExclTax,
                    AttributeDescription = attributeDescription,
                    AttributesXml = attributes,
                    Quantity = quantity,
                    DiscountAmountInclTax = decimal.Zero,
                    DiscountAmountExclTax = decimal.Zero,
                    DownloadCount = 0,
                    IsDownloadActivated = false,
                    LicenseDownloadId = 0,
                    ProductCost = _priceCalculationService.GetProductCost(product, attributes)
                };

                if (product.ProductType == ProductType.BundledProduct)
                {
                    var listBundleData = new List<ProductBundleItemOrderData>();
                    var bundleItems = _productService.GetBundleItems(product.Id);

                    foreach (var bundleItem in bundleItems)
                    {
                        decimal taxRate;
                        decimal finalPrice = _priceCalculationService.GetFinalPrice(bundleItem.Item.Product, bundleItems, order.Customer, decimal.Zero, true, bundleItem.Item.Quantity);
                        decimal bundleItemSubTotalWithDiscountBase = _taxService.GetProductPrice(bundleItem.Item.Product, finalPrice, out taxRate);

                        bundleItem.ToOrderData(listBundleData, bundleItemSubTotalWithDiscountBase);
                    }

                    orderItem.SetBundleData(listBundleData);
                }

                order.OrderItems.Add(orderItem);
                _orderService.UpdateOrder(order);

                //gift cards
                if (product.IsGiftCard)
                {
                    for (int i = 0; i < orderItem.Quantity; i++)
                    {
                        var gc = new GiftCard()
                        {
                            GiftCardType = product.GiftCardType,
                            PurchasedWithOrderItem = orderItem,
                            Amount = unitPriceExclTax,
                            IsGiftCardActivated = false,
                            GiftCardCouponCode = _giftCardService.GenerateGiftCardCode(),
                            RecipientName = recipientName,
                            RecipientEmail = recipientEmail,
                            SenderName = senderName,
                            SenderEmail = senderEmail,
                            Message = giftCardMessage,
                            IsRecipientNotified = false,
                            CreatedOnUtc = DateTime.UtcNow
                        };
                        _giftCardService.InsertGiftCard(gc);
                    }
                }

                if (adjustInventory || (updateTotals ?? false))
                {
                    var context = new AutoUpdateOrderItemContext()
                    {
                        IsNewOrderItem = true,
                        OrderItem = orderItem,
                        QuantityOld = 0,
                        QuantityNew = orderItem.Quantity,
                        AdjustInventory = adjustInventory,
                        UpdateTotals = (updateTotals ?? false)
                    };

                    _orderProcessingService.AutoUpdateOrderDetails(context);

                    TempData[AutoUpdateOrderItemContext.InfoKey] = context.ToString(_localizationService);
                }

                //redirect to order details page
                return RedirectToAction("Edit", "Order", new { id = order.Id });
            }
            else
            {
                //errors
                var model = PrepareAddProductToOrderModel(order.Id, product.Id);
                model.Warnings.AddRange(warnings);
                return View(model);
            }
        }
		public ActionResult Accept(AutoUpdateOrderItemModel model)
		{
			if (!_permissionService.Authorize(StandardPermissionProvider.ManageReturnRequests))
				return AccessDeniedView();

			var returnRequest = _orderService.GetReturnRequestById(model.Id);
			var oi = _orderService.GetOrderItemById(returnRequest.OrderItemId);

			int cancelQuantity = (returnRequest.Quantity > oi.Quantity ? oi.Quantity : returnRequest.Quantity);

			var context = new AutoUpdateOrderItemContext()
			{
				OrderItem = oi,
				QuantityOld = oi.Quantity,
				QuantityNew = Math.Max(oi.Quantity - cancelQuantity, 0),
				AdjustInventory = model.AdjustInventory,
				UpdateRewardPoints = model.UpdateRewardPoints,
				UpdateTotals = model.UpdateTotals
			};

			returnRequest.ReturnRequestStatus = ReturnRequestStatus.ReturnAuthorized;
			_customerService.UpdateCustomer(returnRequest.Customer);

			_orderProcessingService.AutoUpdateOrderDetails(context);

			TempData[AutoUpdateOrderItemContext.InfoKey] = context.ToString(_localizationService);

			return RedirectToAction("Edit", new { id = returnRequest.Id });
		}