Exemplo n.º 1
0
        private async Task ManageStockByAttributesInventory(Product product, Shipment shipment, ShipmentItem shipmentItem)
        {
            var combination = _productAttributeParser.FindProductAttributeCombination(product, shipmentItem.Attributes);

            if (combination == null)
            {
                return;
            }

            if (!product.UseMultipleWarehouses)
            {
                combination.ReservedQuantity -= shipmentItem.Quantity;
                combination.StockQuantity    -= shipmentItem.Quantity;

                var builder = Builders <Product> .Filter;
                var filter  = builder.Eq(x => x.Id, product.Id);
                filter &= builder.ElemMatch(x => x.ProductAttributeCombinations, y => y.Id == combination.Id);
                var update = Builders <Product> .Update
                             .Set("ProductAttributeCombinations.$.StockQuantity", combination.StockQuantity)
                             .Set("ProductAttributeCombinations.$.ReservedQuantity", combination.ReservedQuantity)
                             .Set("ProductAttributeCombinations.$.WarehouseInventory", combination.WarehouseInventory)
                             .CurrentDate("UpdatedOnUtc");

                await _productRepository.Collection.UpdateManyAsync(filter, update);
            }
            else
            {
                var pwi = combination.WarehouseInventory.FirstOrDefault(pi => pi.WarehouseId == shipmentItem.WarehouseId);
                if (pwi == null)
                {
                    return;
                }

                pwi.ReservedQuantity -= shipmentItem.Quantity;
                pwi.StockQuantity    -= shipmentItem.Quantity;

                combination.StockQuantity    = combination.WarehouseInventory.Sum(x => x.StockQuantity);
                combination.ReservedQuantity = combination.WarehouseInventory.Sum(x => x.ReservedQuantity);

                var builder = Builders <Product> .Filter;
                var filter  = builder.Eq(x => x.Id, product.Id);
                filter &= builder.ElemMatch(x => x.ProductAttributeCombinations, y => y.Id == combination.Id);
                var update = Builders <Product> .Update
                             .Set("ProductAttributeCombinations.$.StockQuantity", combination.StockQuantity)
                             .Set("ProductAttributeCombinations.$.ReservedQuantity", combination.ReservedQuantity)
                             .Set("ProductAttributeCombinations.$.WarehouseInventory", combination.WarehouseInventory)
                             .CurrentDate("UpdatedOnUtc");

                await _productRepository.Collection.UpdateManyAsync(filter, update);
            }
            product.StockQuantity    = product.ProductAttributeCombinations.Sum(x => x.StockQuantity);
            product.ReservedQuantity = product.ProductAttributeCombinations.Sum(x => x.ReservedQuantity);
            await UpdateStockProduct(product);
        }
        private async Task ManageStockByAttributesInventory(Product product, Shipment shipment, ShipmentItem shipmentItem)
        {
            var combination = _productAttributeParser.FindProductAttributeCombination(product, shipmentItem.Attributes);

            if (combination == null)
            {
                return;
            }

            if (!product.UseMultipleWarehouses)
            {
                combination.ReservedQuantity -= shipmentItem.Quantity;
                combination.StockQuantity    -= shipmentItem.Quantity;
                if (combination.ReservedQuantity < 0)
                {
                    combination.ReservedQuantity = 0;
                }

                await _productRepository.UpdateToSet(product.Id, x => x.ProductAttributeCombinations, z => z.Id, combination.Id, combination);

                await _productRepository.UpdateField(product.Id, x => x.UpdatedOnUtc, DateTime.UtcNow);
            }
            else
            {
                var pwi = combination.WarehouseInventory.FirstOrDefault(pi => pi.WarehouseId == shipmentItem.WarehouseId);
                if (pwi == null)
                {
                    return;
                }

                pwi.ReservedQuantity -= shipmentItem.Quantity;
                pwi.StockQuantity    -= shipmentItem.Quantity;
                if (pwi.ReservedQuantity < 0)
                {
                    pwi.ReservedQuantity = 0;
                }

                combination.StockQuantity    = combination.WarehouseInventory.Sum(x => x.StockQuantity);
                combination.ReservedQuantity = combination.WarehouseInventory.Sum(x => x.ReservedQuantity);

                await _productRepository.UpdateToSet(product.Id, x => x.ProductAttributeCombinations, z => z.Id, combination.Id, combination);

                await _productRepository.UpdateField(product.Id, x => x.UpdatedOnUtc, DateTime.UtcNow);
            }
            product.StockQuantity    = product.ProductAttributeCombinations.Sum(x => x.StockQuantity);
            product.ReservedQuantity = product.ProductAttributeCombinations.Sum(x => x.ReservedQuantity);
            await UpdateStockProduct(product);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets product code
        /// </summary>
        private static void GetProductCode(this Product product, string attributesXml, IProductAttributeParser productAttributeParser,
                                           out string productCode)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            productCode = null;

            if (!String.IsNullOrEmpty(attributesXml) &&
                product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                //manage stock by attribute combinations
                if (productAttributeParser == null)
                {
                    throw new ArgumentNullException("productAttributeParser");
                }

                //let's find appropriate record
                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    productCode = combination.ProductCode;
                }
            }

            if (String.IsNullOrEmpty(productCode))
            {
                productCode = product.ProductCode;
            }
        }
