/// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            var visitor = new MaximumQuantityConstraintVisitor(MaximumQuantity);
            value.Items.Accept(visitor);

            return this.Success(this.CreateNewLineContainer(visitor.ModifiedItems));
        }
        /// <summary>
        /// Tries to apply the discount line item reward
        /// </summary>
        /// <param name="validate">
        /// The <see cref="ILineItemContainer"/> to validate against
        /// </param>
        /// <param name="customer">
        /// The customer.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILinetItem}"/>.
        /// </returns>
        public override Attempt<ILineItem> TryAward(ILineItemContainer validate, ICustomerBase customer)
        {
            var shippingLineItems = validate.ShippingLineItems();
            var audits = shippingLineItems.Select(item =>
                new CouponRewardAdjustmentAudit()
                    {
                        RelatesToSku = item.Sku,
                        Log = new[]
                                  {
                                      new DataModifierLog()
                                          {
                                              PropertyName = "Price",
                                              OriginalValue = item.Price,
                                              ModifiedValue = 0M
                                          }
                                  }
                    }).ToList();

            // Get the item template
            var discountLineItem = CreateTemplateDiscountLineItem(audits);
            var discount = validate.ShippingLineItems().Sum(x => x.TotalPrice);
            discountLineItem.Price = discount;

            return Attempt<ILineItem>.Succeed(discountLineItem);
        }
        /// <summary>
        /// Clones a <see cref="ILineItemContainer"/> as <see cref="IItemCache"/>
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        /// <returns>
        /// The <see cref="IItemCache"/>.
        /// </returns>
        internal static IItemCache CloneItemCache(ILineItemContainer container)
        {
            var clone = new ItemCache(Guid.NewGuid(), ItemCacheType.Backoffice);
            foreach (var item in container.Items)
            {
                clone.Items.Add(item.AsLineItemOf<ItemCacheLineItem>());
            }

            return clone;
        }
        /// <summary>
        /// Tries to apply the discount line item reward
        /// </summary>
        /// <param name="validate">
        /// The <see cref="ILineItemContainer"/> to validate against
        /// </param>
        /// <param name="customer">
        /// The customer.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILinetItem}"/>.
        /// </returns>
        public override Attempt<ILineItem> TryAward(ILineItemContainer validate, ICustomerBase customer)
        {
            // Get the item template
            var discountLineItem = CreateTemplateDiscountLineItem();

            var discount = validate.ShippingLineItems().Sum(x => x.TotalPrice);

            discountLineItem.Price = discount;

            return Attempt<ILineItem>.Succeed(discountLineItem);
        }
        /// <summary>
        /// The try apply.
        /// </summary>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="customer">
        /// The customer.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt"/>.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            if (MerchelloContext.Current != null)
            {
                if (!MerchelloContext.Current.Gateways.Taxation.ProductPricingEnabled) return this.Success(value);
                var vistor = new ExcludeTaxesInProductPricesVisitor();
                value.Items.Accept(vistor);
                return this.Success(value);
            }

            return Attempt<ILineItemContainer>.Fail(new NullReferenceException("MerchelloContext was null"));
        }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            if (customer.IsAnonymous) return Attempt<ILineItemContainer>.Fail(new OfferRedemptionException("Cannot be applied by anonymous customers."));

            if (MerchelloContext.Current != null)
            {
                var offerRedeemedService = ((ServiceContext)MerchelloContext.Current.Services).OfferRedeemedService;
                var offerSettingsKey = this.OfferComponentDefinition.OfferSettingsKey;
                var remptions = offerRedeemedService.GetByOfferSettingsKeyAndCustomerKey(offerSettingsKey, customer.Key);

                return remptions.Any()
                           ? this.Fail(value, "Customer has already redeemed this offer.")
                           : this.Success(value);

            }

            return Attempt<ILineItemContainer>.Fail(new NullReferenceException("MerchelloContext was null"));
        }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            if (MaximumRedemptions == 0) return Attempt<ILineItemContainer>.Succeed(value);

            if (MerchelloContext.Current != null)
            {
                var offerRedeemedService = ((ServiceContext)MerchelloContext.Current.Services).OfferRedeemedService;
                var offerSettingsKey = this.OfferComponentDefinition.OfferSettingsKey;
                var remptionCount = offerRedeemedService.GetOfferRedeemedCount(offerSettingsKey);

                return remptionCount >= MaximumRedemptions
                           ? this.Fail(value, "Redemption count would exceed the maximum number of allowed")
                           : this.Success(value);

            }

            return this.Fail(value, "MerchelloContext was null");
        }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            var visitor = new NumericalValueFilterConstraintVisitor(Quantity, Operator, "quantity");
            value.Items.Accept(visitor);

            return visitor.FilteredLineItems.Any(x => x.LineItemType == LineItemType.Product)
                       ? this.Success(CreateNewLineContainer(visitor.FilteredLineItems))
                       : this.Fail(value, "No items qualify. Resulting collection would be empty.");
        }
