/// <summary> /// Checks whether the cache dependency has been changed from the last request. /// If the current request has a different signature that the previous one, the cache will be cleared. /// </summary> public static void ClearContextDependentCache(int userId) { string cacheKeyInfoStore = "ContextDependentCacheKeyInfoStore"; var session = System.Web.HttpContext.Current?.Session; string cacheKeyDependency = userId.ToString(); string existingCacheKeyDependency = (string)session?[cacheKeyInfoStore]; if (!string.Equals(cacheKeyDependency, existingCacheKeyDependency, StringComparison.OrdinalIgnoreCase)) { ErpResponseCache.ClearAllCaches(); if (session != null) { session[cacheKeyInfoStore] = cacheKeyDependency; } } }
// Fills the values from Response on the Product public static void FillProductValues(Product product, double quantity = 1) { if (product != null && ErpResponseCache.IsProductInCache(ProductCacheLevel, Helpers.ProductIdentifier(product))) { Dictionary <string, ProductInfo> piCache = ErpResponseCache.GetProductInfos(ProductCacheLevel); if (piCache.ContainsKey(Helpers.ProductIdentifier(product))) { ProductInfo productInfo = piCache[Helpers.ProductIdentifier(product)]; double?newStock = (double?)productInfo["Stock"]; if (newStock.HasValue && product.Stock != newStock) { product.Stock = newStock.Value; product.Save(); productInfo["Stock"] = null; } //product.Stock = (double)productInfo["Stock"]; FillProductPrices(product, productInfo); double?priceValue = SelectPrice(productInfo, quantity) * product.GetUnitPriceMultiplier(); product.Price.PriceWithoutVAT = priceValue.GetValueOrDefault(); // NOTE accessing the Price property, will trigger the price provider to kick in product.Price.PriceWithVAT = priceValue.GetValueOrDefault(); //Update Product Custom Fields if (AddProductFieldsToRequest && product.ProductFieldValues.Count > 0) { foreach (var pfv in product.ProductFieldValues) { if (productInfo.ContainsKey(pfv.ProductField.SystemName)) { pfv.Value = productInfo[pfv.ProductField.SystemName]; } } } } } }
/// <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); } }
public override PriceRaw FindPrice(Product product, double quantity, string variantId, Currency currency, string unitId, User user) { if (!Global.IsIntegrationActive || !Settings.Instance.EnableLivePrices || !Settings.Instance.LiveProductInfoForAnonymousUsers && user == null || user != null && user.IsLivePricesDisabled || !Connector.IsWebServiceConnectionAvailable() || product == null || product.Id == "" || product.Number == "" || product.Number == null) { return(null); } try { Product requestProduct; if (product.VariantId == variantId || (string.IsNullOrEmpty(variantId) && string.IsNullOrEmpty(product.VariantId))) { requestProduct = product; } else { requestProduct = product.Clone(); requestProduct.VariantId = variantId; } //Logger.Instance.Log(ErrorLevel.DebugInfo, $"Id: {requestProduct.Id}, VariantId: {requestProduct.VariantId}, Number: {requestProduct.Number} \r\n { System.Environment.StackTrace}"); // If Product is not in the cache, then get it from Erp if (!ErpResponseCache.IsProductInCache(ProductCacheLevel, Helpers.ProductIdentifier(requestProduct))) { List <Product> products = new List <Product>(); products.Add(requestProduct); if (FetchProductInfos(products, User.GetCurrentExtranetUser())) { //Check if requested product was not received from response if (!ErpResponseCache.IsProductInCache(ProductCacheLevel, Helpers.ProductIdentifier(requestProduct))) { Logger.Instance.Log(ErrorLevel.Error, string.Format("Error receiving product info for product: {0}.", Helpers.ProductIdentifier(requestProduct))); return(null); } } else { //no price from ERP so read DW default price return(new DefaultPriceProvider().FindPrice(product, quantity, variantId, currency, unitId, user)); } } double?priceValue = 0.0; var productCache = ErpResponseCache.GetProductInfos(ProductCacheLevel); ProductInfo productInfo = productCache != null && productCache.TryGetValue(Helpers.ProductIdentifier(requestProduct), out productInfo) ? productInfo : null; if (productInfo != null) { priceValue = SelectPrice(productInfo, quantity); } var price = priceValue == null ? null : new PriceRaw { Price = priceValue.Value * product.GetUnitPriceMultiplier(), Currency = currency }; return(price); } catch (Exception e) { Logger.Instance.Log(ErrorLevel.Error, $"Unknown error during FindPrice(). Exception: {e.Message}"); return(null); } }
internal static bool FetchProductInfos(List <Product> products, User user) { // disable because if causes troubles if the product list fails (missing product) and then we enter to a product, as // it won't fetch its price... //if (LastResponseValid()) // // no need to read cache // return false; //SaveLastResponse(false); if (products == null || products.Count == 0) { return(false); } if (!Settings.Instance.EnableLivePrices) { Logger.Instance.Log(ErrorLevel.DebugInfo, "Live Prices are Disabled"); return(false); } if (!Connector.IsWebServiceConnectionAvailable()) { Logger.Instance.Log(ErrorLevel.DebugInfo, "Live Prices are unavailable"); return(false); } if (user == null) { user = User.GetCurrentExtranetUser(); } if (!Settings.Instance.LiveProductInfoForAnonymousUsers && user == null) { Logger.Instance.Log(ErrorLevel.DebugInfo, "No user is currently logged in. Anonymous user is not allowed."); return(false); } if (user != null && user.IsLivePricesDisabled) { Logger.Instance.Log(ErrorLevel.DebugInfo, string.Format("Calculated prices are not allowed to the user '{0}'.", user.UserName)); return(false); } // Check for existence of the given products in the Cache var productsForRequest = new List <Product>(); foreach (var product in products) { // check for invalid products (without product id) if (string.IsNullOrEmpty(product.Id)) { Logger.Instance.Log(ErrorLevel.DebugInfo, string.Format("Live Prices for invalid product: [{0}]", product.PropertiesToString())); } // Check for existence of the given products in the Cache else if (!ErpResponseCache.IsProductInCache(ProductCacheLevel, Helpers.ProductIdentifier(product))) { productsForRequest.Add(product); } } if (productsForRequest.Count == 0) { //Logger.Instance.Log(ErrorLevel.DebugInfo, "All products in cache!"); SaveLastResponse(); return(true); } var request = BuildProductRequest(productsForRequest); var response = Connector.GetProductsInfo(request); if (!string.IsNullOrEmpty(response?.InnerXml)) { // Parse the response Dictionary <string, ProductInfo> prices = ProcessResponse(response); if (prices == null || prices.Count == 0) { //Logger.Instance.Log(ErrorLevel.DebugInfo, "No result products!"); return(false); } // Cache prices foreach (string productKey in prices.Keys) { Dictionary <string, ProductInfo> piCache = ErpResponseCache.GetProductInfos(ProductCacheLevel); if (piCache.ContainsKey(productKey)) { piCache.Remove(productKey); } piCache.Add(productKey, prices[productKey]); } } else //error occurred { return(false); } SaveLastResponse(); return(true); }