Exemplo n.º 4
0
        private static string GeStockMessage(Product product, string attributesXml, ILocalizationService localizationService, IProductAttributeParser productAttributeParser, IDateRangeService dateRangeService, IProductAttributeService productAttributeService)
        {
            if (!product.DisplayStockAvailability)
            {
                return(string.Empty);
            }

            string stockMessage;

            var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);

            if (combination != null)
            {
                //combination exists
                var stockQuantity = combination.StockQuantity;
                if (stockQuantity > 0)
                {
                    stockMessage = product.DisplayStockQuantity
                        ?
                                   //display "in stock" with stock quantity
                                   string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"),
                                                 stockQuantity)
                        :
                                   //display "in stock" without stock quantity
                                   localizationService.GetResource("Products.Availability.InStock");
                }
                else if (combination.AllowOutOfStockOrders)
                {
                    stockMessage = localizationService.GetResource("Products.Availability.InStock");
                }
                else
                {
                    var productAvailabilityRange =
                        dateRangeService.GetProductAvailabilityRangeById(product.ProductAvailabilityRangeId);
                    stockMessage = productAvailabilityRange == null
                        ? localizationService.GetResource("Products.Availability.OutOfStock")
                        : string.Format(localizationService.GetResource("Products.Availability.AvailabilityRange"),
                                        productAvailabilityRange.GetLocalized(range => range.Name));
                }
            }
            else
            {
                //no combination configured
                if (product.AllowAddingOnlyExistingAttributeCombinations)
                {
                    var productAvailabilityRange =
                        dateRangeService.GetProductAvailabilityRangeById(product.ProductAvailabilityRangeId);
                    stockMessage = productAvailabilityRange == null
                        ? localizationService.GetResource("Products.Availability.OutOfStock")
                        : string.Format(localizationService.GetResource("Products.Availability.AvailabilityRange"),
                                        productAvailabilityRange.GetLocalized(range => range.Name));
                }
                else
                {
                    stockMessage = !productAttributeService.GetProductAttributeMappingsByProductId(product.Id)
                                   .Any(pam => pam.IsRequired) ? localizationService.GetResource("Products.Availability.InStock") : localizationService.GetResource("Products.Availability.SelectRequiredAttributes");
                }
            }
            return(stockMessage);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Get product picture (for shopping cart and order details pages)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Atributes (in XML format)</param>
        /// <param name="pictureService">Picture service</param>
        /// <param name="productAttributeParser">Product attribute service</param>
        /// <returns>Picture</returns>
        public static Picture GetProductPicture(this Product product, string attributesXml,
                                                IPictureService pictureService,
                                                IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            if (pictureService == null)
            {
                throw new ArgumentNullException(nameof(pictureService));
            }

            if (productAttributeParser == null)
            {
                throw new ArgumentNullException(nameof(productAttributeParser));
            }

            //first, try to get product attribute combination picture
            var combination        = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
            var combinationPicture = pictureService.GetPictureById(combination?.PictureId ?? 0);

            if (combinationPicture != null)
            {
                return(combinationPicture);
            }

            //then, let's see whether we have attribute values with pictures
            var attributePicture = productAttributeParser.ParseProductAttributeValues(attributesXml)
                                   .Select(attributeValue => pictureService.GetPictureById(attributeValue?.PictureId ?? 0))
                                   .FirstOrDefault(picture => picture != null);

            if (attributePicture != null)
            {
                return(attributePicture);
            }

            //now let's load the default product picture
            var productPicture = pictureService.GetPicturesByProductId(product.Id, 1).FirstOrDefault();

            if (productPicture != null)
            {
                return(productPicture);
            }

            //finally, let's check whether this product has some parent "grouped" product
            if (!product.VisibleIndividually && product.ParentGroupedProductId > 0)
            {
                var parentGroupedProductPicture = pictureService.GetPicturesByProductId(product.ParentGroupedProductId, 1).FirstOrDefault();
                if (parentGroupedProductPicture != null)
                {
                    return(parentGroupedProductPicture);
                }
            }

            return(null);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Gets SKU, Manufacturer part number and GTIN
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Attributes in XML format</param>
        /// <param name="productAttributeParser">Product attribute service (used when attributes are specified)</param>
        /// <param name="sku">SKU</param>
        /// <param name="manufacturerPartNumber">Manufacturer part number</param>
        // nopCommerceTest1-START
        /// <param name="author">Author</param>
        // nopCommerceTest1-END
        /// <param name="gtin">GTIN</param>
        private static void GetSkuMpnGtin(this Product product, string attributesXml, IProductAttributeParser productAttributeParser,
                                          out string sku, out string manufacturerPartNumber, out string author, out string gtin)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            sku = null;
            manufacturerPartNumber = null;
            // nopCommerceTest1-START
            author = null;
            // nopCommerceTest1-END
            gtin = null;

            if (!string.IsNullOrEmpty(attributesXml) &&
                product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                //manage stock by attribute combinations
                if (productAttributeParser == null)
                {
                    throw new ArgumentNullException(nameof(productAttributeParser));
                }

                //let's find appropriate record
                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    sku = combination.Sku;
                    manufacturerPartNumber = combination.ManufacturerPartNumber;
                    // nopCommerceTest1-START
                    author = combination.Author;
                    // nopCommerceTest1-END
                    gtin = combination.Gtin;
                }
            }

            if (string.IsNullOrEmpty(sku))
            {
                sku = product.Sku;
            }
            if (string.IsNullOrEmpty(manufacturerPartNumber))
            {
                manufacturerPartNumber = product.ManufacturerPartNumber;
            }
            // nopCommerceTest1-START
            if (String.IsNullOrEmpty(author))
            {
                author = product.Author;
            }
            // nopCommerceTest1-END
            if (string.IsNullOrEmpty(gtin))
            {
                gtin = product.Gtin;
            }
        }
        /// <summary>
        /// Gets SKU, Manufacturer part number and GTIN
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributes">Attributes</param>
        /// <param name="productAttributeParser">Product attribute service (used when attributes are specified)</param>
        /// <param name="sku">SKU</param>
        /// <param name="manufacturerPartNumber">Manufacturer part number</param>
        /// <param name="gtin">GTIN</param>
        private static void GetSkuMpnGtin(this Product product, IList <CustomAttribute> attributes, IProductAttributeParser productAttributeParser,
                                          out string sku, out string manufacturerPartNumber, out string gtin)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            sku = null;
            manufacturerPartNumber = null;
            gtin = null;

            if (attributes != null &&
                product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                //manage stock by attribute combinations
                if (productAttributeParser == null)
                {
                    throw new ArgumentNullException("productAttributeParser");
                }

                //let's find appropriate record
                var combination = productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (combination != null)
                {
                    sku = combination.Sku;
                    manufacturerPartNumber = combination.ManufacturerPartNumber;
                    gtin = combination.Gtin;
                }
            }

            if (string.IsNullOrEmpty(sku))
            {
                sku = product.Sku;
            }
            if (string.IsNullOrEmpty(manufacturerPartNumber))
            {
                manufacturerPartNumber = product.ManufacturerPartNumber;
            }
            if (string.IsNullOrEmpty(gtin))
            {
                gtin = product.Gtin;
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Gets SKU, Collection part number and GTIN
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributes">Attributes</param>
        /// <param name="productAttributeParser">Product attribute service</param>
        /// <param name="sku">SKU</param>
        /// <param name="Mpn">MPN</param>
        /// <param name="gtin">GTIN</param>
        private static void GetSkuMpnGtin(this Product product, IList <CustomAttribute> attributes, IProductAttributeParser productAttributeParser,
                                          out string sku, out string Mpn, out string gtin)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            sku  = null;
            Mpn  = null;
            gtin = null;

            if (attributes != null &&
                product.ManageInventoryMethodId == ManageInventoryMethod.ManageStockByAttributes)
            {
                if (productAttributeParser == null)
                {
                    throw new ArgumentNullException(nameof(productAttributeParser));
                }

                var combination = productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (combination != null)
                {
                    sku  = combination.Sku;
                    Mpn  = combination.Mpn;
                    gtin = combination.Gtin;
                }
            }

            if (string.IsNullOrEmpty(sku))
            {
                sku = product.Sku;
            }
            if (string.IsNullOrEmpty(Mpn))
            {
                Mpn = product.Mpn;
            }
            if (string.IsNullOrEmpty(gtin))
            {
                gtin = product.Gtin;
            }
        }
        /// <summary>
        /// Create items from shopping cart
        /// </summary>
        /// <param name="shoppingCart">Shopping cart</param>
        /// <returns>Collection of PayPal items</returns>
        protected IEnumerable <Item> CreateItems(IEnumerable <ShoppingCartItem> shoppingCart)
        {
            return(shoppingCart.Select(shoppingCartItem =>
            {
                if (shoppingCartItem.Product == null)
                {
                    return null;
                }

                var item = new Item
                {
                    //name
                    name = shoppingCartItem.Product.Name
                };

                //SKU
                if (!string.IsNullOrEmpty(shoppingCartItem.AttributesXml))
                {
                    var combination = _productAttributeParser.FindProductAttributeCombination(shoppingCartItem.Product, shoppingCartItem.AttributesXml);
                    item.sku = combination != null && !string.IsNullOrEmpty(combination.Sku) ? combination.Sku : shoppingCartItem.Product.Sku;
                }
                else
                {
                    item.sku = shoppingCartItem.Product.Sku;
                }

                //item price
                var unitPrice = _priceCalculationService.GetUnitPrice(shoppingCartItem);
                var price = _taxService.GetProductPrice(shoppingCartItem.Product, unitPrice, false, shoppingCartItem.Customer, out decimal _);
                item.price = price.ToString("N", new CultureInfo("en-US"));

                //quantity
                item.quantity = shoppingCartItem.Quantity.ToString();

                return item;
            }));
        }
        /// <summary>
        /// Gets the shopping cart unit price (one item)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="attributesXml">Product atrributes (XML format)</param>
        /// <param name="customerEnteredPrice">Customer entered price (if specified)</param>
        /// <param name="rentalStartDate">Rental start date (null for not rental products)</param>
        /// <param name="rentalEndDate">Rental end date (null for not rental products)</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Shopping cart unit price (one item)</returns>
        public virtual async Task <(decimal unitprice, decimal discountAmount, List <AppliedDiscount> appliedDiscounts)> GetUnitPrice(Product product,
                                                                                                                                      Customer customer,
                                                                                                                                      ShoppingCartType shoppingCartType,
                                                                                                                                      int quantity,
                                                                                                                                      string attributesXml,
                                                                                                                                      decimal customerEnteredPrice,
                                                                                                                                      DateTime?rentalStartDate, DateTime?rentalEndDate,
                                                                                                                                      bool includeDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (customer == null)
            {
                throw new ArgumentNullException("customer");
            }

            var discountAmount   = decimal.Zero;
            var appliedDiscounts = new List <AppliedDiscount>();

            decimal?finalPrice = null;

            if (shoppingCartType == ShoppingCartType.Auctions && product.ProductType == ProductType.Auction)
            {
                finalPrice = customerEnteredPrice;
            }

            if (!finalPrice.HasValue)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    if (combination.OverriddenPrice.HasValue)
                    {
                        finalPrice = combination.OverriddenPrice.Value;
                    }
                    if (combination.TierPrices.Any())
                    {
                        var storeId          = _storeContext.CurrentStore.Id;
                        var actualTierPrices = combination.TierPrices.Where(x => string.IsNullOrEmpty(x.StoreId) || x.StoreId == storeId)
                                               .Where(x => string.IsNullOrEmpty(x.CustomerRoleId) ||
                                                      customer.CustomerRoles.Where(role => role.Active).Select(role => role.Id).Contains(x.CustomerRoleId)).ToList();
                        var tierPrice = actualTierPrices.LastOrDefault(price => quantity >= price.Quantity);
                        if (tierPrice != null)
                        {
                            finalPrice = tierPrice.Price;
                        }
                    }
                }
            }
            if (!finalPrice.HasValue)
            {
                //summarize price of all attributes
                decimal attributesTotalPrice = decimal.Zero;
                var     attributeValues      = _productAttributeParser.ParseProductAttributeValues(product, attributesXml);
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        attributesTotalPrice += await GetProductAttributeValuePriceAdjustment(attributeValue);
                    }
                }

                //get price of a product (with previously calculated price of all attributes)
                if (product.CustomerEntersPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty;
                    if (_shoppingCartSettings.GroupTierPricesForDistinctShoppingCartItems)
                    {
                        //the same products with distinct product attributes could be stored as distinct "ShoppingCartItem" records
                        //so let's find how many of the current products are in the cart
                        qty = customer.ShoppingCartItems
                              .Where(x => x.ProductId == product.Id)
                              .Where(x => x.ShoppingCartType == shoppingCartType)
                              .Sum(x => x.Quantity);
                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }
                    var getfinalPrice = await GetFinalPrice(product,
                                                            customer,
                                                            attributesTotalPrice,
                                                            includeDiscounts,
                                                            qty,
                                                            product.ProductType == ProductType.Reservation?rentalStartDate : null,
                                                            product.ProductType == ProductType.Reservation?rentalEndDate : null);

                    finalPrice       = getfinalPrice.finalPrice;
                    discountAmount   = getfinalPrice.discountAmount;
                    appliedDiscounts = getfinalPrice.appliedDiscounts;
                }
            }

            if (!finalPrice.HasValue)
            {
                finalPrice = 0;
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                var primaryCurrency = await _currencyService.GetPrimaryExchangeRateCurrency();

                finalPrice = RoundingHelper.RoundPrice(finalPrice.Value, primaryCurrency);
            }
            return(finalPrice.Value, discountAmount, appliedDiscounts);
        }
Exemplo n.º 11
0
        public List <Dictionary <string, object> > GenerateProductStockFeed()
        {
            var productFeed = new List <Dictionary <string, object> >();

            var products = _productService.SearchProducts(visibleIndividuallyOnly: true);

            foreach (var product in products)
            {
                var productsToProcess = new List <Product>();
                switch (product.ProductType)
                {
                case ProductType.SimpleProduct:
                {
                    //simple product doesn't have child products
                    productsToProcess.Add(product);
                }
                break;

                case ProductType.GroupedProduct:
                {
                    //grouped products could have several child products
                    var associatedProducts = _productService.GetAssociatedProducts(product.Id);
                    productsToProcess.AddRange(associatedProducts);
                }
                break;

                default:
                    continue;
                }

                foreach (var productToProcess in productsToProcess)
                {
                    var productInfo = new Dictionary <string, object>
                    {
                        { "id", productToProcess.Id.ToString() },
                        {
                            "product_availability",
                            product.AvailableEndDateTimeUtc != null
                                ? product.AvailableEndDateTimeUtc.Value.ToString("yy-MM-dd hh:mm:ss")
                                : null
                        }
                    };

                    decimal price;
                    decimal priceWithDiscount;
                    GetProductPrice(product, out price, out priceWithDiscount);

                    productInfo.Add("price", price.ToString(new CultureInfo("en-US", false).NumberFormat));
                    productInfo.Add("promo", priceWithDiscount.ToString(new CultureInfo("en-US", false).NumberFormat));
                    productInfo.Add("promo_price_end_date", null);

                    var inventory  = new Dictionary <string, object>();
                    var attributes = new Dictionary <string, object>();

                    var allAttributesXml = _productAttributeParser.GenerateAllCombinations(product, true);
                    foreach (var attributesXml in allAttributesXml)
                    {
                        var warnings = new List <string>();
                        warnings.AddRange(_shoppingCartService.GetShoppingCartItemAttributeWarnings(_workContext.CurrentCustomer,
                                                                                                    ShoppingCartType.ShoppingCart, product, 1, attributesXml, true));
                        if (warnings.Count != 0)
                        {
                            continue;
                        }

                        var inStock             = true;
                        var existingCombination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                        if (existingCombination != null)
                        {
                            inStock = existingCombination.StockQuantity > 0;
                        }

                        var varCode = GetCombinationCode(attributesXml);
                        if (!attributes.ContainsKey(varCode))
                        {
                            attributes.Add(varCode, inStock);
                        }
                    }

                    var variation = new Dictionary <string, object>
                    {
                        { "variation", attributes }
                    };

                    if (attributes.Count > 0)
                    {
                        inventory.Add("variations", true);
                        inventory.Add("stock", variation);
                    }
                    else
                    {
                        inventory.Add("variations", false);
                        inventory.Add("stock", product.StockQuantity > 0);
                    }

                    productInfo.Add("inventory", inventory);
                    productInfo.Add("user_groups", false);

                    productFeed.Add(productInfo);
                }
            }

            return(productFeed);
        }
