using System.Xml; using Nop.Core.Domain.Orders; using Nop.Core.Infrastructure; using Nop.Services.Attributes; namespace Nop.Services.Orders; /// /// Checkout attribute parser extensions /// public static partial class CheckoutAttributeParserExtensions { /// /// Removes checkout attributes which cannot be applied to the current cart and returns an update attributes in XML format /// /// Checkout attribute parser /// Attributes in XML format /// Shopping cart items /// /// A task that represents the asynchronous operation /// The task result contains the updated attributes in XML format /// public static async Task EnsureOnlyActiveAttributesAsync(this IAttributeParser parser, string attributesXml, IList cart) { if (string.IsNullOrEmpty(attributesXml)) return attributesXml; var result = attributesXml; //removing "shippable" checkout attributes if there's no any shippable products in the cart //do not inject IShoppingCartService via constructor because it'll cause circular references var shoppingCartService = EngineContext.Current.Resolve(); if (await shoppingCartService.ShoppingCartRequiresShippingAsync(cart)) return result; //find attribute IDs to remove var checkoutAttributeIdsToRemove = new List(); var attributes = await parser.ParseAttributesAsync(attributesXml); foreach (var ca in attributes) if (ca.ShippableProductRequired) checkoutAttributeIdsToRemove.Add(ca.Id); //remove them from XML try { var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(attributesXml); var nodesToRemove = new List(); var nodes = xmlDoc.SelectNodes(@$"//Attributes/{nameof(CheckoutAttribute)}"); if (nodes != null) { foreach (XmlNode node in nodes) { if (node.Attributes?["ID"] == null) continue; var str1 = node.Attributes["ID"].InnerText.Trim(); if (!int.TryParse(str1, out var id)) continue; if (checkoutAttributeIdsToRemove.Contains(id)) nodesToRemove.Add(node); } foreach (var node in nodesToRemove) node.ParentNode?.RemoveChild(node); } result = xmlDoc.OuterXml; } catch { //ignore } return result; } }