Exemple #9
0
 /// <summary>
 /// Adds a line item to the collection
 /// </summary>
 public static void AddItem(this ILineItemContainer container, ILineItem lineItem)
 {
     container.Items.Add(lineItem);
 }
 /// <summary>
 /// Returns a value indicating whether collection contains shippable items.
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <returns>
 /// A value indicating whether collection contains shippable items.
 /// </returns>
 public static bool HasShippableItems(this ILineItemContainer container)
 {
     return(container.Items.Any(x => x.IsShippable()));
 }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            var visitor = new ProductSelectionConstraintVisitor(this.ProductConstraintDataSet);
            value.Items.Accept(visitor);

            return visitor.FilteredItems.Any()
                       ? this.Success(this.CreateNewLineContainer(visitor.FilteredItems))
                       : this.Fail(value, "No products matched the configured filter.");
        }
Exemple #12
0
 /// <summary>
 /// Validates the constraint against the <see cref="ILineItemContainer"/>
 /// </summary>
 /// <param name="value">
 /// The value to object to which the constraint is to be applied.
 /// </param>
 /// <param name="customer">
 /// The <see cref="ICustomerBase"/>.
 /// </param>
 /// <returns>
 /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
 /// </returns>
 public override Attempt <ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
 {
     return(!value.ContainsAnyCoupons()
                ? this.Success(value)
                : this.Fail(value, "One or more coupons have already been added."));
 }
 /// <summary>
 /// Returns a collection of shippable line items
 /// </summary>
 /// <param name="container">The <see cref="ILineItemContainer"/></param>
 /// <returns>A collection of line items that can be shipped</returns>
 public static IEnumerable <ILineItem> ShippableItems(this ILineItemContainer container)
 {
     return(container.Items.Where(x => x.IsShippable()));
 }
 /// <summary>
 /// Gets the tax line items.
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <returns>
 /// The collection of tax line items.
 /// </returns>
 public static IEnumerable <ILineItem> TaxLineItems(this ILineItemContainer container)
 {
     return(container.Items.Where(x => x.LineItemType == LineItemType.Tax));
 }
 /// <summary>
 /// Adds a line item to the collection
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <param name="lineItem">
 /// The line Item.
 /// </param>
 public static void AddItem(this ILineItemContainer container, ILineItem lineItem)
 {
     lineItem.ContainerKey = container.Key;
     container.Items.Add(lineItem);
 }
 /// <summary>
 /// Adds a line item to the collection
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <param name="lineItemType">
 /// The line Item Type.
 /// </param>
 /// <param name="name">
 /// The name.
 /// </param>
 /// <param name="sku">
 /// The sku.
 /// </param>
 /// <param name="quantity">
 /// The quantity.
 /// </param>
 /// <param name="amount">
 /// The amount.
 /// </param>
 public static void AddItem(this ILineItemContainer container, LineItemType lineItemType, string name, string sku, int quantity, decimal amount)
 {
     container.AddItem(lineItemType, name, sku, quantity, amount, new ExtendedDataCollection());
 }
 /// <summary>
 /// Adds a <see cref="IProductVariant"/> line item to the collection
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <param name="productVariant">
 /// The product Variant.
 /// </param>
 /// <param name="quantity">
 /// The quantity.
 /// </param>
 /// <param name="extendedData">
 /// The extended Data.
 /// </param>
 public static void AddItem(this ILineItemContainer container, IProductVariant productVariant, int quantity, ExtendedDataCollection extendedData)
 {
     extendedData.AddProductVariantValues(productVariant);
     container.AddItem(LineItemType.Product, productVariant.Name, productVariant.Sku, quantity, productVariant.Price, extendedData);
 }
        /// <summary>
        /// Adds a <see cref="IProductVariant"/> line item to the collection
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        /// <param name="productVariant">
        /// The product Variant.
        /// </param>
        /// <param name="quantity">
        /// The quantity.
        /// </param>
        public static void AddItem(this ILineItemContainer container, IProductVariant productVariant, int quantity)
        {
            var extendedData = new ExtendedDataCollection();

            container.AddItem(productVariant, quantity, extendedData);
        }