Exemplo n.º 12
0
        public virtual async Task <ShipmentModel> PrepareShipmentModel(Order order)
        {
            var model = new ShipmentModel
            {
                OrderId     = order.Id,
                OrderNumber = order.OrderNumber
            };

            //measures
            var baseWeight = await _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);

            var baseWeightIn  = baseWeight != null ? baseWeight.Name : "";
            var baseDimension = await _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);

            var baseDimensionIn = baseDimension != null ? baseDimension.Name : "";

            var orderItems = order.OrderItems;

            //a vendor should have access only to his products
            if (_workContext.CurrentVendor != null && !await _groupService.IsStaff(_workContext.CurrentCustomer))
            {
                orderItems = orderItems.Where(_workContext.HasAccessToOrderItem).ToList();
            }

            foreach (var orderItem in orderItems)
            {
                var product = await _productService.GetProductByIdIncludeArch(orderItem.ProductId);

                //we can ship only shippable products
                if (!product.IsShipEnabled)
                {
                    continue;
                }

                //quantities
                var qtyInThisShipment = 0;
                var maxQtyToAdd       = orderItem.OpenQty;
                var qtyOrdered        = orderItem.Quantity;
                var qtyInAllShipments = orderItem.ShipQty;

                //ensure that this product can be added to a shipment
                if (maxQtyToAdd <= 0)
                {
                    continue;
                }

                var shipmentItemModel = new ShipmentModel.ShipmentItemModel
                {
                    OrderItemId            = orderItem.Id,
                    ProductId              = orderItem.ProductId,
                    ProductName            = product.Name,
                    WarehouseId            = orderItem.WarehouseId,
                    Sku                    = product.FormatSku(orderItem.Attributes, _productAttributeParser),
                    AttributeInfo          = orderItem.AttributeDescription,
                    ShipSeparately         = product.ShipSeparately,
                    ItemWeight             = orderItem.ItemWeight.HasValue ? string.Format("{0:F2} [{1}]", orderItem.ItemWeight, baseWeightIn) : "",
                    ItemDimensions         = string.Format("{0:F2} x {1:F2} x {2:F2} [{3}]", product.Length, product.Width, product.Height, baseDimensionIn),
                    QuantityOrdered        = qtyOrdered,
                    QuantityInThisShipment = qtyInThisShipment,
                    QuantityInAllShipments = qtyInAllShipments,
                    QuantityToAdd          = maxQtyToAdd,
                };

                if (product.ManageInventoryMethodId == ManageInventoryMethod.ManageStock)
                {
                    if (product.UseMultipleWarehouses)
                    {
                        //multiple warehouses supported
                        shipmentItemModel.AllowToChooseWarehouse = true;
                        foreach (var pwi in product.ProductWarehouseInventory
                                 .OrderBy(w => w.WarehouseId).ToList())
                        {
                            var warehouse = await _warehouseService.GetWarehouseById(pwi.WarehouseId);

                            if (warehouse != null)
                            {
                                shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                                {
                                    WarehouseId      = warehouse.Id,
                                    WarehouseName    = warehouse.Name,
                                    StockQuantity    = pwi.StockQuantity,
                                    ReservedQuantity = pwi.ReservedQuantity,
                                    PlannedQuantity  = await _shipmentService.GetQuantityInShipments(product, orderItem.Attributes, warehouse.Id, true, true)
                                });
                            }
                        }
                    }
                    else
                    {
                        //multiple warehouses are not supported
                        var warehouse = await _warehouseService.GetWarehouseById(product.WarehouseId);

                        if (warehouse != null)
                        {
                            shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                            {
                                WarehouseId   = warehouse.Id,
                                WarehouseName = warehouse.Name,
                                StockQuantity = product.StockQuantity
                            });
                        }
                    }
                }

                if (product.ManageInventoryMethodId == ManageInventoryMethod.ManageStockByAttributes)
                {
                    if (product.UseMultipleWarehouses)
                    {
                        //multiple warehouses supported
                        shipmentItemModel.AllowToChooseWarehouse = true;
                        var comb = _productAttributeParser.FindProductAttributeCombination(product, orderItem.Attributes);
                        if (comb != null)
                        {
                            foreach (var pwi in comb.WarehouseInventory
                                     .OrderBy(w => w.WarehouseId).ToList())
                            {
                                var warehouse = await _warehouseService.GetWarehouseById(pwi.WarehouseId);

                                if (warehouse != null)
                                {
                                    shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                                    {
                                        WarehouseId      = warehouse.Id,
                                        WarehouseName    = warehouse.Name,
                                        StockQuantity    = pwi.StockQuantity,
                                        ReservedQuantity = pwi.ReservedQuantity,
                                        PlannedQuantity  = await _shipmentService.GetQuantityInShipments(product, orderItem.Attributes, warehouse.Id, true, true)
                                    });
                                }
                            }
                        }
                    }
                    else
                    {
                        //multiple warehouses are not supported
                        var warehouse = await _warehouseService.GetWarehouseById(product.WarehouseId);

                        if (warehouse != null)
                        {
                            shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                            {
                                WarehouseId   = warehouse.Id,
                                WarehouseName = warehouse.Name,
                                StockQuantity = product.StockQuantity
                            });
                        }
                    }
                }

                if (product.ManageInventoryMethodId == ManageInventoryMethod.ManageStockByBundleProducts)
                {
                    if (!string.IsNullOrEmpty(orderItem.WarehouseId))
                    {
                        var warehouse = await _warehouseService.GetWarehouseById(product.WarehouseId);

                        if (warehouse != null)
                        {
                            shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                            {
                                WarehouseId      = warehouse.Id,
                                WarehouseName    = warehouse.Name,
                                StockQuantity    = await GetStockQty(product, orderItem.WarehouseId),
                                ReservedQuantity = await GetReservedQty(product, orderItem.WarehouseId),
                                PlannedQuantity  = await GetPlannedQty(product, orderItem.WarehouseId)
                            });
                        }
                    }
                    else
                    {
                        shipmentItemModel.AllowToChooseWarehouse = false;
                        if (shipmentItemModel.AllowToChooseWarehouse)
                        {
                            var warehouses = await _warehouseService.GetAllWarehouses();

                            foreach (var warehouse in warehouses)
                            {
                                shipmentItemModel.AvailableWarehouses.Add(new ShipmentModel.ShipmentItemModel.WarehouseInfo
                                {
                                    WarehouseId      = warehouse.Id,
                                    WarehouseName    = warehouse.Name,
                                    StockQuantity    = await GetStockQty(product, warehouse.Id),
                                    ReservedQuantity = await GetReservedQty(product, warehouse.Id),
                                    PlannedQuantity  = await GetPlannedQty(product, warehouse.Id)
                                });
                            }
                        }
                    }
                }

                model.Items.Add(shipmentItemModel);
            }
            return(model);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Formats the stock availability/quantity message
        /// </summary>
        public static string FormatStockMessage(this Product product, string attributesXml,
                                                ILocalizationService localizationService, IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (localizationService == null)
            {
                throw new ArgumentNullException("localizationService");
            }

            if (productAttributeParser == null)
            {
                throw new ArgumentNullException("productAttributeParser");
            }


            string stockMessage = string.Empty;

            switch (product.ManageInventoryMethod)
            {
            case ManageInventoryMethod.ManageStock:
            {
                #region Manage stock

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var stockQuantity = product.GetTotalStockQuantity();
                if (stockQuantity > 0)
                {
                    stockMessage = product.DisplayStockQuantity ?
                                   //display "in stock" with stock quantity
                                   string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                   //display "in stock" without stock quantity
                                   localizationService.GetResource("Products.Availability.InStock");
                }
                else
                {
                    //out of stock

                    stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.ManageStockByAttributes:
            {
                #region Manage stock by attributes

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    //combination exists
                    var stockQuantity = combination.StockQuantity;
                    if (stockQuantity > 0)
                    {
                        stockMessage = product.DisplayStockQuantity ?
                                       //display "in stock" with stock quantity
                                       string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                       //display "in stock" without stock quantity
                                       localizationService.GetResource("Products.Availability.InStock");
                    }
                    else if (combination.AllowOutOfStockOrders)
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.InStock");
                    }
                    else
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                    }
                }
                else
                {
                    //no combination configured
                    if (product.AllowAddingOnlyExistingAttributeCombinations)
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                    }
                    else
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.InStock");
                    }
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.DontManageStock:
            default:
                return(stockMessage);
            }
            return(stockMessage);
        }
        public async Task <ProductDetailsAttributeChangeModel> Handle(GetProductDetailsAttributeChange request, CancellationToken cancellationToken)
        {
            var model = new ProductDetailsAttributeChangeModel();

            string attributeXml = await _mediator.Send(new GetParseProductAttributes()
            {
                Product = request.Product, Form = request.Form
            });

            string warehouseId = _shoppingCartSettings.AllowToSelectWarehouse ?
                                 request.Form["WarehouseId"].ToString() :
                                 request.Product.UseMultipleWarehouses ? request.Store.DefaultWarehouseId :
                                 (string.IsNullOrEmpty(request.Store.DefaultWarehouseId) ? request.Product.WarehouseId : request.Store.DefaultWarehouseId);

            //rental attributes
            DateTime?rentalStartDate = null;
            DateTime?rentalEndDate   = null;

            if (request.Product.ProductType == ProductType.Reservation)
            {
                request.Product.ParseReservationDates(request.Form, out rentalStartDate, out rentalEndDate);
            }

            model.Sku  = request.Product.FormatSku(attributeXml, _productAttributeParser);
            model.Mpn  = request.Product.FormatMpn(attributeXml, _productAttributeParser);
            model.Gtin = request.Product.FormatGtin(attributeXml, _productAttributeParser);

            if (await _permissionService.Authorize(StandardPermissionProvider.DisplayPrices) && !request.Product.CustomerEntersPrice && request.Product.ProductType != ProductType.Auction)
            {
                //we do not calculate price of "customer enters price" option is enabled
                var unitprice = await _priceCalculationService.GetUnitPrice(request.Product,
                                                                            request.Customer,
                                                                            ShoppingCartType.ShoppingCart,
                                                                            1, attributeXml, 0,
                                                                            rentalStartDate, rentalEndDate,
                                                                            true);

                decimal discountAmount             = unitprice.discountAmount;
                List <AppliedDiscount> scDiscounts = unitprice.appliedDiscounts;
                decimal finalPrice   = unitprice.unitprice;
                var     productprice = await _taxService.GetProductPrice(request.Product, finalPrice);

                decimal finalPriceWithDiscountBase = productprice.productprice;
                decimal taxRate = productprice.taxRate;
                decimal finalPriceWithDiscount = await _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceWithDiscountBase, request.Currency);

                model.Price = _priceFormatter.FormatPrice(finalPriceWithDiscount);
            }
            //stock
            model.StockAvailability = request.Product.FormatStockMessage(warehouseId, attributeXml, _localizationService, _productAttributeParser);

            //back in stock subscription
            if ((request.Product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes ||
                 request.Product.ManageInventoryMethod == ManageInventoryMethod.ManageStock) &&
                request.Product.BackorderMode == BackorderMode.NoBackorders &&
                request.Product.AllowBackInStockSubscriptions)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(request.Product, attributeXml);

                if (combination != null)
                {
                    if (request.Product.GetTotalStockQuantityForCombination(combination, warehouseId: request.Store.DefaultWarehouseId) <= 0)
                    {
                        model.DisplayBackInStockSubscription = true;
                    }
                }

                if (request.Product.ManageInventoryMethod == ManageInventoryMethod.ManageStock)
                {
                    model.DisplayBackInStockSubscription = request.Product.AllowBackInStockSubscriptions;
                    attributeXml = "";
                }

                var subscription = await _backInStockSubscriptionService
                                   .FindSubscription(request.Customer.Id,
                                                     request.Product.Id, attributeXml, request.Store.Id, warehouseId);

                if (subscription != null)
                {
                    model.ButtonTextBackInStockSubscription = _localizationService.GetResource("BackInStockSubscriptions.DeleteNotifyWhenAvailable");
                }
                else
                {
                    model.ButtonTextBackInStockSubscription = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable");
                }
            }


            //conditional attributes
            if (request.ValidateAttributeConditions)
            {
                var attributes = request.Product.ProductAttributeMappings;
                foreach (var attribute in attributes)
                {
                    var conditionMet = _productAttributeParser.IsConditionMet(request.Product, attribute, attributeXml);
                    if (conditionMet.HasValue)
                    {
                        if (conditionMet.Value)
                        {
                            model.EnabledAttributeMappingIds.Add(attribute.Id);
                        }
                        else
                        {
                            model.DisabledAttributeMappingids.Add(attribute.Id);
                        }
                    }
                }
            }
            //picture. used when we want to override a default product picture when some attribute is selected
            if (request.LoadPicture)
            {
                //first, try to get product attribute combination picture
                var pictureId = request.Product.ProductAttributeCombinations.Where(x => x.AttributesXml == attributeXml).FirstOrDefault()?.PictureId ?? "";
                //then, let's see whether we have attribute values with pictures
                if (string.IsNullOrEmpty(pictureId))
                {
                    pictureId = _productAttributeParser.ParseProductAttributeValues(request.Product, attributeXml)
                                .FirstOrDefault(attributeValue => !string.IsNullOrEmpty(attributeValue.PictureId))?.PictureId ?? "";
                }

                if (!string.IsNullOrEmpty(pictureId))
                {
                    var pictureModel = new PictureModel {
                        Id = pictureId,
                        FullSizeImageUrl = await _pictureService.GetPictureUrl(pictureId),
                        ImageUrl         = await _pictureService.GetPictureUrl(pictureId, _mediaSettings.ProductDetailsPictureSize)
                    };
                    model.PictureFullSizeUrl    = pictureModel.FullSizeImageUrl;
                    model.PictureDefaultSizeUrl = pictureModel.ImageUrl;
                }
            }
            return(model);
        }
        public virtual async Task <IActionResult> SubscribePopup(string productId, IFormCollection form)
        {
            var product = await _productService.GetProductById(productId);

            if (product == null)
            {
                throw new ArgumentException("No product found with the specified id");
            }

            var customer = _workContext.CurrentCustomer;

            if (!customer.IsRegistered())
            {
                return(Json(new
                {
                    subscribe = false,
                    buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                    resource = _localizationService.GetResource("BackInStockSubscriptions.OnlyRegistered")
                }));
            }

            if ((product.ManageInventoryMethod == ManageInventoryMethod.ManageStock) &&
                product.BackorderMode == BackorderMode.NoBackorders &&
                product.AllowBackInStockSubscriptions &&
                product.GetTotalStockQuantity(warehouseId: _storeContext.CurrentStore.DefaultWarehouseId) <= 0)
            {
                var subscription = await _backInStockSubscriptionService
                                   .FindSubscription(customer.Id, product.Id, string.Empty, _storeContext.CurrentStore.Id, product.UseMultipleWarehouses?_storeContext.CurrentStore.DefaultWarehouseId : "");

                if (subscription != null)
                {
                    //subscription already exists
                    //unsubscribe
                    await _backInStockSubscriptionService.DeleteSubscription(subscription);

                    return(Json(new
                    {
                        subscribe = false,
                        buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                        resource = _localizationService.GetResource("BackInStockSubscriptions.Unsubscribed")
                    }));
                }

                //subscription does not exist
                //subscribe
                if ((await _backInStockSubscriptionService
                     .GetAllSubscriptionsByCustomerId(customer.Id, _storeContext.CurrentStore.Id, 0, 1))
                    .TotalCount >= _catalogSettings.MaximumBackInStockSubscriptions)
                {
                    return(Json(new
                    {
                        subscribe = false,
                        buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                        resource = string.Format(_localizationService.GetResource("BackInStockSubscriptions.MaxSubscriptions"), _catalogSettings.MaximumBackInStockSubscriptions)
                    }));
                }
                subscription = new BackInStockSubscription {
                    CustomerId   = customer.Id,
                    ProductId    = product.Id,
                    StoreId      = _storeContext.CurrentStore.Id,
                    WarehouseId  = product.UseMultipleWarehouses ? _storeContext.CurrentStore.DefaultWarehouseId : "",
                    CreatedOnUtc = DateTime.UtcNow
                };
                await _backInStockSubscriptionService.InsertSubscription(subscription);

                return(Json(new
                {
                    subscribe = true,
                    buttontext = _localizationService.GetResource("BackInStockSubscriptions.DeleteNotifyWhenAvailable"),
                    resource = _localizationService.GetResource("BackInStockSubscriptions.Subscribed")
                }));
            }

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes &&
                product.BackorderMode == BackorderMode.NoBackorders &&
                product.AllowBackInStockSubscriptions)
            {
                string attributeXml = await _shoppingCartViewModelService.ParseProductAttributes(product, form);

                var combination  = _productAttributeParser.FindProductAttributeCombination(product, attributeXml);
                var subscription = await _backInStockSubscriptionService
                                   .FindSubscription(customer.Id, product.Id, attributeXml, _storeContext.CurrentStore.Id, product.UseMultipleWarehouses?_storeContext.CurrentStore.DefaultWarehouseId : "");

                if (subscription != null)
                {
                    //subscription already exists
                    //unsubscribe
                    await _backInStockSubscriptionService.DeleteSubscription(subscription);

                    return(Json(new
                    {
                        subscribe = false,
                        buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                        resource = _localizationService.GetResource("BackInStockSubscriptions.Unsubscribed")
                    }));
                }

                //subscription does not exist
                //subscribe
                if ((await _backInStockSubscriptionService
                     .GetAllSubscriptionsByCustomerId(customer.Id, _storeContext.CurrentStore.Id, 0, 1))
                    .TotalCount >= _catalogSettings.MaximumBackInStockSubscriptions)
                {
                    return(Json(new
                    {
                        subscribe = false,
                        buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                        resource = string.Format(_localizationService.GetResource("BackInStockSubscriptions.MaxSubscriptions"), _catalogSettings.MaximumBackInStockSubscriptions)
                    }));
                }

                subscription = new BackInStockSubscription {
                    CustomerId   = customer.Id,
                    ProductId    = product.Id,
                    AttributeXml = attributeXml,
                    StoreId      = _storeContext.CurrentStore.Id,
                    WarehouseId  = product.UseMultipleWarehouses ? _storeContext.CurrentStore.DefaultWarehouseId : "",
                    CreatedOnUtc = DateTime.UtcNow
                };

                await _backInStockSubscriptionService.InsertSubscription(subscription);

                return(Json(new
                {
                    subscribe = true,
                    buttontext = _localizationService.GetResource("BackInStockSubscriptions.DeleteNotifyWhenAvailable"),
                    resource = _localizationService.GetResource("BackInStockSubscriptions.Subscribed")
                }));
            }

            return(Json(new
            {
                subscribe = false,
                buttontext = _localizationService.GetResource("BackInStockSubscriptions.NotifyMeWhenAvailable"),
                resource = _localizationService.GetResource("BackInStockSubscriptions.NotAllowed")
            }));
        }
        /// <summary>
        /// Handle shopping cart changed event
        /// </summary>
        /// <param name="cartItem">Shopping cart item</param>
        public void HandleShoppingCartChangedEvent(ShoppingCartItem cartItem)
        {
            //whether marketing automation is enabled
            if (!_sendInBlueSettings.UseMarketingAutomation)
            {
                return;
            }

            try
            {
                //create API client
                var client = CreateMarketingAutomationClient();

                //first, try to identify current customer
                client.Identify(new Identify(cartItem.Customer.Email));

                //get shopping cart GUID
                var shoppingCartGuid = _genericAttributeService.GetAttribute <Guid?>(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute);

                //create track event object
                var trackEvent = new TrackEvent(cartItem.Customer.Email, string.Empty);

                //get current customer's shopping cart
                var cart = cartItem.Customer.ShoppingCartItems
                           .Where(item => item.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(_storeContext.CurrentStore.Id).ToList();

                if (cart.Any())
                {
                    //get URL helper
                    var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);

                    //get shopping cart amounts
                    _orderTotalCalculationService.GetShoppingCartSubTotal(cart, _workContext.TaxDisplayType == TaxDisplayType.IncludingTax,
                                                                          out var cartDiscount, out _, out var cartSubtotal, out _);
                    var cartTax      = _orderTotalCalculationService.GetTaxTotal(cart, false);
                    var cartShipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart);
                    var cartTotal    = _orderTotalCalculationService.GetShoppingCartTotal(cart, false, false);

                    //get products data by shopping cart items
                    var itemsData = cart.Where(item => item.Product != null).Select(item =>
                    {
                        //try to get product attribute combination
                        var combination = _productAttributeParser.FindProductAttributeCombination(item.Product, item.AttributesXml);

                        //get default product picture
                        var picture = _pictureService.GetProductPicture(item.Product, item.AttributesXml);

                        //get product SEO slug name
                        var seName = _urlRecordService.GetSeName(item.Product);

                        //create product data
                        return(new
                        {
                            id = item.Product.Id,
                            name = item.Product.Name,
                            variant_id = combination?.Id ?? item.Product.Id,
                            variant_name = combination?.Sku ?? item.Product.Name,
                            sku = combination?.Sku ?? item.Product.Sku,
                            category = item.Product.ProductCategories.Aggregate(",", (all, category) => {
                                var res = category.Category.Name;
                                res = all == "," ? res : all + ", " + res;
                                return res;
                            }),
                            url = urlHelper.RouteUrl("Product", new { SeName = seName }, _webHelper.CurrentRequestProtocol),
                            image = _pictureService.GetPictureUrl(picture),
                            quantity = item.Quantity,
                            price = _priceCalculationService.GetSubTotal(item)
                        });
                    }).ToArray();

                    //prepare cart data
                    var cartData = new
                    {
                        affiliation      = _storeContext.CurrentStore.Name,
                        subtotal         = cartSubtotal,
                        shipping         = cartShipping ?? decimal.Zero,
                        total_before_tax = cartSubtotal + cartShipping ?? decimal.Zero,
                        tax      = cartTax,
                        discount = cartDiscount,
                        revenue  = cartTotal ?? decimal.Zero,
                        url      = urlHelper.RouteUrl("ShoppingCart", null, _webHelper.CurrentRequestProtocol),
                        currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)?.CurrencyCode,
                        //gift_wrapping = string.Empty, //currently we can't get this value
                        items = itemsData
                    };

                    //if there is a single item in the cart, so the cart is just created
                    if (cart.Count == 1)
                    {
                        shoppingCartGuid = Guid.NewGuid();
                    }
                    else
                    {
                        //otherwise cart is updated
                        shoppingCartGuid = shoppingCartGuid ?? Guid.NewGuid();
                    }
                    trackEvent.EventName = SendinBlueDefaults.CartUpdatedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}", data = cartData };
                }
                else
                {
                    //there are no items in the cart, so the cart is deleted
                    shoppingCartGuid     = shoppingCartGuid ?? Guid.NewGuid();
                    trackEvent.EventName = SendinBlueDefaults.CartDeletedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}" };
                }

                //track event
                client.TrackEvent(trackEvent);

                //update GUID for the current customer's shopping cart
                _genericAttributeService.SaveAttribute(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute, shoppingCartGuid);
            }
            catch (Exception exception)
            {
                //log full error
                _logger.Error($"SendinBlue Marketing Automation error: {exception.Message}.", exception, cartItem.Customer);
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Formats the stock availability/quantity message
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Selected product attributes in XML format (if specified)</param>
        /// <param name="localizationService">Localization service</param>
        /// <param name="productAttributeParser">Product attribute parser</param>
        /// <returns>The stock message</returns>
        public static string FormatStockMessage(this Product product, string attributesXml,
            ILocalizationService localizationService, IProductAttributeParser productAttributeParser)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            if (localizationService == null)
                throw new ArgumentNullException("localizationService");

            if (productAttributeParser == null)
                throw new ArgumentNullException("productAttributeParser");

            string stockMessage = string.Empty;

            switch (product.ManageInventoryMethod)
            {
                case ManageInventoryMethod.ManageStock:
                {
                        #region Manage stock
                        
                        if (!product.DisplayStockAvailability)
                            return stockMessage;

                        var stockQuantity = product.GetTotalStockQuantity();
                        if (stockQuantity > 0)
                        {
                            stockMessage = product.DisplayStockQuantity ?
                                //display "in stock" with stock quantity
                                string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                //display "in stock" without stock quantity
                                localizationService.GetResource("Products.Availability.InStock");
                        }
                        else
                        {
                            //out of stock
                            switch (product.BackorderMode)
                            {
                                case BackorderMode.NoBackorders:
                                    stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                                    break;
                                case BackorderMode.AllowQtyBelow0:
                                    stockMessage = localizationService.GetResource("Products.Availability.InStock");
                                    break;
                                case BackorderMode.AllowQtyBelow0AndNotifyCustomer:
                                    stockMessage = localizationService.GetResource("Products.Availability.Backordering");
                                    break;
                                default:
                                    break;
                            }
                        }
                        
                        #endregion
                    }
                    break;
                case ManageInventoryMethod.ManageStockByAttributes:
                    {
                        #region Manage stock by attributes

                        if (!product.DisplayStockAvailability)
                            return stockMessage;

                        var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                        if (combination != null)
                        {
                            //combination exists
                            var stockQuantity = combination.StockQuantity;
                            if (stockQuantity > 0)
                            {
                                stockMessage = product.DisplayStockQuantity ?
                                    //display "in stock" with stock quantity
                                    string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                    //display "in stock" without stock quantity
                                    localizationService.GetResource("Products.Availability.InStock");
                            }
                            else if (combination.AllowOutOfStockOrders)
                            {
                                stockMessage = localizationService.GetResource("Products.Availability.InStock");
                            }
                            else
                            {
                                stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                            }
                        }
                        else
                        {
                            //no combination configured
                            stockMessage = localizationService.GetResource("Products.Availability.InStock");
                        }

                        #endregion
                    }
                    break;
                case ManageInventoryMethod.DontManageStock:
                default:
                    return stockMessage;
            }
            return stockMessage;
        }
