Skip to content

Commit b691ba1

Browse files
committed
Synchronize quantity of required products in cart (wip)
1 parent d4c163d commit b691ba1

3 files changed

Lines changed: 50 additions & 18 deletions

File tree

src/Smartstore.Web/Models/ShoppingCart/Mappers/MiniShoppingCartMapper.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ public override async Task MapAsync(ShoppingCart from, MiniShoppingCartModel to,
135135
var checkoutAttributes = await _checkoutAttributeMaterializer.GetCheckoutAttributesAsync(from, store.Id);
136136
to.DisplayCheckoutButton = !checkoutAttributes.Any(x => x.IsRequired) && from.Items.Any(x => x.Active);
137137

138+
var requiredProducts = new Dictionary<int, OrganizedShoppingCartItem>();
139+
foreach (var item in from.Items.Where(x => x.Item.Product.RequireOtherProducts))
140+
{
141+
var requiredProductIds = item.Item.Product.ParseRequiredProductIds();
142+
requiredProductIds.Each(id => requiredProducts[id] = item);
143+
}
144+
138145
// Products sort descending (recently added products).
139146
foreach (var cartItem in from.Items)
140147
{
@@ -149,7 +156,7 @@ public override async Task MapAsync(ShoppingCart from, MiniShoppingCartModel to,
149156
customer,
150157
batchContext);
151158

152-
var cartItemModel = new MiniShoppingCartModel.ShoppingCartItemModel
159+
var itemModel = new MiniShoppingCartModel.ShoppingCartItemModel
153160
{
154161
Id = item.Id,
155162
Active = cartItem.Active,
@@ -165,12 +172,12 @@ public override async Task MapAsync(ShoppingCart from, MiniShoppingCartModel to,
165172

166173
if (_shoppingCartSettings.ShowEssentialAttributesInMiniShoppingCart)
167174
{
168-
cartItemModel.EssentialSpecAttributesInfo = _productAttributeFormatter.FormatSpecificationAttributes(
175+
itemModel.EssentialSpecAttributesInfo = _productAttributeFormatter.FormatSpecificationAttributes(
169176
await batchContext.EssentialAttributes.GetOrLoadAsync(product.Id),
170177
DefaultAttributeFormatOptions);
171178
}
172179

173-
await cartItem.MapQuantityInputAsync(cartItemModel);
180+
await cartItem.MapQuantityInputAsync(itemModel);
174181

175182
if (cartItem.ChildItems != null && _shoppingCartSettings.ShowProductBundleImagesOnShoppingCart)
176183
{
@@ -208,36 +215,45 @@ await batchContext.EssentialAttributes.GetOrLoadAsync(product.Id),
208215
};
209216
}
210217

211-
cartItemModel.BundleItems.Add(bundleItemModel);
218+
itemModel.BundleItems.Add(bundleItemModel);
212219
}
213220
}
214221

222+
// Required products.
223+
if (requiredProducts.TryGetValue(product.Id, out var parent))
224+
{
225+
var expectedQuantity = parent.Item.Quantity * product.QuantityPerParentUnit;
226+
227+
itemModel.IsRequired = parent.Item.Product.AutomaticallyAddRequiredProducts;
228+
itemModel.DisableQuantityControl = product.QuantityPerParentUnit > 0 && item.Quantity == expectedQuantity;
229+
}
230+
215231
// Unit prices.
216232
if (lineItems.TryGetValue(item.Id, out var lineItem))
217233
{
218234
if (lineItem.UnitPrice.PricingType == PricingType.CallForPrice)
219235
{
220-
cartItemModel.UnitPrice = lineItem.UnitPrice.FinalPrice;
236+
itemModel.UnitPrice = lineItem.UnitPrice.FinalPrice;
221237
}
222238
else
223239
{
224240
var unitPrice = _currencyService.ConvertFromPrimaryCurrency(lineItem.UnitPrice.FinalPrice.Amount, currency);
225-
cartItemModel.UnitPrice = unitPrice.WithPostFormat(taxFormat);
241+
itemModel.UnitPrice = unitPrice.WithPostFormat(taxFormat);
226242

227243
if (unitPrice != 0 && to.ShowBasePrice)
228244
{
229-
cartItemModel.BasePriceInfo = _priceCalculationService.GetBasePriceInfo(item.Product, unitPrice, currency);
245+
itemModel.BasePriceInfo = _priceCalculationService.GetBasePriceInfo(item.Product, unitPrice, currency);
230246
}
231247
}
232248
}
233249

234250
// Image.
235251
if (_shoppingCartSettings.ShowProductImagesInMiniShoppingCart)
236252
{
237-
await cartItem.MapAsync(cartItemModel.Image, _mediaSettings.MiniCartThumbPictureSize, cartItemModel.ProductName);
253+
await cartItem.MapAsync(itemModel.Image, _mediaSettings.MiniCartThumbPictureSize, itemModel.ProductName);
238254
}
239255

240-
to.Items.Add(cartItemModel);
256+
to.Items.Add(itemModel);
241257
}
242258
}
243259
}