Exemple #19
0
 /// <summary>
 /// Determines whether or not the <see cref="ILineItemContainer"/> contains ANY serialized coupons.
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <returns>
 /// A value indicating whether or not the <see cref="ILineItemContainer"/> contains ANY serialized coupons..
 /// </returns>
 public static bool ContainsAnyCoupons(this ILineItemContainer container)
 {
     return(container.Items.Any(x => x.ContainsCoupon()));
 }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            if (Quantity <= 0) return Attempt<ILineItemContainer>.Succeed(value);

            var total = value.Items.Sum(x => x.Quantity);

            return StringOperatorHelper.Evaluate(Quantity, total, Operator) ?
                this.Success(value) :
                this.Fail(value, "The total quantity of items failed to pass the configured condition.");
        }
        /// <summary>
        /// Tries to apply the discount line item reward
        /// </summary>
        /// <param name="validate">
        /// The <see cref="ILineItemContainer"/> to validate against
        /// </param>
        /// <param name="customer">
        /// The customer.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILinetItem}"/>.
        /// </returns>
        public override Attempt<ILineItem> TryAward(ILineItemContainer validate, ICustomerBase customer)
        {
            if (!IsConfigured) return Attempt<ILineItem>.Fail(new OfferRedemptionException("The coupon reward is not configured."));
            if (MerchelloContext.Current == null) return Attempt<ILineItem>.Fail(new OfferRedemptionException("The MerchelloContext was null"));

            // apply to the entire collection excluding previously added discounts
            var qualifying =
                LineItemExtensions.CreateNewItemCacheLineItemContainer(validate.Items.Where(x => x.LineItemType != LineItemType.Discount));

            var visitor = new CouponDiscountLineItemRewardVisitor(Amount, AdjustmentType);
            qualifying.Items.Accept(visitor);

            var qualifyingTotal = visitor.QualifyingTotal;

            var discount = this.AdjustmentType == Adjustment.Flat
                                    ? this.Amount > qualifyingTotal ? qualifyingTotal : this.Amount
                                    : qualifyingTotal * (this.Amount / 100);

            // Get the item template
            var discountLineItem = CreateTemplateDiscountLineItem(visitor.Audits);
            discountLineItem.ExtendedData.SetValue(Core.Constants.ExtendedDataKeys.CouponAdjustedProductPreTaxTotal, visitor.AdjustedProductPreTaxTotal.ToString(CultureInfo.InvariantCulture));
            discountLineItem.ExtendedData.SetValue(Core.Constants.ExtendedDataKeys.CouponAdjustedProductTaxTotal, visitor.AdjustedTaxTotal.ToString(CultureInfo.InvariantCulture));
            discountLineItem.Price = discount;

            return Attempt<ILineItem>.Succeed(discountLineItem);
        }