Exemplo n.º 18
0
        /// <summary>
        /// Adjust inventory
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="quantityToChange">Quantity to increase or descrease</param>
        /// <param name="attributesXml">Attributes in XML format</param>
        public virtual async Task AdjustInventory(Product product, int quantityToChange, string attributesXml = "", string warehouseId = "")
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (quantityToChange == 0)
            {
                return;
            }

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock)
            {
                var prevStockQuantity = product.GetTotalStockQuantity(warehouseId: warehouseId);

                //update stock quantity
                if (product.UseMultipleWarehouses)
                {
                    //use multiple warehouses
                    if (quantityToChange < 0)
                    {
                        await ReserveInventory(product, quantityToChange, warehouseId);
                    }
                    else
                    {
                        await UnblockReservedInventory(product, quantityToChange, warehouseId);
                    }

                    product.StockQuantity = product.ProductWarehouseInventory.Sum(x => x.StockQuantity);
                    await UpdateStockProduct(product);
                }
                else
                {
                    //do not use multiple warehouses
                    //simple inventory management
                    product.StockQuantity += quantityToChange;
                    await UpdateStockProduct(product);
                }

                //check if minimum quantity is reached
                if (quantityToChange < 0 && product.MinStockQuantity >= product.GetTotalStockQuantity(warehouseId: ""))
                {
                    switch (product.LowStockActivity)
                    {
                    case LowStockActivity.DisableBuyButton:
                        product.DisableBuyButton      = true;
                        product.DisableWishlistButton = true;

                        var filter = Builders <Product> .Filter.Eq("Id", product.Id);

                        var update = Builders <Product> .Update
                                     .Set(x => x.DisableBuyButton, product.DisableBuyButton)
                                     .Set(x => x.DisableWishlistButton, product.DisableWishlistButton)
                                     .Set(x => x.LowStock, true)
                                     .CurrentDate("UpdatedOnUtc");

                        await _productRepository.Collection.UpdateOneAsync(filter, update);

                        //cache
                        await _cacheManager.RemoveAsync(string.Format(PRODUCTS_BY_ID_KEY, product.Id));

                        //event notification
                        await _mediator.EntityUpdated(product);

                        break;

                    case LowStockActivity.Unpublish:
                        product.Published = false;
                        var filter2 = Builders <Product> .Filter.Eq("Id", product.Id);

                        var update2 = Builders <Product> .Update
                                      .Set(x => x.Published, product.Published)
                                      .CurrentDate("UpdatedOnUtc");

                        await _productRepository.Collection.UpdateOneAsync(filter2, update2);

                        //cache
                        await _cacheManager.RemoveAsync(string.Format(PRODUCTS_BY_ID_KEY, product.Id));

                        if (product.ShowOnHomePage)
                        {
                            await _cacheManager.RemoveByPrefix(PRODUCTS_SHOWONHOMEPAGE);
                        }

                        //event notification
                        await _mediator.EntityUpdated(product);

                        break;

                    default:
                        break;
                    }
                }
                //qty is increased. product is back in stock (minimum stock quantity is reached again)?
                if (_catalogSettings.PublishBackProductWhenCancellingOrders)
                {
                    if (quantityToChange > 0 && prevStockQuantity <= product.MinStockQuantity && product.MinStockQuantity < product.GetTotalStockQuantity(warehouseId: ""))
                    {
                        switch (product.LowStockActivity)
                        {
                        case LowStockActivity.DisableBuyButton:
                            var filter = Builders <Product> .Filter.Eq("Id", product.Id);

                            var update = Builders <Product> .Update
                                         .Set(x => x.DisableBuyButton, product.DisableBuyButton)
                                         .Set(x => x.DisableWishlistButton, product.DisableWishlistButton)
                                         .Set(x => x.LowStock, true)
                                         .CurrentDate("UpdatedOnUtc");

                            await _productRepository.Collection.UpdateOneAsync(filter, update);

                            //cache
                            await _cacheManager.RemoveAsync(string.Format(PRODUCTS_BY_ID_KEY, product.Id));

                            break;

                        case LowStockActivity.Unpublish:
                            product.Published = false;
                            var filter2 = Builders <Product> .Filter.Eq("Id", product.Id);

                            var update2 = Builders <Product> .Update
                                          .Set(x => x.Published, product.Published)
                                          .CurrentDate("UpdatedOnUtc");

                            await _productRepository.Collection.UpdateOneAsync(filter2, update2);

                            //cache
                            await _cacheManager.RemoveAsync(string.Format(PRODUCTS_BY_ID_KEY, product.Id));

                            if (product.ShowOnHomePage)
                            {
                                await _cacheManager.RemoveByPrefix(PRODUCTS_SHOWONHOMEPAGE);
                            }

                            break;

                        default:
                            break;
                        }
                    }
                }

                //send email notification
                if (quantityToChange < 0 && product.GetTotalStockQuantity(warehouseId: warehouseId) < product.NotifyAdminForQuantityBelow)
                {
                    await _mediator.Send(new SendQuantityBelowStoreOwnerNotificationCommand()
                    {
                        Product = product
                    });
                }
            }

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    combination.ProductId = product.Id;
                    if (!product.UseMultipleWarehouses)
                    {
                        combination.StockQuantity += quantityToChange;
                        await _productAttributeService.UpdateProductAttributeCombination(combination);
                    }
                    else
                    {
                        if (quantityToChange < 0)
                        {
                            await ReserveInventoryCombination(product, combination, quantityToChange, warehouseId);
                        }
                        else
                        {
                            await UnblockReservedInventoryCombination(product, combination, quantityToChange, warehouseId);
                        }
                    }

                    product.StockQuantity += quantityToChange;
                    await UpdateStockProduct(product);

                    //send email notification
                    if (quantityToChange < 0 && combination.StockQuantity < combination.NotifyAdminForQuantityBelow)
                    {
                        await _mediator.Send(new SendQuantityBelowStoreOwnerNotificationCommand()
                        {
                            Product = product,
                            ProductAttributeCombination = combination
                        });
                    }
                }
            }

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByBundleProducts)
            {
                foreach (var item in product.BundleProducts)
                {
                    var p1 = await _productRepository.GetByIdAsync(item.ProductId);

                    if (p1 != null && (p1.ManageInventoryMethod == ManageInventoryMethod.ManageStock || p1.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes))
                    {
                        await AdjustInventory(p1, quantityToChange *item.Quantity, attributesXml, warehouseId);
                    }
                }
            }

            //bundled products
            var attributeValues = _productAttributeParser.ParseProductAttributeValues(product, attributesXml);

            foreach (var attributeValue in attributeValues)
            {
                if (attributeValue.AttributeValueType == AttributeValueType.AssociatedToProduct)
                {
                    //associated product (bundle)
                    var associatedProduct = await _productRepository.GetByIdAsync(attributeValue.AssociatedProductId);

                    if (associatedProduct != null)
                    {
                        await AdjustInventory(associatedProduct, quantityToChange *attributeValue.Quantity, warehouseId);
                    }
                }
            }

            //event notification
            await _mediator.EntityUpdated(product);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Get product picture (for shopping cart and order details pages)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Atributes (in XML format)</param>
        /// <param name="pictureService">Picture service</param>
        /// <param name="productAttributeParser">Product attribute service</param>
        /// <returns>Picture</returns>
        public static async Task <Picture> GetProductPicture(this Product product, IList <CustomAttribute> attributes,
                                                             IProductService productService, IPictureService pictureService,
                                                             IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }
            if (pictureService == null)
            {
                throw new ArgumentNullException("pictureService");
            }
            if (productAttributeParser == null)
            {
                throw new ArgumentNullException("productAttributeParser");
            }

            Picture picture = null;

            //first, let's see whether we have some attribute values with custom pictures
            if (attributes != null && attributes.Any())
            {
                var comb = productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (comb != null)
                {
                    if (!string.IsNullOrEmpty(comb.PictureId))
                    {
                        var combPicture = await pictureService.GetPictureById(comb.PictureId);

                        if (combPicture != null)
                        {
                            picture = combPicture;
                        }
                    }
                }
                if (picture == null)
                {
                    var attributeValues = productAttributeParser.ParseProductAttributeValues(product, attributes);
                    foreach (var attributeValue in attributeValues)
                    {
                        var attributePicture = await pictureService.GetPictureById(attributeValue.PictureId);

                        if (attributePicture != null)
                        {
                            picture = attributePicture;
                            break;
                        }
                    }
                }
            }
            //now let's load the default product picture
            if (picture == null)
            {
                var pp = product.ProductPictures.OrderBy(x => x.DisplayOrder).FirstOrDefault();
                if (pp != null)
                {
                    picture = await pictureService.GetPictureById(pp.PictureId);
                }
            }

            //let's check whether this product has some parent "grouped" product
            if (picture == null && !product.VisibleIndividually && !string.IsNullOrEmpty(product.ParentGroupedProductId))
            {
                var parentProduct = await productService.GetProductById(product.ParentGroupedProductId);

                if (parentProduct != null)
                {
                    if (parentProduct.ProductPictures.Any())
                    {
                        picture = await pictureService.GetPictureById(parentProduct.ProductPictures.FirstOrDefault().PictureId);
                    }
                }
            }

            return(picture);
        }
