/// <summary> /// Attempts to add the coupons discounts to the invoice /// </summary> /// <param name="value"> /// The value. /// </param> /// <returns> /// The <see cref="Attempt"/>. /// </returns> public override Attempt <IInvoice> PerformTask(IInvoice value) { // check if there are any coupon offers if (!this.SalePreparation.OfferCodes.Any()) { return(Attempt <IInvoice> .Succeed(value)); } if (!(this.SalePreparation is IBasketSalePreparation)) { return(Attempt <IInvoice> .Fail(value, new InvalidCastException("SalePreparation object is not IBasketSalePreparation"))); } this._basketSalePreparation = this.SalePreparation as IBasketSalePreparation; foreach (var code in this.SalePreparation.OfferCodes) { var foundCoupon = this.CouponOfferManager.GetByOfferCode(code, this.SalePreparation.Customer); if (!foundCoupon.Success) { continue; } var coupon = foundCoupon.Result; var clone = LineItemExtensions.CreateNewItemCacheLineItemContainer(value.Items.Where(x => x.LineItemType != LineItemType.Tax)); var apply = coupon.TryApply(clone, this.SalePreparation.Customer).AsCouponRedemptionResult(coupon); if (apply.Success) { this.CouponOfferManager.SafeAddCouponAttemptContainer <InvoiceLineItem>(value, apply, true); } } return(Attempt <IInvoice> .Succeed(value)); }
/// <summary> /// Attempts to add the coupons discounts to the invoice /// </summary> /// <param name="value"> /// The value. /// </param> /// <returns> /// The <see cref="Attempt"/>. /// </returns> public override Attempt <IInvoice> PerformTask(IInvoice value) { // check if there are any coupon offers if (!this.CheckoutManager.Offer.OfferCodes.Any()) { return(Attempt <IInvoice> .Succeed(value)); } foreach (var code in this.CheckoutManager.Offer.OfferCodes) { var foundCoupon = this.CouponOfferManager.GetByOfferCode(code, this.CheckoutManager.Context.Customer); if (!foundCoupon.Success) { continue; } var coupon = foundCoupon.Result; var clone = LineItemExtensions.CreateNewItemCacheLineItemContainer(value.Items.Where(x => x.LineItemType != LineItemType.Tax)); var apply = coupon.TryApply(clone, this.CheckoutManager.Context.Customer).AsCouponRedemptionResult(coupon); if (apply.Success) { this.CouponOfferManager.SafeAddCouponAttemptContainer <InvoiceLineItem>(value, apply, true); } } return(Attempt <IInvoice> .Succeed(value)); }
/// <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> /// Attempts to add a coupon offer to the sale. /// </summary> /// <param name="offerCode"> /// The offer code. /// </param> /// <returns> /// The <see cref="ICouponRedemptionResult"/>. /// </returns> public ICouponRedemptionResult RedeemCouponOffer(string offerCode) { var couponAttempt = this.GetCouponAttempt(offerCode); if (!couponAttempt) { return(new CouponRedemptionResult(couponAttempt.Exception)); } var coupon = couponAttempt.Result; var validationItems = this.PrepareInvoice(); var result = TryApplyOffer <ILineItemContainer, ILineItem>(LineItemExtensions.CreateNewItemCacheLineItemContainer(validationItems.Items.Where(x => x.LineItemType != LineItemType.Tax)), offerCode).AsCouponRedemptionResult(coupon); if (!result.Success) { return(result); } // check if there are any previously added coupons and if so revalidate them with the new coupon added. // Use case: First coupon added has the "not usable with other coupons constraint" and then a second coupon is added. // In this case the first coupon needs to be revalidated. If the attempt to apply the coupon again fails, the one currently // being added needs to fail. if (OfferCodes.Any()) { // Now we have to revalidate any existing coupon offers to make sure the newly approved ones will still be valid. var clone = this.CreateNewLineContainer(ItemCache.Items.Where(x => x.LineItemType != LineItemType.Discount)); _couponManager.Value.SafeAddCouponAttemptContainer <ItemCacheLineItem>(clone, result); ICouponRedemptionResult redemption = new CouponRedemptionResult(result.Award, result.Messages); foreach (var oc in OfferCodes) { redemption = DoTryApplyOffer <ILineItemContainer, ILineItem>(clone, oc).AsCouponRedemptionResult(coupon); if (!redemption.Success) { if (redemption.Messages.Any()) { result.AddMessage(redemption.Messages); } result.Exception = redemption.Exception; result.Success = false; break; } _couponManager.Value.SafeAddCouponAttemptContainer <ItemCacheLineItem>(clone, result); } if (!redemption.Success) { return(redemption); } } this.SaveOfferCode(offerCode); return(result); }
/// <summary> /// Creates a new <see cref="ILineItemContainer"/> with filtered items. /// </summary> /// <param name="filteredItems"> /// The line items. /// </param> /// <returns> /// The <see cref="ILineItemContainer"/>. /// </returns> internal ILineItemContainer CreateNewLineContainer(IEnumerable <ILineItem> filteredItems) { return(LineItemExtensions.CreateNewItemCacheLineItemContainer(filteredItems)); }