Exemple #22
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RedeemCouponEventArgs"/> class.
 /// </summary>
 /// <param name="container">
 /// The line item container (usually the <see cref="IInvoice"/>).
 /// </param>
 /// <param name="lineItem">
 /// The line item.
 /// </param>
 public RedeemCouponEventArgs(ILineItemContainer container, ILineItem lineItem)
 {
     LineItem = lineItem;
     Container = container;
 }
        /// <summary>
        /// Tries to apply the discount line item reward
        /// </summary>
        /// <param name="validate">
        /// The <see cref="ILineItemContainer"/> to validate against
        /// </param>
        /// <param name="customer">
        /// The customer.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILinetItem}"/>.
        /// </returns>
        public override Attempt<ILineItem> TryAward(ILineItemContainer validate, ICustomerBase customer)
        {
            if (!IsConfigured) return Attempt<ILineItem>.Fail(new OfferRedemptionException("The coupon reward is not configured."));

            // Get the item template
            var discountLineItem = CreateTemplateDiscountLineItem();

            // apply to the entire collection excluding previously added discounts
            var qualifyingTotal = validate.Items.Where(x => x.LineItemType != LineItemType.Discount).Sum(x => x.TotalPrice);

            var discount = this.AdjustmentType == Adjustment.Flat
                                    ? this.Amount > qualifyingTotal ? qualifyingTotal : this.Amount
                                    : qualifyingTotal * (this.Amount / 100);

            discountLineItem.Price = discount;

            return Attempt<ILineItem>.Succeed(discountLineItem);
        }
 /// <summary>
 /// Validates the constraint against the <see cref="ILineItemContainer"/>
 /// </summary>
 /// <param name="value">
 /// The value to object to which the constraint is to be applied.
 /// </param>
 /// <param name="customer">
 /// The <see cref="ICustomerBase"/>.
 /// </param>
 /// <returns>
 /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
 /// </returns>
 public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
 {
     return !value.ContainsAnyCoupons()
                ? this.Success(value)
                : this.Fail(value, "One or more coupons have already been added.");
 }
        /// <summary>
        /// Gets a collection of <see cref="IReplaceablePattern"/> for each line item in the <see cref="LineItemCollection"/>
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        /// <param name="currencySymbol">
        /// The currency Symbol.
        /// </param>
        /// <returns>
        /// A collection of replaceable patterns
        /// </returns>
        internal static IEnumerable <IReplaceablePattern> LineItemReplaceablePatterns(this ILineItemContainer container, string currencySymbol)
        {
            var patterns = new List <IReplaceablePattern>();

            var token = container.GetFormatterIterationIdentifier();

            var iterateItems =
                container.Items.Where(
                    x => x.LineItemType == LineItemType.Product || x.LineItemType == LineItemType.Custom).ToArray();

            // TODO localization needed on pricing and datetime
            for (var i = 0; i < iterateItems.Count(); i++)
            {
                var sku        = new ReplaceablePattern(string.Format("{0}.{1}.{2}", token, "Sku", i), string.Format("{0}Item.Sku.{1}{2}", "{{", i, "}}"), iterateItems[i].LineItemType == LineItemType.Shipping ? string.Empty : iterateItems[i].Sku);
                var unitPrice  = new ReplaceablePattern(string.Format("{0}.{1}.{2}", token, "UnitPrice", i), string.Format("{0}Item.UnitPrice.{1}{2}", "{{", i, "}}"), iterateItems[i].Price.FormatAsPrice(currencySymbol));
                var name       = new ReplaceablePattern(string.Format("{0}.{1}.{2}", token, "Name", i), string.Format("{0}Item.Name.{1}{2}", "{{", i, "}}"), iterateItems[i].Name);
                var qty        = new ReplaceablePattern(string.Format("{0}.{1}.{2}", token, "Quantity", i), string.Format("{0}Item.Quantity.{1}{2}", "{{", i, "}}"), iterateItems[i].Quantity.ToString(CultureInfo.InvariantCulture));
                var totalPrice = new ReplaceablePattern(string.Format("{0}.{1}.{2}", token, "TotalPrice", i), string.Format("{0}Item.TotalPrice.{1}{2}", "{{", i, "}}"), iterateItems[i].TotalPrice.FormatAsPrice(currencySymbol));

                patterns.Add(sku);
                patterns.Add(name);
                patterns.Add(unitPrice);
                patterns.Add(qty);
                patterns.Add(totalPrice);
            }

            //var shippingLineItems = container.ShippingLineItems().ToArray();

            //// TODO - needs work once we expose multiple shipments to do an array if multiple destinations are detected
            //if (shippingLineItems.Any())
            //{
            //    var shipment = shippingLineItems.First().ExtendedData.GetShipment<InvoiceLineItem>();
            //    patterns.Add(ReplaceablePattern.GetConfigurationReplaceablePattern("ShipToName", shipment.ToName));

            //}


            return(patterns.Where(x => x != null));
        }
 /// <summary>
 /// The try apply.
 /// </summary>
 /// <param name="value">
 /// The value.
 /// </param>
 /// <param name="customer">
 /// The customer.
 /// </param>
 /// <returns>
 /// The <see cref="Attempt"/>.
 /// </returns>
 public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
 {
     return customer.IsAnonymous ? this.Fail(value, "Customer cannont be anonymous") : this.Success(value);
 }
 /// <summary>
 /// Gets the shipping line items.
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <returns>
 /// The collection of shipping line item.
 /// </returns>
 public static IEnumerable <ILineItem> ShippingLineItems(this ILineItemContainer container)
 {
     return(container.Items.Where(x => x.LineItemType == LineItemType.Shipping));
 }
 /// <summary>
 /// Gets the discount line items.
 /// </summary>
 /// <param name="container">
 /// The container.
 /// </param>
 /// <returns>
 /// The collection of discount line items.
 /// </returns>
 public static IEnumerable <ILineItem> DiscountLineItems(this ILineItemContainer container)
 {
     return(container.Items.Where(x => x.LineItemType == LineItemType.Discount));
 }
 /// <summary>
 /// Validates the constraint against the <see cref="ILineItemContainer"/>
 /// </summary>
 /// <param name="value">
 /// The value to object to which the constraint is to be applied.
 /// </param>
 /// <param name="customer">
 /// The <see cref="ICustomerBase"/>.
 /// </param>
 /// <returns>
 /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
 /// </returns>
 public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
 {
     return Attempt<ILineItemContainer>.Succeed(CreateNewLineContainer(value.Items.Where(x => x.LineItemType != LineItemType.Shipping)));
 }
        /// <summary>
        /// Validates the constraint against the <see cref="ILineItemContainer"/>
        /// </summary>
        /// <param name="value">
        /// The value to object to which the constraint is to be applied.
        /// </param>
        /// <param name="customer">
        /// The <see cref="ICustomerBase"/>.
        /// </param>
        /// <returns>
        /// The <see cref="Attempt{ILineItemContainer}"/> indicating whether or not the constraint can be enforced.
        /// </returns>
        public override Attempt<ILineItemContainer> TryApply(ILineItemContainer value, ICustomerBase customer)
        {
            var visitor = new NumericalValueFilterConstraintVisitor(this.Price, Operator, "price");
            value.Items.Accept(visitor);

            return visitor.FilteredLineItems.Any(x => x.LineItemType == LineItemType.Product)
                       ? this.Success(CreateNewLineContainer(visitor.FilteredLineItems))
                       : this.Fail(value, "No items qualify. Quantity filter removes all items");
        }