Exemplo n.º 20
0
        /// <summary>
        /// Gets the shopping cart unit price
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="currency">The currency</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="attributes">Product atrributes</param>
        /// <param name="customerEnteredPrice">Customer entered price</param>
        /// <param name="rentalStartDate">Rental start date</param>
        /// <param name="rentalEndDate">Rental end date</param>
        /// <param name="includeDiscounts">Include discounts or not for price</param>
        /// <returns>Shopping cart unit price</returns>
        public virtual async Task <(double unitprice, double discountAmount, List <ApplyDiscount> appliedDiscounts)> GetUnitPrice(
            Product product,
            Customer customer,
            Currency currency,
            ShoppingCartType shoppingCartType,
            int quantity,
            IList <CustomAttribute> attributes,
            double?customerEnteredPrice,
            DateTime?rentalStartDate,
            DateTime?rentalEndDate,
            bool includeDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            if (customer == null)
            {
                throw new ArgumentNullException(nameof(customer));
            }

            double discountAmount   = 0;
            var    appliedDiscounts = new List <ApplyDiscount>();

            double?finalPrice = null;

            if (customerEnteredPrice.HasValue)
            {
                finalPrice = await _currencyService.ConvertFromPrimaryStoreCurrency(customerEnteredPrice.Value, currency);
            }

            if (!finalPrice.HasValue)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (combination != null)
                {
                    if (combination.OverriddenPrice.HasValue)
                    {
                        finalPrice = await _currencyService.ConvertFromPrimaryStoreCurrency(combination.OverriddenPrice.Value, currency);
                    }
                    if (combination.TierPrices.Any())
                    {
                        var storeId          = _workContext.CurrentStore.Id;
                        var actualTierPrices = combination.TierPrices.Where(x => string.IsNullOrEmpty(x.StoreId) || x.StoreId == storeId)
                                               .Where(x => string.IsNullOrEmpty(x.CustomerGroupId) ||
                                                      customer.Groups.Contains(x.CustomerGroupId)).ToList();
                        var tierPrice = actualTierPrices.LastOrDefault(price => quantity >= price.Quantity);
                        if (tierPrice != null)
                        {
                            finalPrice = await _currencyService.ConvertFromPrimaryStoreCurrency(tierPrice.Price, currency);
                        }
                    }
                }
            }
            if (!finalPrice.HasValue)
            {
                //summarize price of all attributes
                double attributesTotalPrice = 0;
                if (attributes != null && attributes.Any())
                {
                    if (product.ProductTypeId != ProductType.BundledProduct)
                    {
                        var attributeValues = _productAttributeParser.ParseProductAttributeValues(product, attributes);
                        if (attributeValues != null)
                        {
                            foreach (var attributeValue in attributeValues)
                            {
                                attributesTotalPrice += await GetProductAttributeValuePriceAdjustment(attributeValue);
                            }
                        }
                    }
                    else
                    {
                        foreach (var item in product.BundleProducts)
                        {
                            var p1 = await _productService.GetProductById(item.ProductId);

                            if (p1 != null)
                            {
                                var attributeValues = _productAttributeParser.ParseProductAttributeValues(p1, attributes);
                                if (attributeValues != null)
                                {
                                    foreach (var attributeValue in attributeValues)
                                    {
                                        attributesTotalPrice += (item.Quantity * await GetProductAttributeValuePriceAdjustment(attributeValue));
                                    }
                                }
                            }
                        }
                    }
                }

                if (product.EnteredPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty = 0;
                    if (_shoppingCartSettings.GroupTierPrices)
                    {
                        qty = customer.ShoppingCartItems
                              .Where(x => x.ProductId == product.Id)
                              .Where(x => x.ShoppingCartTypeId == shoppingCartType)
                              .Sum(x => x.Quantity);
                    }
                    if (qty == 0)
                    {
                        qty = quantity;
                    }

                    var getfinalPrice = await GetFinalPrice(product,
                                                            customer,
                                                            currency,
                                                            attributesTotalPrice,
                                                            includeDiscounts,
                                                            qty,
                                                            rentalStartDate,
                                                            rentalEndDate);

                    finalPrice       = getfinalPrice.finalPrice;
                    discountAmount   = getfinalPrice.discountAmount;
                    appliedDiscounts = getfinalPrice.appliedDiscounts;
                }
            }

            if (!finalPrice.HasValue)
            {
                finalPrice = 0;
            }

            //rounding
            if (_shoppingCartSettings.RoundPrices)
            {
                finalPrice = RoundingHelper.RoundPrice(finalPrice.Value, _workContext.WorkingCurrency);
            }
            return(finalPrice.Value, discountAmount, appliedDiscounts);
        }
