private XmlNode BuildOrderXml(XmlDocument xmlDocument, Order order, RenderOrderSettings settings)
        {
            var tableNode = CreateTableNode(xmlDocument, "EcomOrders");
            var itemNode  = CreateAndAppendItemNode(tableNode, "EcomOrders");

            var user = User.GetUserByID(order.CustomerAccessUserId) ?? (!ExecutingContext.IsBackEnd() ? User.GetCurrentExtranetUser() : null);

            // do not use order.Modified in XML unless the field can be ignored for hash calculation

            // in the current version of NAV for vanBaerle, the calculation is made using the ExternalId field name but the logic corresonds to the customer number in DynamicWeb
            //AddChildXmlNode(itemNode, "OrderCustomerAccessUserExternalId", !string.IsNullOrWhiteSpace(user?.ExternalID) ? user.ExternalID : Settings.Instance.AnonymousUserKey);
            AddChildXmlNode(itemNode, "OrderCustomerAccessUserExternalId", !string.IsNullOrWhiteSpace(user?.CustomerNumber) ? user.CustomerNumber : Settings.Instance.AnonymousUserKey);


            AddChildXmlNode(itemNode, "OrderCustomerNumber", !string.IsNullOrWhiteSpace(user?.CustomerNumber) ? user.CustomerNumber : Settings.Instance.AnonymousUserKey);
            AddChildXmlNode(itemNode, "CreateOrder", settings.CreateOrder.ToString());
            AddChildXmlNode(itemNode, "OrderId", order.Id);
            AddChildXmlNode(itemNode, "OrderAutoId", order.AutoId.ToString());
            AddChildXmlNode(itemNode, "OrderIntegrationOrderId", order.IntegrationOrderId);
            AddChildXmlNode(itemNode, "OrderCurrencyCode", order.CurrencyCode);
            AddChildXmlNode(itemNode, "OrderDate", order.Date.ToIntegrationString());
            AddChildXmlNode(itemNode, "OrderPaymentMethodName", order.PaymentMethod, true);
            AddChildXmlNode(itemNode, "OrderPaymentMethodId", order.PaymentMethodId);
            AddChildXmlNode(itemNode, "OrderShippingMethodName", order.ShippingMethod, true);
            AddChildXmlNode(itemNode, "OrderShippingMethodId", order.ShippingMethodId);
            AddChildXmlNode(itemNode, "OrderShippingFee", order.ShippingFee.PriceWithoutVAT.ToIntegrationString());
            AddChildXmlNode(itemNode, "OrderCustomerName", order.CustomerName);
            AddChildXmlNode(itemNode, "OrderCustomerAddress", order.CustomerAddress);
            AddChildXmlNode(itemNode, "OrderCustomerAddress2", order.CustomerAddress2);
            AddChildXmlNode(itemNode, "OrderCustomerCity", order.CustomerCity);
            AddChildXmlNode(itemNode, "OrderCustomerState", order.CustomerRegion);
            AddChildXmlNode(itemNode, "OrderCustomerZip", order.CustomerZip);
            AddChildXmlNode(itemNode, "OrderCustomerCountryCode", order.CustomerCountryCode);
            AddChildXmlNode(itemNode, "OrderCustomerEmail", order.CustomerEmail);
            AddChildXmlNode(itemNode, "OrderCustomerPhone", order.CustomerPhone);
            AddChildXmlNode(itemNode, "OrderCustomerFax", order.CustomerFax);
            AddChildXmlNode(itemNode, "OrderDeliveryName", !string.IsNullOrWhiteSpace(order.DeliveryName) ? order.DeliveryName : order.CustomerName);
            AddChildXmlNode(itemNode, "OrderDeliveryAddress", order.DeliveryAddress);
            AddChildXmlNode(itemNode, "OrderDeliveryAddress2", order.DeliveryAddress2);
            AddChildXmlNode(itemNode, "OrderDeliveryCity", order.DeliveryCity);
            AddChildXmlNode(itemNode, "OrderDeliveryState", order.DeliveryRegion);
            AddChildXmlNode(itemNode, "OrderDeliveryZip", order.DeliveryZip);
            AddChildXmlNode(itemNode, "OrderDeliveryCountryCode", order.DeliveryCountryCode);
            AddChildXmlNode(itemNode, "OrderDeliveryEmail", order.DeliveryEmail);
            AddChildXmlNode(itemNode, "OrderDeliveryPhone", order.DeliveryPhone);
            AddChildXmlNode(itemNode, "OrderDeliveryFax", order.DeliveryFax);
            AddChildXmlNode(itemNode, "OrderCustomerComment", order.CustomerComment);
            AddChildXmlNode(itemNode, "OrderPriceTotal", order.TotalPrice.ToIntegrationString());
            AddChildXmlNode(itemNode, "OrderCaptureAmount", order.CaptureAmount.ToIntegrationString());
            AddChildXmlNode(itemNode, "OrderVoucherCode", order.VoucherCode);
            AddChildXmlNode(itemNode, "OrderTransactionId", order.TransactionNumber);
            AddChildXmlNode(itemNode, "OrderStateId", order.StateId);
            AddChildXmlNode(itemNode, "OrderStateName", order.OrderState.Name, true);

            CreditCardGatewayResult paymentInformation = ReadPaymentInformation(order);

            AddChildXmlNode(itemNode, "OrderTransactionCardType", paymentInformation.Type, true);
            AddChildXmlNode(itemNode, "OrderTransactionCardExpiryDate", paymentInformation.ExpiryDate, true);
            AddChildXmlNode(itemNode, "OrderTransactionMaskedCreditCardNumber", paymentInformation.Number, true);
            AddChildXmlNode(itemNode, "CardHolderFirstName", paymentInformation.FirstName, true);
            AddChildXmlNode(itemNode, "CardholderLastName", paymentInformation.LastName, true);

            if (settings.AddOrderFieldsToRequest)
            {
                AppendOrderFields(order, itemNode);
            }
            return(tableNode);
        }
        /// <summary>
        /// Updates an order in the ERP.
        /// </summary>
        /// <param name="order">The order that must be synced with the ERP.</param>
        /// <param name="liveIntegrationSubmitType">Determines the origin of this submit such.</param>
        /// <param name="successOrderStateId">The order state that is applied to the order when it integrates successfully.</param>
        /// <param name="failedOrderStateId">The order state that is applied to the order when an error occurred during the integration.</param>
        /// <returns>Returns null if no communication has made, or bool if order has been updated successfully or not.</returns>
        public static bool?UpdateOrder(Order order, LiveIntegrationSubmitType liveIntegrationSubmitType, string successOrderStateId = null, string failedOrderStateId = null)
        {
            if (order == null || !order.OrderLines.Any())
            {
                return(null);
            }
            if (liveIntegrationSubmitType == LiveIntegrationSubmitType.LiveOrderOrCart && !string.IsNullOrEmpty(order.IntegrationOrderId))
            {
                return(null);
            }

            var orderId = order.Id ?? "ID is null";

            Logger.Instance.Log(ErrorLevel.DebugInfo, string.Format("Updating order with ID: {0}. Complete: {1}. Order submitted from the backend: {2}. Stack trace: {3}", orderId, order.Complete, ExecutingContext.IsBackEnd(), Environment.StackTrace));

            // use current user if is not backend running or if the cart is Anonymous
            var user = (order.CustomerAccessUserId > 0 ? User.GetUserByID(order.CustomerAccessUserId) : null)
                       ?? (!ExecutingContext.IsBackEnd() ? User.GetCurrentExtranetUser() : null);

            // customization for VanBaerle branch: ERP doesn't support anonymous users and throws errors
            if (user == null)
            {
                return(null);
            }

            /* create order: if it is false, you will get a calculate order from the ERP with the total prices */
            /* if it is true, then a new order will be created in the ERP */
            bool createOrder = order.Complete;

            if (createOrder && user != null)
            {
                UserSync(user);
            }

            if (!Settings.Instance.EnableCartCommunicationForAnonymousUsers && user == null)
            {
                Logger.Instance.Log(ErrorLevel.DebugInfo, string.Format("No user is currently logged in. Anonymous user cart is not allowed. Order = {0}", orderId));
                return(null);
            }

            // default states
            if (successOrderStateId == null)
            {
                successOrderStateId = Settings.Instance.OrderStateAfterExportSucceeded;
            }
            if (failedOrderStateId == null)
            {
                failedOrderStateId = Settings.Instance.OrderStateAfterExportFailed;
            }

            var requestXml = new OrderXmlRenderer().RenderOrderXml(order, new RenderOrderSettings {
                AddOrderLineFieldsToRequest = AddOrderLineFieldsToRequest, AddOrderFieldsToRequest = AddOrderFieldsToRequest, CreateOrder = createOrder, LiveIntegrationSubmitType = liveIntegrationSubmitType, ReferenceName = "OrdersPut"
            });

            if (createOrder && SaveOrderXml && liveIntegrationSubmitType == LiveIntegrationSubmitType.LiveOrderOrCart)
            {
                SaveCopyOfXml(order.Id, requestXml);
            }

            // calculate current hash
            string currentHash = CalculateHash(requestXml);

            // get last hash
            string lastHash = GetLastOrderHash();

            if (!string.IsNullOrEmpty(lastHash) && lastHash == currentHash)
            {
                // no changes to order
                return(null);
            }
            // save this hash for next calls
            SaveOrderHash(currentHash);

            // clear all session var to avoid miss calculations
            HttpContext.Current.Session.Remove("LiveIntegrationDiscounts" + order.Id);

            Dictionary <string, XmlDocument> responsesCache = ErpResponseCache.GetWebOrdersConnectorResponses(OrderCacheLevel);

            XmlDocument response = null;

            if (!createOrder && responsesCache.ContainsKey(requestXml))
            {
                response = responsesCache[requestXml];
            }
            else
            {
                if (createOrder)
                {
                    OrderDebuggingInfo.Save(order, "Sending order to the ERP system through Live Integration.", "OrderHandler");
                }
                try
                {
                    response = Connector.CalculateOrder(requestXml, order.Id, createOrder);
                }
                catch (LiveIntegrationException ex)
                {
                    // TODO Rui, handle appropriately
                    Logger.Instance.Log(ErrorLevel.ConnectionError, ex.Message);
                }
                if (responsesCache.ContainsKey(requestXml))
                {
                    responsesCache.Remove(requestXml);
                }
                if (!string.IsNullOrWhiteSpace(response?.InnerXml))
                {
                    responsesCache.Add(requestXml, response);
                }
            }
            if (!string.IsNullOrWhiteSpace(response?.InnerXml))
            {
                bool processResponseResult = ProcessResponse(response, order, createOrder, successOrderStateId, failedOrderStateId);

                // new user sync active, sync user (Update)
                if (Settings.Instance.UpdateUserAfterNewOrder && user != null)
                {
                    user.SynchronizeUsingLiveIntegration(true, UserSyncMode.Get);
                }

                return(processResponseResult);
            }
            else
            {
                //error occurred
                CheckIfOrderShouldRevertToCart(order, createOrder);
                return(false);
            }
        }