/// <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."); }
/// <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."); }
/// <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); }
/// <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); }
/// <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"); }