Exemplo n.º 21
0
        /// <summary>
        /// Gets SKU, Manufacturer part number and GTIN
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Attributes in XML format</param>
        /// <param name="productAttributeParser">Product attribute service (used when attributes are specified)</param>
        /// <param name="sku">SKU</param>
        /// <param name="manufacturerPartNumber">Manufacturer part number</param>
        /// <param name="gtin">GTIN</param>
        private static void GetSkuMpnGtin(this Product product, string attributesXml, IProductAttributeParser productAttributeParser,
            out string sku, out string manufacturerPartNumber, out string gtin)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            sku = null;
            manufacturerPartNumber = null;
            gtin = null;

            if (!String.IsNullOrEmpty(attributesXml) && 
                product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                //manage stock by attribute combinations
                if (productAttributeParser == null)
                    throw new ArgumentNullException("productAttributeParser");

                //let's find appropriate record
                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    sku = combination.Sku;
                    manufacturerPartNumber = combination.ManufacturerPartNumber;
                    gtin = combination.Gtin;
                }
            }

            if (String.IsNullOrEmpty(sku))
                sku = product.Sku;
            if (String.IsNullOrEmpty(manufacturerPartNumber))
                manufacturerPartNumber = product.ManufacturerPartNumber;
            if (String.IsNullOrEmpty(gtin))
                gtin = product.Gtin;
        }
Exemplo n.º 22
0
        /// <summary>
        /// Get product picture (for shopping cart and order details pages)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributes">Atributes </param>
        /// <param name="pictureService">Picture service</param>
        /// <param name="productAttributeParser">Product attribute service</param>
        /// <returns>Picture</returns>
        public static async Task <Picture> GetProductPicture(this Product product, IList <CustomAttribute> attributes,
                                                             IProductService productService, IPictureService pictureService,
                                                             IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }
            if (pictureService == null)
            {
                throw new ArgumentNullException(nameof(pictureService));
            }
            if (productAttributeParser == null)
            {
                throw new ArgumentNullException(nameof(productAttributeParser));
            }

            Picture picture = null;

            if (attributes != null && attributes.Any())
            {
                var comb = productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (comb != null)
                {
                    if (!string.IsNullOrEmpty(comb.PictureId))
                    {
                        var combPicture = await pictureService.GetPictureById(comb.PictureId);

                        if (combPicture != null)
                        {
                            picture = combPicture;
                        }
                    }
                }
                if (picture == null)
                {
                    var attributeValues = productAttributeParser.ParseProductAttributeValues(product, attributes);
                    foreach (var attributeValue in attributeValues)
                    {
                        var attributePicture = await pictureService.GetPictureById(attributeValue.PictureId);

                        if (attributePicture != null)
                        {
                            picture = attributePicture;
                            break;
                        }
                    }
                }
            }
            if (picture == null)
            {
                var pp = product.ProductPictures.OrderBy(x => x.DisplayOrder).FirstOrDefault();
                if (pp != null)
                {
                    picture = await pictureService.GetPictureById(pp.PictureId);
                }
            }

            if (picture == null && !product.VisibleIndividually && !string.IsNullOrEmpty(product.ParentGroupedProductId))
            {
                var parentProduct = await productService.GetProductById(product.ParentGroupedProductId);

                if (parentProduct != null)
                {
                    if (parentProduct.ProductPictures.Any())
                    {
                        picture = await pictureService.GetPictureById(parentProduct.ProductPictures.FirstOrDefault().PictureId);
                    }
                }
            }

            return(picture);
        }
