/// <summary>
        /// Deletes an order
        /// </summary>
        /// <param name="order">The order</param>
        public virtual void DeleteOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            order.Deleted = true;
            UpdateOrder(order);
        }
        /// <summary>
        /// Gets a value indicating whether cancel is allowed
        /// </summary>
        /// <param name="order">Order</param>
        /// <returns>
        /// A value indicating whether cancel is allowed
        /// </returns>
        /// <exception cref="System.ArgumentNullException">order</exception>
        public bool CanCancelOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (order.OrderStatus == OrderStatus.Cancelled)
                return false;

            return true;
        }
        /// <summary>
        /// Cancels order
        /// </summary>
        /// <param name="order">Order</param>
        /// <param name="notifyCustomer">True to notify customer</param>
        /// <exception cref="System.ArgumentNullException">order</exception>
        /// <exception cref="AFException">Cannot do cancel for order.</exception>
        public void CancelOrder(Order order, bool notifyCustomer)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (!CanCancelOrder(order))
                throw new AFException("Cannot do cancel for order.");

            //Cancel order
            SetOrderStatus(order, OrderStatus.Cancelled, notifyCustomer);

            //add a note
            order.OrderNotes.Add(new OrderNote
            {
                Note = "Order has been cancelled",
                CreatedOn = DateTime.Now
            });
            _orderService.UpdateOrder(order);
            _eventPublisher.Publish(new OrderCancelledEvent(order));
        }
        /// <summary>
        /// Updates the order
        /// </summary>
        /// <param name="order">The order</param>
        public virtual void UpdateOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            _orderRepository.Update(order);

            //event notification
            _eventPublisher.EntityUpdated(order);
        }
        /// <summary>
        /// Places an order
        /// </summary>
        /// <param name="processPaymentRequest">Process payment request</param>
        /// <returns>
        /// Place order result
        /// </returns>
        /// <exception cref="System.ArgumentNullException">processPaymentRequest</exception>
        public PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest)
        {
            //think about moving functionality of processing recurring orders (after the initial order was placed) to ProcessNextRecurringPayment() method
            if (processPaymentRequest == null)
                throw new ArgumentNullException("processPaymentRequest");

            var result = new PlaceOrderResult();
            try
            {
                if (processPaymentRequest.OrderGuid == Guid.Empty)
                    processPaymentRequest.OrderGuid = Guid.NewGuid();

                #region Payment workflow

                //process payment
                var processPaymentResult = new ProcessPaymentResult { NewPaymentStatus = PaymentStatus.Pending };

                #endregion

                if (processPaymentResult.Success)
                {
                    #region Save order details

                    var order = new Order
                    {
                        OrderGuid = processPaymentRequest.OrderGuid,
                        CustomerId = processPaymentRequest.CustomerId,
                        CustomerIp = _webHelper.GetCurrentIpAddress(),
                        OrderTotal = processPaymentRequest.OrderTotal,
                        RefundedAmount = decimal.Zero,
                        OrderStatus = OrderStatus.Pending,
                        PaymentMethod = processPaymentRequest.PaymentMethod,
                        PaymentStatus = processPaymentResult.NewPaymentStatus,
                        PaidDate = null,
                        CreatedTime = DateTime.Now
                    };
                    order.TradeNo = order.OrderGuid.ToString("N");

                    _orderService.InsertOrder(order);
                    result.PlacedOrder = order;

                    #endregion

                    #region Notifications & notes

                    //notes, messages
                    order.OrderNotes.Add(new OrderNote
                    {
                        Note = "Order placed",
                        CreatedOn = DateTime.Now
                    });
                    _orderService.UpdateOrder(order);

                    //send email notifications
                    /*           order.OrderNotes.Add(new OrderNote
                               {
                                   Note = string.Format("\"Order placed\" email (to store owner) has been queued. Queued email identifier: {0}.", orderPlacedStoreOwnerNotificationQueuedEmailId),
                                   DisplayToCustomer = false,
                                   CreatedOn = DateTime.Now
                               });
                               _orderService.UpdateOrder(order);*/

                    //check order status
                    CheckOrderStatus(order);

                    //raise event
                    _eventPublisher.Publish(new OrderPlacedEvent(order));

                    if (order.PaymentStatus == PaymentStatus.Paid)
                    {
                        //raise event
                        _eventPublisher.Publish(new OrderPaidEvent(order));
                    }
                    #endregion
                }
                else
                {
                    foreach (var paymentError in processPaymentResult.Errors)
                        result.AddError(paymentError);
                }
            }
            catch (Exception exc)
            {
                _logger.Error(exc.Message, exc);
                result.AddError(exc.Message);
            }

            #region Process errors

            string error = "";
            for (int i = 0; i < result.Errors.Count; i++)
            {
                error += string.Format("Error {0}: {1}", i + 1, result.Errors[i]);
                if (i != result.Errors.Count - 1)
                    error += ". ";
            }
            if (!String.IsNullOrEmpty(error))
            {
                //log it
                string logError = string.Format("Error while placing order. {0}", error);
                _logger.Error(logError);
            }

            #endregion

            return result;
        }
        /// <summary>
        /// Sets an order status
        /// </summary>
        /// <param name="order">Order</param>
        /// <param name="os">New order status</param>
        /// <param name="notifyCustomer">if set to <c>true</c> [notify customer].</param>
        /// <exception cref="System.ArgumentNullException">order</exception>
        protected virtual void SetOrderStatus(Order order, OrderStatus os, bool notifyCustomer)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            OrderStatus prevOrderStatus = order.OrderStatus;
            if (prevOrderStatus == os)
                return;

            //set and save new order status
            order.OrderStatusId = (int)os;
            _orderService.UpdateOrder(order);

            //order notes, notifications
            order.OrderNotes.Add(new OrderNote
            {
                Note = string.Format("Order status has been changed to {0}", os.ToString()),
                CreatedOn = DateTime.Now
            });
            _orderService.UpdateOrder(order);

            /*            if (prevOrderStatus != OrderStatus.Complete &&
                os == OrderStatus.Complete && notifyCustomer)
            {
                //notification or email to customer
                order.OrderNotes.Add(new OrderNote
                {
                    Note =
                        string.Format(
                            "\"Order completed\" email (to customer) has been queued. Queued email identifier: {0}.",
                            _workContext.CurrentCustomer.Email),
                    CreatedOn = DateTime.Now
                });
                _orderService.UpdateOrder(order);
            }

            if (prevOrderStatus != OrderStatus.Cancelled &&
                os == OrderStatus.Cancelled
                && notifyCustomer)
            {
                //notification
                order.OrderNotes.Add(new OrderNote
                {
                    Note =
                        string.Format(
                            "\"Order cancelled\" email (to customer) has been queued. Queued email identifier: {0}.",
                            _workContext.CurrentCustomer.Email),
                    CreatedOn = DateTime.Now
                });
                _orderService.UpdateOrder(order);
            }*/
        }
        /// <summary>
        /// Marks order as paid
        /// </summary>
        /// <param name="order">Order</param>
        public virtual void MarkOrderAsPaid(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (!CanMarkOrderAsPaid(order))
                throw new AFException("You can't mark this order as paid");

            order.PaymentStatusId = (int)PaymentStatus.Paid;
            order.PaidDate = DateTime.Now;
            _orderService.UpdateOrder(order);

            //add a note
            order.OrderNotes.Add(new OrderNote
            {
                Note = "Order has been marked as paid",
                CreatedOn = DateTime.Now
            });
            _orderService.UpdateOrder(order);

            CheckOrderStatus(order);

            if (order.PaymentStatus == PaymentStatus.Paid)
            {
                //raise event
                _eventPublisher.Publish(new OrderPaidEvent(order));
            }
        }
        /// <summary>
        /// Deletes an order
        /// </summary>
        /// <param name="order">The order</param>
        /// <exception cref="System.ArgumentNullException">order</exception>
        public void DeleteOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            //add a note
            order.OrderNotes.Add(new OrderNote
            {
                Note = "Order has been deleted",
                CreatedOn = DateTime.Now
            });
            _orderService.UpdateOrder(order);

            //now delete an order
            _orderService.DeleteOrder(order);
        }
        /// <summary>
        /// Checks order status
        /// </summary>
        /// <param name="order">Order</param>
        /// <returns>Validated order</returns>
        public virtual void CheckOrderStatus(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (order.PaymentStatus == PaymentStatus.Paid && !order.PaidDate.HasValue)
            {
                //ensure that paid date is set
                order.PaidDate = DateTime.Now;
                _orderService.UpdateOrder(order);
            }

            if (order.OrderStatus == OrderStatus.Pending)
            {
                if (order.PaymentStatus == PaymentStatus.Paid)
                {
                    SetOrderStatus(order, OrderStatus.Processing, false);
                }
            }

            if (order.OrderStatus != OrderStatus.Cancelled &&
                order.OrderStatus != OrderStatus.Complete)
            {
                if (order.PaymentStatus == PaymentStatus.Paid)
                {
                    SetOrderStatus(order, OrderStatus.Complete, true);
                }
            }
        }
        /// <summary>
        /// Gets a value indicating whether refund from admin panel is allowed
        /// </summary>
        /// <param name="order">Order</param>
        /// <returns>A value indicating whether refund from admin panel is allowed</returns>
        public virtual bool CanRefund(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (order.OrderTotal == decimal.Zero)
                return false;

            //uncomment the lines below in order to allow this operation for cancelled orders
            //if (order.OrderStatus == OrderStatus.Cancelled)
            //    return false;

            if (order.PaymentStatus == PaymentStatus.Paid)
                return true;

            return false;
        }
        /// <summary>
        /// Gets a value indicating whether order can be marked as paid
        /// </summary>
        /// <param name="order">Order</param>
        /// <returns>A value indicating whether order can be marked as paid</returns>
        public virtual bool CanMarkOrderAsPaid(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (order.OrderStatus == OrderStatus.Cancelled)
                return false;

            if (order.PaymentStatus == PaymentStatus.Paid ||
                order.PaymentStatus == PaymentStatus.Refunded ||
                order.PaymentStatus == PaymentStatus.Voided)
                return false;

            return true;
        }