Example #1
0
        /// <returns>A task that represents the asynchronous operation</returns>
        protected virtual async Task WriteOrderItemsToXmlAsync(XmlWriter writer, ICollection <OrderItem> orderItems)
        {
            await writer.WriteStartElementAsync("Items");

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

                var order = await _orderService.GetOrderByIdAsync(orderItem.OrderId);

                //is shippable
                if (!product.IsShipEnabled)
                {
                    continue;
                }

                await writer.WriteStartElementAsync("Item");

                var sku = product.Sku;

                if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes)
                {
                    var attributesXml = orderItem.AttributesXml;

                    if (!string.IsNullOrEmpty(attributesXml) && product.ManageInventoryMethod ==
                        ManageInventoryMethod.ManageStockByAttributes)
                    {
                        var combination = await _productAttributeParser.FindProductAttributeCombinationAsync(product, attributesXml);

                        if (combination != null && !string.IsNullOrEmpty(combination.Sku))
                        {
                            sku = combination.Sku;
                        }
                    }
                }

                await writer.WriteElementStringAsync("SKU", string.IsNullOrEmpty(sku)?product.Id.ToString() : sku);

                await writer.WriteElementStringAsync("Name", product.Name);

                await writer.WriteElementStringAsync("Quantity", orderItem.Quantity.ToString());

                await writer.WriteElementStringAsync("UnitPrice", (order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax ? orderItem.UnitPriceInclTax : orderItem.UnitPriceExclTax).ToString(CultureInfo.InvariantCulture));

                await writer.WriteEndElementAsync();

                await writer.FlushAsync();
            }

            await writer.WriteEndElementAsync();

            await writer.FlushAsync();
        }
        /// <summary>
        /// Handle shopping cart changed event
        /// </summary>
        /// <param name="cartItem">Shopping cart item</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleShoppingCartChangedEventAsync(ShoppingCartItem cartItem)
        {
            //whether marketing automation is enabled
            if (!_sendinblueSettings.UseMarketingAutomation)
            {
                return;
            }

            var customer = await _customerService.GetCustomerByIdAsync(cartItem.CustomerId);

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

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

                //get shopping cart GUID
                var shoppingCartGuid = await _genericAttributeService
                                       .GetAttributeAsync <Guid?>(customer, SendinblueDefaults.ShoppingCartGuidAttribute);

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

                //get current customer's shopping cart
                var store = await _storeContext.GetCurrentStoreAsync();

                var cart = await _shoppingCartService
                           .GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, store.Id);

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

                    //get shopping cart amounts
                    var(_, cartDiscount, _, cartSubtotal, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart,
                                                                                                                                await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax);

                    var cartTax = await _orderTotalCalculationService.GetTaxTotalAsync(cart, false);

                    var cartShipping = await _orderTotalCalculationService.GetShoppingCartShippingTotalAsync(cart);

                    var(cartTotal, _, _, _, _, _) = await _orderTotalCalculationService.GetShoppingCartTotalAsync(cart, false, false);

                    //get products data by shopping cart items
                    var itemsData = await cart.Where(item => item.ProductId != 0).SelectAwait(async item =>
                    {
                        var product = await _productService.GetProductByIdAsync(item.ProductId);

                        //try to get product attribute combination
                        var combination = await _productAttributeParser.FindProductAttributeCombinationAsync(product, item.AttributesXml);

                        //get default product picture
                        var picture = await _pictureService.GetProductPictureAsync(product, item.AttributesXml);

                        //get product SEO slug name
                        var seName = await _urlRecordService.GetSeNameAsync(product);

                        //create product data
                        return(new
                        {
                            id = product.Id,
                            name = product.Name,
                            variant_id = combination?.Id ?? product.Id,
                            variant_name = combination?.Sku ?? product.Name,
                            sku = combination?.Sku ?? product.Sku,
                            category = await(await _categoryService.GetProductCategoriesByProductIdAsync(item.ProductId)).AggregateAwaitAsync(",", async(all, pc) =>
                            {
                                var res = (await _categoryService.GetCategoryByIdAsync(pc.CategoryId)).Name;
                                res = all == "," ? res : all + ", " + res;
                                return res;
                            }),
                            url = urlHelper.RouteUrl("Product", new { SeName = seName }, _webHelper.GetCurrentRequestProtocol()),
                            image = (await _pictureService.GetPictureUrlAsync(picture)).Url,
                            quantity = item.Quantity,
                            price = (await _shoppingCartService.GetSubTotalAsync(item, true)).subTotal
                        });
                    }).ToArrayAsync();

                    //prepare cart data
                    var cartData = new
                    {
                        affiliation      = store.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.GetCurrentRequestProtocol()),
                        currency = (await _currencyService.GetCurrencyByIdAsync(_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 ??= 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 ??= Guid.NewGuid();
                    trackEvent.EventName = SendinblueDefaults.CartDeletedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}" };
                }

                //track event
                await client.TrackEventAsync(trackEvent);

                //update GUID for the current customer's shopping cart
                await _genericAttributeService.SaveAttributeAsync(customer, SendinblueDefaults.ShoppingCartGuidAttribute, shoppingCartGuid);
            }
            catch (Exception exception)
            {
                //log full error
                await _logger.ErrorAsync($"Sendinblue Marketing Automation error: {exception.Message}.", exception, customer);
            }
        }