Exemplo n.º 23
0
        /// <summary>
        /// Gets the shopping cart unit price (one item)
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="attributesXml">Product atrributes (XML format)</param>
        /// <param name="customerEnteredPrice">Customer entered price (if specified)</param>
        /// <param name="rentalStartDate">Rental start date (null for not rental products)</param>
        /// <param name="rentalEndDate">Rental end date (null for not rental products)</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for price computation</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscounts">Applied discounts</param>
        /// <returns>Shopping cart unit price (one item)</returns>
        public virtual decimal GetUnitPrice(Product product,
                                            Customer customer,
                                            ShoppingCartType shoppingCartType,
                                            int quantity,
                                            string attributesXml,
                                            decimal customerEnteredPrice,
                                            DateTime?rentalStartDate, DateTime?rentalEndDate,
                                            bool includeDiscounts,
                                            out decimal discountAmount,
                                            out List <DiscountForCaching> appliedDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (customer == null)
            {
                throw new ArgumentNullException("customer");
            }

            discountAmount   = decimal.Zero;
            appliedDiscounts = new List <DiscountForCaching>();

            decimal finalPrice;

            var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);

            if (combination != null && combination.OverriddenPrice.HasValue)
            {
                finalPrice = GetFinalPrice(product,
                                           customer,
                                           combination.OverriddenPrice.Value,
                                           decimal.Zero,
                                           includeDiscounts,
                                           quantity,
                                           product.IsRental ? rentalStartDate : null,
                                           product.IsRental ? rentalEndDate : null,
                                           out discountAmount, out appliedDiscounts);
            }
            else
            {
                //summarize price of all attributes
                decimal attributesTotalPrice = decimal.Zero;
                var     attributeValues      = _productAttributeParser.ParseProductAttributeValues(attributesXml);
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        attributesTotalPrice += GetProductAttributeValuePriceAdjustment(attributeValue);
                    }
                }

                //get price of a product (with previously calculated price of all attributes)
                if (product.CustomerEntersPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty;
                    if (_shoppingCartSettings.GroupTierPricesForDistinctShoppingCartItems)
                    {
                        //the same products with distinct product attributes could be stored as distinct "ShoppingCartItem" records
                        //so let's find how many of the current products are in the cart
                        qty = customer.ShoppingCartItems
                              .Where(x => x.ProductId == product.Id)
                              .Where(x => x.ShoppingCartType == shoppingCartType)
                              .Sum(x => x.Quantity);
                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }
                    finalPrice = GetFinalPrice(product,
                                               customer,
                                               attributesTotalPrice,
                                               includeDiscounts,
                                               qty,
                                               product.IsRental ? rentalStartDate : null,
                                               product.IsRental ? rentalEndDate : null,
                                               out discountAmount, out appliedDiscounts);
                }
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                finalPrice = RoundingHelper.RoundPrice(finalPrice);
            }

            return(finalPrice);
        }
        public override void AdjustInventory(Product product, int quantityToChange, string attributesXml = "", string message = "")
        {
            Debug.WriteLine("*****In New Override Adjust Inventory*****");

            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            if (quantityToChange == 0)
            {
                return;
            }

            //WGR Get the MMS total stock
            var mms_stock_qty = GetMmsStockQty(product);

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock)
            {
                //previous stock
                var prevStockQuantity = GetTotalStockQuantity(product);

                //update stock quantity
                if (product.UseMultipleWarehouses)
                {
                    //use multiple warehouses
                    if (quantityToChange < 0)
                    {
                        ReserveInventory(product, quantityToChange);
                    }
                    else
                    {
                        UnblockReservedInventory(product, quantityToChange);
                    }
                }
                else
                {
                    //do not use multiple warehouses
                    //simple inventory management
                    product.StockQuantity += quantityToChange;
                    UpdateProduct(product);

                    //quantity change history
                    AddStockQuantityHistoryEntry(product, quantityToChange, product.StockQuantity, product.WarehouseId, message);
                }

                //qty is reduced. check if minimum stock quantity is reached
                if ((quantityToChange < 0) && (product.MinStockQuantity >= mms_stock_qty))  //WGR
                {
                    //what should we do now? disable buy button, unpublish the product, or do nothing? check "Low stock activity" property
                    switch (product.LowStockActivity)
                    {
                    case LowStockActivity.DisableBuyButton:
                        product.DisableBuyButton      = true;
                        product.DisableWishlistButton = true;
                        UpdateProduct(product);
                        break;

                    case LowStockActivity.Unpublish:
                        product.Published = false;
                        UpdateProduct(product);
                        break;

                    default:
                        break;
                    }
                }
                //qty is increased. product is back in stock (minimum stock quantity is reached again)?
                if (_catalogSettings.PublishBackProductWhenCancellingOrders)
                {
                    if (quantityToChange > 0 && prevStockQuantity <= product.MinStockQuantity && product.MinStockQuantity < mms_stock_qty)
                    {
                        switch (product.LowStockActivity)
                        {
                        case LowStockActivity.DisableBuyButton:
                            product.DisableBuyButton      = false;
                            product.DisableWishlistButton = false;
                            UpdateProduct(product);
                            break;

                        case LowStockActivity.Unpublish:
                            product.Published = true;
                            UpdateProduct(product);
                            break;

                        default:
                            break;
                        }
                    }
                }

                //send email notification
                if ((quantityToChange < 0) && (mms_stock_qty < product.NotifyAdminForQuantityBelow)) //WGR
                {
                    var workflowMessageService = EngineContext.Current.Resolve <IWorkflowMessageService>();
                    workflowMessageService.SendQuantityBelowStoreOwnerNotification(product, _localizationSettings.DefaultAdminLanguageId);
                }
            }

            if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
            {
                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    combination.StockQuantity += quantityToChange;
                    _productAttributeService.UpdateProductAttributeCombination(combination);

                    //quantity change history
                    AddStockQuantityHistoryEntry(product, quantityToChange, combination.StockQuantity, message: message, combinationId: combination.Id);

                    //send email notification
                    if (quantityToChange < 0 && combination.StockQuantity < combination.NotifyAdminForQuantityBelow)
                    {
                        var workflowMessageService = EngineContext.Current.Resolve <IWorkflowMessageService>();
                        workflowMessageService.SendQuantityBelowStoreOwnerNotification(combination, _localizationSettings.DefaultAdminLanguageId);
                    }
                }
            }
        } // AdjustInventory