src/Smartstore.Web/Models/ShoppingCart/MiniShoppingCartModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ public partial class ShoppingCartItemModel : EntityModelBase, IQuantityInput
5151
public string AttributeInfo { get; set; }
5252
public string EssentialSpecAttributesInfo { get; set; }
5353

54+
/// <summary>
55+
/// Gets or sets a value indicating whether the item is an auto-added, required product.
56+
/// It can only be removed from the cart when the parent product is removed, if <c>true</c>.
57+
/// </summary>
58+
public bool IsRequired { get; set; }
59+
public bool DisableQuantityControl { get; set; }
60+
5461
public ImageModel Image { get; set; } = new();
5562

5663
public List<ShoppingCartItemBundleItem> BundleItems { get; set; } = [];

src/Smartstore.Web/Views/ShoppingCart/Partials/OffCanvasShoppingCart.cshtml

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,25 @@
100100

101101
<div class="row sm-gutters flex-wrap align-items-center mt-2">
102102
<div class="col col-alpha">
103+
@{
104+
var qtyAttributes = new Dictionary<string, object>
105+
{
106+
["data-update-url"] = Url.Action("UpdateCartItem", "ShoppingCart"),
107+
["data-type"] = "cart",
108+
["data-sci-id"] = item.Id,
109+
["id"] = $"o-cart-item-quantity-{item.Id}",
110+
["aria-label"] = $"{T("ShoppingCart.Quantity")} {item.ProductName}"
111+
};
112+
if (item.DisableQuantityControl)
113+
{
114+
qtyAttributes["disabled"] = "disabled";
115+
qtyAttributes["title"] = T("ShoppingCart.SyncedRequiredProductQuantityInfo").Value;
116+
}
117+
}
103118
@Html.EditorFor(x => item, "QtyInput", new
104119
{
105120
size = ControlSize.Small,
106-
htmlAttributes = new
107-
{
108-
data_update_url = Url.Action("UpdateCartItem", "ShoppingCart"),
109-
data_type = "cart",
110-
data_sci_id = item.Id,
111-
id = $"o-cart-item-quantity-{item.Id}",
112-
aria_label = $"{T("ShoppingCart.Quantity")} {item.ProductName}"
113-
}
121+
htmlAttributes = qtyAttributes
114122
})
115123
</div>
116124
<div class="col">
@@ -148,7 +156,8 @@
148156
data-href='@Url.Action("DeleteCartItem", "ShoppingCart", new { cartItemId = item.Id })'
149157
data-name="@item.ProductName"
150158
data-type="cart"
151-
data-action="remove">
159+
data-action="remove"
160+
attr-disabled='(item.IsRequired, "disabled")'>
152161
<i class="fal fa-trash-can" aria-hidden="true"></i>
153162
</button>
154163
</div>

0 commit comments

Comments
 (0)