Example #3
0
        public async override Task <(decimal unitPrice, decimal discountAmount, List <Discount> appliedDiscounts)> GetUnitPriceAsync(
            Product product,
            Customer customer,
            ShoppingCartType shoppingCartType,
            int quantity,
            string attributesXml,
            decimal customerEnteredPrice,
            DateTime?rentalStartDate, DateTime?rentalEndDate,
            bool includeDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

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

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

            decimal finalPrice;

            var combination = await _productAttributeParser.FindProductAttributeCombinationAsync(product, attributesXml);

            if (combination?.OverriddenPrice.HasValue ?? false)
            {
                (_, finalPrice, discountAmount, appliedDiscounts) = await _priceCalculationService.GetFinalPriceAsync(product,
                                                                                                                      customer,
                                                                                                                      combination.OverriddenPrice.Value,
                                                                                                                      decimal.Zero,
                                                                                                                      includeDiscounts,
                                                                                                                      quantity,
                                                                                                                      product.IsRental?rentalStartDate : null,
                                                                                                                      product.IsRental?rentalEndDate : null);
            }
            else
            {
                // custom
                // summarize price of all attributes except warranties (warranties processed separately)
                decimal warrantyPrice = decimal.Zero;
                ProductAttributeMapping warrantyPam = await _attributeUtilities.GetWarrantyAttributeMappingAsync(attributesXml);

                //summarize price of all attributes
                var attributesTotalPrice = decimal.Zero;
                var attributeValues      = await _productAttributeParser.ParseProductAttributeValuesAsync(attributesXml);

                // custom - considers warranties
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        if (warrantyPam != null && attributeValue.ProductAttributeMappingId == warrantyPam.Id)
                        {
                            warrantyPrice =
                                await _priceCalculationService.GetProductAttributeValuePriceAdjustmentAsync(
                                    product,
                                    attributeValue,
                                    customer,
                                    product.CustomerEntersPrice?(decimal?)customerEnteredPrice : null
                                    );
                        }
                        else
                        {
                            attributesTotalPrice += await _priceCalculationService.GetProductAttributeValuePriceAdjustmentAsync(
                                product,
                                attributeValue,
                                customer,
                                product.CustomerEntersPrice?(decimal?)customerEnteredPrice : null
                                );
                        }
                    }
                }

                //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 = (await GetShoppingCartAsync(customer, shoppingCartType: shoppingCartType, productId: product.Id))
                              .Sum(x => x.Quantity);

                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }

                    (_, finalPrice, discountAmount, appliedDiscounts) = await _priceCalculationService.GetFinalPriceAsync(product,
                                                                                                                          customer,
                                                                                                                          attributesTotalPrice,
                                                                                                                          includeDiscounts,
                                                                                                                          qty,
                                                                                                                          product.IsRental?rentalStartDate : null,
                                                                                                                          product.IsRental?rentalEndDate : null);

                    finalPrice += warrantyPrice;
                }
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                finalPrice = await _priceCalculationService.RoundPriceAsync(finalPrice);
            }

            return(finalPrice, discountAmount, appliedDiscounts);
        }