Exemplo n.º 25
0
        public virtual string FormatStockMessage(Product product, string warehouseId, IList <CustomAttribute> attributes)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            string stockMessage = string.Empty;

            switch (product.ManageInventoryMethodId)
            {
            case ManageInventoryMethod.ManageStock:
            {
                #region Manage stock

                if (!product.StockAvailability)
                {
                    return(stockMessage);
                }

                var stockQuantity = GetTotalStockQuantity(product, warehouseId: warehouseId);
                if (stockQuantity > 0)
                {
                    stockMessage = product.DisplayStockQuantity ?
                                   string.Format(_translationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                   _translationService.GetResource("Products.Availability.InStock");
                }
                else
                {
                    switch (product.BackorderModeId)
                    {
                    case BackorderMode.NoBackorders:
                        stockMessage = _translationService.GetResource("Products.Availability.OutOfStock");
                        break;

                    case BackorderMode.AllowQtyBelowZero:
                        stockMessage = _translationService.GetResource("Products.Availability.Backordering");
                        break;

                    default:
                        break;
                    }
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.ManageStockByAttributes:
            {
                #region Manage stock by attributes

                if (!product.StockAvailability)
                {
                    return(stockMessage);
                }

                var combination = _productAttributeParser.FindProductAttributeCombination(product, attributes);
                if (combination != null)
                {
                    //combination exists
                    var stockQuantity = GetTotalStockQuantityForCombination(product, combination, warehouseId: warehouseId);
                    if (stockQuantity > 0)
                    {
                        stockMessage = product.DisplayStockQuantity ?
                                       //display "in stock" with stock quantity
                                       string.Format(_translationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                       //display "in stock" without stock quantity
                                       _translationService.GetResource("Products.Availability.InStock");
                    }
                    else
                    {
                        //out of stock
                        switch (product.BackorderModeId)
                        {
                        case BackorderMode.NoBackorders:
                            stockMessage = _translationService.GetResource("Products.Availability.Attributes.OutOfStock");
                            break;

                        case BackorderMode.AllowQtyBelowZero:
                            stockMessage = _translationService.GetResource("Products.Availability.Attributes.Backordering");
                            break;

                        default:
                            break;
                        }
                        if (!combination.AllowOutOfStockOrders)
                        {
                            stockMessage = _translationService.GetResource("Products.Availability.Attributes.OutOfStock");
                        }
                    }
                }
                else
                {
                    stockMessage = _translationService.GetResource("Products.Availability.AttributeCombinationsNotExists");
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.DontManageStock:
            case ManageInventoryMethod.ManageStockByBundleProducts:
            default:
                return(stockMessage);
            }
            return(stockMessage);
        }
Exemplo n.º 26
0
        public virtual async Task <IList <string> > GetStandardWarnings(Customer customer, Product product, ShoppingCartItem shoppingCartItem)
        {
            if (customer == null)
            {
                throw new ArgumentNullException(nameof(customer));
            }

            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            var warnings = new List <string>();

            //published
            if (!product.Published)
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.ProductUnpublished"));
            }

            //we can't add grouped product
            if (product.ProductTypeId == ProductType.GroupedProduct)
            {
                warnings.Add("You can't add grouped product");
            }

            //ACL
            if (!_aclService.Authorize(product, customer))
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.ProductUnpublished"));
            }

            //Store acl
            if (!_aclService.Authorize(product, shoppingCartItem.StoreId))
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.ProductUnpublished"));
            }

            //disabled "add to cart" button
            if (shoppingCartItem.ShoppingCartTypeId == ShoppingCartType.ShoppingCart && product.DisableBuyButton)
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.BuyingDisabled"));
            }

            //disabled "add to wishlist" button
            if (shoppingCartItem.ShoppingCartTypeId == ShoppingCartType.Wishlist && product.DisableWishlistButton)
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.WishlistDisabled"));
            }

            //call for price
            if (shoppingCartItem.ShoppingCartTypeId == ShoppingCartType.ShoppingCart && product.CallForPrice)
            {
                warnings.Add(_translationService.GetResource("Products.CallForPrice"));
            }

            //customer entered price
            if (product.EnteredPrice)
            {
                var shoppingCartItemEnteredPrice = shoppingCartItem.EnteredPrice.HasValue ? shoppingCartItem.EnteredPrice.Value : 0;
                if (shoppingCartItemEnteredPrice < product.MinEnteredPrice ||
                    shoppingCartItemEnteredPrice > product.MaxEnteredPrice)
                {
                    double minimumCustomerEnteredPrice = await _currencyService.ConvertFromPrimaryStoreCurrency(product.MinEnteredPrice, _workContext.WorkingCurrency);

                    double maximumCustomerEnteredPrice = await _currencyService.ConvertFromPrimaryStoreCurrency(product.MaxEnteredPrice, _workContext.WorkingCurrency);

                    warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.CustomerEnteredPrice.RangeError"),
                                               _priceFormatter.FormatPrice(minimumCustomerEnteredPrice, false),
                                               _priceFormatter.FormatPrice(maximumCustomerEnteredPrice, false)));
                }
            }

            //quantity validation
            var hasQtyWarnings = false;

            if (shoppingCartItem.Quantity < product.OrderMinimumQuantity)
            {
                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.MinimumQuantity"), product.OrderMinimumQuantity));
                hasQtyWarnings = true;
            }
            if (shoppingCartItem.Quantity > product.OrderMaximumQuantity)
            {
                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.MaximumQuantity"), product.OrderMaximumQuantity));
                hasQtyWarnings = true;
            }
            var allowedQuantities = product.ParseAllowedQuantities();

            if (allowedQuantities.Length > 0 && !allowedQuantities.Contains(shoppingCartItem.Quantity))
            {
                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.AllowedQuantities"), string.Join(", ", allowedQuantities)));
            }

            if (_shoppingCartSettings.AllowToSelectWarehouse && string.IsNullOrEmpty(shoppingCartItem.WarehouseId))
            {
                warnings.Add(_translationService.GetResource("ShoppingCart.RequiredWarehouse"));
            }

            var warehouseId = !string.IsNullOrEmpty(shoppingCartItem.WarehouseId) ? shoppingCartItem.WarehouseId : _workContext.CurrentStore?.DefaultWarehouseId;

            if (!string.IsNullOrEmpty(warehouseId))
            {
                var warehouse = await _warehouseService.GetWarehouseById(warehouseId);

                if (warehouse == null)
                {
                    warnings.Add(_translationService.GetResource("ShoppingCart.WarehouseNotExists"));
                }
            }

            var validateOutOfStock = shoppingCartItem.ShoppingCartTypeId == ShoppingCartType.ShoppingCart || !_shoppingCartSettings.AllowOutOfStockItemsToBeAddedToWishlist;

            if (validateOutOfStock && !hasQtyWarnings)
            {
                switch (product.ManageInventoryMethodId)
                {
                case ManageInventoryMethod.DontManageStock:
                {
                    //do nothing
                }
                break;

                case ManageInventoryMethod.ManageStock:
                {
                    if (product.BackorderModeId == BackorderMode.NoBackorders)
                    {
                        var qty = shoppingCartItem.Quantity;

                        qty += customer.ShoppingCartItems
                               .Where(x => x.ShoppingCartTypeId == shoppingCartItem.ShoppingCartTypeId &&
                                      x.WarehouseId == warehouseId &&
                                      x.ProductId == shoppingCartItem.ProductId &&
                                      x.StoreId == shoppingCartItem.StoreId &&
                                      x.Id != shoppingCartItem.Id)
                               .Sum(x => x.Quantity);

                        var maximumQuantityCanBeAdded = _stockQuantityService.GetTotalStockQuantity(product, warehouseId: warehouseId);
                        if (maximumQuantityCanBeAdded < qty)
                        {
                            if (maximumQuantityCanBeAdded <= 0)
                            {
                                warnings.Add(_translationService.GetResource("ShoppingCart.OutOfStock"));
                            }
                            else
                            {
                                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded));
                            }
                        }
                    }
                }
                break;

                case ManageInventoryMethod.ManageStockByBundleProducts:
                {
                    foreach (var item in product.BundleProducts)
                    {
                        var _qty = shoppingCartItem.Quantity * item.Quantity;
                        var p1   = await _productService.GetProductById(item.ProductId);

                        if (p1 != null)
                        {
                            if (p1.BackorderModeId == BackorderMode.NoBackorders)
                            {
                                if (p1.ManageInventoryMethodId == ManageInventoryMethod.ManageStock)
                                {
                                    int maximumQuantityCanBeAdded = _stockQuantityService.GetTotalStockQuantity(p1, warehouseId: warehouseId);
                                    if (maximumQuantityCanBeAdded < _qty)
                                    {
                                        warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.OutOfStock.BundleProduct"), p1.Name));
                                    }
                                }
                                if (p1.ManageInventoryMethodId == ManageInventoryMethod.ManageStockByAttributes)
                                {
                                    var combination = _productAttributeParser.FindProductAttributeCombination(p1, shoppingCartItem.Attributes);
                                    if (combination != null)
                                    {
                                        //combination exists - check stock level
                                        var stockquantity = _stockQuantityService.GetTotalStockQuantityForCombination(p1, combination, warehouseId: warehouseId);
                                        if (!combination.AllowOutOfStockOrders && stockquantity < _qty)
                                        {
                                            if (stockquantity <= 0)
                                            {
                                                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.OutOfStock.BundleProduct"), p1.Name));
                                            }
                                            else
                                            {
                                                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.QuantityExceedsStock.BundleProduct"), p1.Name, stockquantity));
                                            }
                                        }
                                    }
                                    else
                                    {
                                        warnings.Add(_translationService.GetResource("ShoppingCart.Combination.NotExist"));
                                    }
                                }
                            }
                        }
                    }
                }
                break;

                case ManageInventoryMethod.ManageStockByAttributes:
                {
                    var combination = _productAttributeParser.FindProductAttributeCombination(product, shoppingCartItem.Attributes);
                    if (combination != null)
                    {
                        //combination exists - check stock level
                        var stockquantity = _stockQuantityService.GetTotalStockQuantityForCombination(product, combination, warehouseId: warehouseId);
                        if (!combination.AllowOutOfStockOrders && stockquantity < shoppingCartItem.Quantity)
                        {
                            int maximumQuantityCanBeAdded = stockquantity;
                            if (maximumQuantityCanBeAdded <= 0)
                            {
                                warnings.Add(_translationService.GetResource("ShoppingCart.OutOfStock"));
                            }
                            else
                            {
                                warnings.Add(string.Format(_translationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded));
                            }
                        }
                    }
                    else
                    {
                        warnings.Add(_translationService.GetResource("ShoppingCart.Combination.NotExist"));
                    }
                }
                break;

                default:
                    break;
                }
            }

            //availability dates
            bool availableStartDateError = false;

            if (product.AvailableStartDateTimeUtc.HasValue)
            {
                DateTime now = DateTime.UtcNow;
                DateTime availableStartDateTime = DateTime.SpecifyKind(product.AvailableStartDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableStartDateTime.CompareTo(now) > 0)
                {
                    warnings.Add(_translationService.GetResource("ShoppingCart.NotAvailable"));
                    availableStartDateError = true;
                }
            }
            if (product.AvailableEndDateTimeUtc.HasValue && !availableStartDateError && shoppingCartItem.ShoppingCartTypeId == ShoppingCartType.ShoppingCart)
            {
                DateTime now = DateTime.UtcNow;
                DateTime availableEndDateTime = DateTime.SpecifyKind(product.AvailableEndDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableEndDateTime.CompareTo(now) < 0)
                {
                    warnings.Add(_translationService.GetResource("ShoppingCart.NotAvailable"));
                }
            }
            return(warnings);
        }
        /// <summary>
        /// Formats the stock availability/quantity message
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Selected product attributes in XML format (if specified)</param>
        /// <param name="localizationService">Localization service</param>
        /// <param name="productAttributeParser">Product attribute parser</param>
        /// <returns>The stock message</returns>
        public static string FormatStockMessage(this Product product, string warehouseId, string attributesXml,
                                                ILocalizationService localizationService, IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (localizationService == null)
            {
                throw new ArgumentNullException("localizationService");
            }

            if (productAttributeParser == null)
            {
                throw new ArgumentNullException("productAttributeParser");
            }

            string stockMessage = string.Empty;

            switch (product.ManageInventoryMethod)
            {
            case ManageInventoryMethod.ManageStock:
            {
                #region Manage stock

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var stockQuantity = product.GetTotalStockQuantity(warehouseId: warehouseId);
                if (stockQuantity > 0)
                {
                    stockMessage = product.DisplayStockQuantity ?
                                   //display "in stock" with stock quantity
                                   string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                   //display "in stock" without stock quantity
                                   localizationService.GetResource("Products.Availability.InStock");
                }
                else
                {
                    //out of stock
                    switch (product.BackorderMode)
                    {
                    case BackorderMode.NoBackorders:
                        stockMessage = localizationService.GetResource("Products.Availability.OutOfStock");
                        break;

                    case BackorderMode.AllowQtyBelow0:
                        stockMessage = localizationService.GetResource("Products.Availability.InStock");
                        break;

                    case BackorderMode.AllowQtyBelow0AndNotifyCustomer:
                        stockMessage = localizationService.GetResource("Products.Availability.Backordering");
                        break;

                    default:
                        break;
                    }
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.ManageStockByAttributes:
            {
                #region Manage stock by attributes

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    //combination exists
                    var stockQuantity = product.GetTotalStockQuantityForCombination(combination, warehouseId: warehouseId);
                    if (stockQuantity > 0)
                    {
                        stockMessage = product.DisplayStockQuantity ?
                                       //display "in stock" with stock quantity
                                       string.Format(localizationService.GetResource("Products.Availability.InStockWithQuantity"), stockQuantity) :
                                       //display "in stock" without stock quantity
                                       localizationService.GetResource("Products.Availability.InStock");
                    }
                    else
                    {
                        //out of stock
                        switch (product.BackorderMode)
                        {
                        case BackorderMode.NoBackorders:
                            stockMessage = localizationService.GetResource("Products.Availability.Attributes.OutOfStock");
                            break;

                        case BackorderMode.AllowQtyBelow0:
                            stockMessage = localizationService.GetResource("Products.Availability.Attributes.InStock");
                            break;

                        case BackorderMode.AllowQtyBelow0AndNotifyCustomer:
                            stockMessage = localizationService.GetResource("Products.Availability.Attributes.Backordering");
                            break;

                        default:
                            break;
                        }
                        if (!combination.AllowOutOfStockOrders)
                        {
                            stockMessage = localizationService.GetResource("Products.Availability.Attributes.OutOfStock");
                        }
                    }
                }
                else
                {
                    //no combination configured
                    stockMessage = localizationService.GetResource("Products.Availability.InStock");
                    if (product.AllowAddingOnlyExistingAttributeCombinations)
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.AllowAddingOnlyExistingAttributeCombinations.Yes");
                    }
                    else
                    {
                        stockMessage = localizationService.GetResource("Products.Availability.AllowAddingOnlyExistingAttributeCombinations.No");
                    }
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.DontManageStock:
            case ManageInventoryMethod.ManageStockByBundleProducts:
            default:
                return(stockMessage);
            }
            return(stockMessage);
        }
Exemplo n.º 28
0
        /// <summary>
        /// Formats the stock availability/quantity message
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="attributesXml">Selected product attributes in XML format (if specified)</param>
        /// <param name="localizationService">Localization service</param>
        /// <param name="productAttributeParser">Product attribute parser</param>
        /// <returns>The stock message</returns>
        public static string FormatStockMessage(this Product product
                                                , string attributesXml
                                                //LocalizationDomainService localizationService
                                                , IProductAttributeParser productAttributeParser)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            //if (localizationService == null)
            //    throw new ArgumentNullException("localizationService");

            if (productAttributeParser == null)
            {
                throw new ArgumentNullException("productAttributeParser");
            }

            string stockMessage = string.Empty;

            switch (product.ManageInventoryMethod)
            {
            case ManageInventoryMethod.ManageStock:
            {
                #region Manage stock

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var stockQuantity = product.GetTotalStockQuantity();
                if (stockQuantity > 0)
                {
                    stockMessage = product.DisplayStockQuantity ?
                                   //display "in stock" with stock quantity
                                   string.Format(InfoMsg.Products_Availability_InStockWithQuantity, stockQuantity) :
                                   //display "in stock" without stock quantity
                                   InfoMsg.Products_Availability_InStock;
                }
                else
                {
                    //out of stock
                    switch (product.BackorderMode)
                    {
                    case BackorderMode.NoBackorders:
                        stockMessage = InfoMsg.Products_Availability_OutOfStock;
                        break;

                    case BackorderMode.AllowQtyBelow0:
                        stockMessage = InfoMsg.Products_Availability_InStock;
                        break;

                    case BackorderMode.AllowQtyBelow0AndNotifyCustomer:
                        stockMessage = InfoMsg.Products_Availability_Backordering;
                        break;

                    default:
                        break;
                    }
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.ManageStockByAttributes:
            {
                #region Manage stock by attributes

                if (!product.DisplayStockAvailability)
                {
                    return(stockMessage);
                }

                var combination = productAttributeParser.FindProductAttributeCombination(product, attributesXml);
                if (combination != null)
                {
                    //combination exists
                    var stockQuantity = combination.StockQuantity;
                    if (stockQuantity > 0)
                    {
                        stockMessage = product.DisplayStockQuantity ?
                                       //display "in stock" with stock quantity
                                       string.Format(InfoMsg.Products_Availability_InStockWithQuantity, stockQuantity) :
                                       //display "in stock" without stock quantity
                                       InfoMsg.Products_Availability_InStock;
                    }
                    else if (combination.AllowOutOfStockOrders)
                    {
                        stockMessage = InfoMsg.Products_Availability_InStock;
                    }
                    else
                    {
                        stockMessage = InfoMsg.Products_Availability_OutOfStock;
                    }
                }
                else
                {
                    //no combination configured
                    stockMessage = InfoMsg.Products_Availability_InStock;
                }

                #endregion
            }
            break;

            case ManageInventoryMethod.DontManageStock:
            default:
                return(stockMessage);
            }
            return(stockMessage);
        }