public virtual async Task <AdjustInventoryResult> AdjustInventoryAsync(Product product, ProductVariantAttributeSelection selection, bool decrease, int quantity) { Guard.NotNull(product, nameof(product)); Guard.NotNull(selection, nameof(selection)); var result = new AdjustInventoryResult(); switch (product.ManageInventoryMethod) { case ManageInventoryMethod.ManageStock: { result.StockQuantityOld = product.StockQuantity; result.StockQuantityNew = decrease ? product.StockQuantity - quantity : product.StockQuantity + quantity; var newPublished = product.Published; var newDisableBuyButton = product.DisableBuyButton; var newDisableWishlistButton = product.DisableWishlistButton; // Check if the minimum quantity is reached. switch (product.LowStockActivity) { case LowStockActivity.DisableBuyButton: newDisableBuyButton = product.MinStockQuantity >= result.StockQuantityNew; newDisableWishlistButton = product.MinStockQuantity >= result.StockQuantityNew; break; case LowStockActivity.Unpublish: newPublished = product.MinStockQuantity <= result.StockQuantityNew; break; } product.StockQuantity = result.StockQuantityNew; product.DisableBuyButton = newDisableBuyButton; product.DisableWishlistButton = newDisableWishlistButton; product.Published = newPublished; // Commit required because of store owner notification. await _db.SaveChangesAsync(); if (decrease && product.NotifyAdminForQuantityBelow > result.StockQuantityNew) { await _messageFactory.SendQuantityBelowStoreOwnerNotificationAsync(product, _localizationSettings.DefaultAdminLanguageId); } } break; case ManageInventoryMethod.ManageStockByAttributes: { var combination = await _productAttributeMaterializer.FindAttributeCombinationAsync(product.Id, selection); if (combination != null) { result.StockQuantityOld = combination.StockQuantity; result.StockQuantityNew = decrease ? combination.StockQuantity - quantity : combination.StockQuantity + quantity; combination.StockQuantity = result.StockQuantityNew; } } break; case ManageInventoryMethod.DontManageStock: default: // Do nothing. break; } var attributeValues = await _productAttributeMaterializer.MaterializeProductVariantAttributeValuesAsync(selection); var productLinkageValues = attributeValues .Where(x => x.ValueType == ProductVariantAttributeValueType.ProductLinkage) .ToList(); foreach (var chunk in productLinkageValues.Slice(100)) { var linkedProductIds = chunk.Select(x => x.LinkedProductId).Distinct().ToArray(); var linkedProducts = await _db.Products.GetManyAsync(linkedProductIds, true); var linkedProductsDic = linkedProducts.ToDictionarySafe(x => x.Id); foreach (var value in chunk) { if (linkedProductsDic.TryGetValue(value.LinkedProductId, out var linkedProduct)) { await AdjustInventoryAsync(linkedProduct, null, decrease, quantity *value.Quantity); } } } await _db.SaveChangesAsync(); return(result); }
public virtual async Task <AdjustInventoryResult> AdjustInventoryAsync(Product product, ProductVariantAttributeSelection selection, bool decrease, int quantity) { Guard.NotNull(product, nameof(product)); Guard.NotNull(selection, nameof(selection)); var result = new AdjustInventoryResult(); switch (product.ManageInventoryMethod) { case ManageInventoryMethod.ManageStock: { result.StockQuantityOld = product.StockQuantity; result.StockQuantityNew = decrease ? product.StockQuantity - quantity : product.StockQuantity + quantity; var newPublished = product.Published; var newDisableBuyButton = product.DisableBuyButton; var newDisableWishlistButton = product.DisableWishlistButton; // Check if the minimum quantity is reached. switch (product.LowStockActivity) { case LowStockActivity.DisableBuyButton: newDisableBuyButton = product.MinStockQuantity >= result.StockQuantityNew; newDisableWishlistButton = product.MinStockQuantity >= result.StockQuantityNew; break; case LowStockActivity.Unpublish: newPublished = product.MinStockQuantity <= result.StockQuantityNew; break; } product.StockQuantity = result.StockQuantityNew; product.DisableBuyButton = newDisableBuyButton; product.DisableWishlistButton = newDisableWishlistButton; product.Published = newPublished; // TODO: (mg) (core) ProductService.AdjustInventoryAsync doesn't send SendQuantityBelowStoreOwnerNotification anymore. Must be sent by caller after (!) database commit. // TODO: (mg) (core) The caller should definitely NOT be responsible for figuring out, when and how to publish messages. That would be extremely bad API design. //if (decrease && product.NotifyAdminForQuantityBelow > result.StockQuantityNew) //{ // _services.MessageFactory.SendQuantityBelowStoreOwnerNotification(product, _localizationSettings.DefaultAdminLanguageId); //} } break; case ManageInventoryMethod.ManageStockByAttributes: { var combination = await _productAttributeMaterializer.FindAttributeCombinationAsync(product.Id, selection); if (combination != null) { result.StockQuantityOld = combination.StockQuantity; result.StockQuantityNew = decrease ? combination.StockQuantity - quantity : combination.StockQuantity + quantity; combination.StockQuantity = result.StockQuantityNew; } } break; case ManageInventoryMethod.DontManageStock: default: // Do nothing. break; } var attributeValues = await _productAttributeMaterializer.MaterializeProductVariantAttributeValuesAsync(selection); var productLinkageValues = attributeValues .Where(x => x.ValueType == ProductVariantAttributeValueType.ProductLinkage) .ToList(); foreach (var chunk in productLinkageValues.Slice(100)) { var linkedProductIds = chunk.Select(x => x.LinkedProductId).Distinct().ToArray(); var linkedProducts = await _db.Products.GetManyAsync(linkedProductIds, true); var linkedProductsDic = linkedProducts.ToDictionarySafe(x => x.Id); foreach (var value in chunk) { if (linkedProductsDic.TryGetValue(value.LinkedProductId, out var linkedProduct)) { await AdjustInventoryAsync(linkedProduct, null, decrease, quantity *value.Quantity); } } } return(result); }