|
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
|
|
using EPiServer.Commerce.Extensions; |
|
using EPiServer.Commerce.Marketing; |
|
using EPiServer.Commerce.Marketing.Extensions; |
|
using EPiServer.Commerce.Order; |
|
using EPiServer.Commerce.Validation; |
|
using EPiServer.Framework.Localization; |
|
using EPiServer.ServiceLocation; |
|
|
|
/// <summary> |
|
/// The processor responsible for evaluating if a promotion of type <see cref="T:BuyProductGetGiftItems" /> should |
|
/// apply a reward to an order group. |
|
/// </summary> |
|
[ServiceConfiguration(Lifecycle = ServiceInstanceScope.Singleton)] |
|
public class BuyProductGetGiftItemsProcessor : EntryPromotionProcessorBase<BuyProductGetGiftItems> |
|
{ |
|
/// <summary> |
|
/// The fulfillment evaluator |
|
/// </summary> |
|
private readonly FulfillmentEvaluator fulfillmentEvaluator; |
|
|
|
/// <summary> |
|
/// The gift item factory |
|
/// </summary> |
|
private readonly GiftItemFactory giftItemFactory; |
|
|
|
/// <summary> |
|
/// The localization service |
|
/// </summary> |
|
private readonly LocalizationService localizationService; |
|
|
|
/// <summary> |
|
/// The target evaluator |
|
/// </summary> |
|
private readonly CollectionTargetEvaluator targetEvaluator; |
|
|
|
/// <summary> |
|
/// Initializes a new instance of the <see cref="BuyProductGetGiftItemsProcessor" /> class. |
|
/// </summary> |
|
/// <param name="targetEvaluator">The target evaluator.</param> |
|
/// <param name="fulfillmentEvaluator">The service that is used to evaluate the fulfillment status of the promotion.</param> |
|
/// <param name="giftItemFactory">The service that is used to get applicable gift items.</param> |
|
/// <param name="localizationService">Service to handle localization of text strings.</param> |
|
public BuyProductGetGiftItemsProcessor( |
|
CollectionTargetEvaluator targetEvaluator, |
|
FulfillmentEvaluator fulfillmentEvaluator, |
|
GiftItemFactory giftItemFactory, |
|
LocalizationService localizationService) |
|
{ |
|
ParameterValidator.ThrowIfNull(() => targetEvaluator, targetEvaluator); |
|
ParameterValidator.ThrowIfNull(() => fulfillmentEvaluator, fulfillmentEvaluator); |
|
ParameterValidator.ThrowIfNull(() => giftItemFactory, giftItemFactory); |
|
ParameterValidator.ThrowIfNull(() => localizationService, localizationService); |
|
|
|
this.targetEvaluator = targetEvaluator; |
|
this.fulfillmentEvaluator = fulfillmentEvaluator; |
|
this.giftItemFactory = giftItemFactory; |
|
this.localizationService = localizationService; |
|
} |
|
|
|
/// <summary> |
|
/// Verify that the current promotion can potentially be fulfilled |
|
/// </summary> |
|
/// <param name="promotionData">The promotion to evaluate.</param> |
|
/// <param name="context">The context for the promotion processor evaluation.</param> |
|
/// <returns><c>true</c> if the current promotion can potentially be fulfilled; otherwise, <c>false</c>.</returns> |
|
/// <remarks>This method is intended to be a very quick pre-check to avoid doing more expensive operations. |
|
/// Used to verify basic things, for example a Buy-3-pay-for-2 promotion needs at least three items in the cart. |
|
/// If we have less than three we can skip further processing.</remarks> |
|
/// <exception cref="ArgumentNullException">Line or discount items is null.</exception> |
|
protected override bool CanBeFulfilled(BuyProductGetGiftItems promotionData, PromotionProcessorContext context) |
|
{ |
|
IEnumerable<ILineItem> lineItems = this.GetLineItems(context.OrderForm); |
|
|
|
if (lineItems.Any() |
|
&& (promotionData?.GiftItems != null && promotionData.GiftItems.Any())) |
|
{ |
|
return promotionData.GiftItems.Any(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Evaluates a promotion against an order form. Implementations should use context.OrderForm for evaluations. |
|
/// </summary> |
|
/// <param name="promotionData">The promotion to evaluate.</param> |
|
/// <param name="context">The context for the promotion processor evaluation.</param> |
|
/// <returns>A <see cref="T:EPiServer.Commerce.Marketing.RewardDescription" /> telling whether the promotion was fulfilled, |
|
/// which items the promotion was applied to and to which amount.</returns> |
|
/// <exception cref="ArgumentNullException">Applicable codes is null.</exception> |
|
/// <exception cref="OverflowException">The sum for the quantities is larger than <see cref="F:System.Decimal.MaxValue" />.</exception> |
|
protected override RewardDescription Evaluate( |
|
BuyProductGetGiftItems promotionData, |
|
PromotionProcessorContext context) |
|
{ |
|
FulfillmentStatus fulfillmentStatus = promotionData.Condition.GetFulfillmentStatus( |
|
context.OrderForm, |
|
this.targetEvaluator, |
|
this.fulfillmentEvaluator); |
|
|
|
if (!fulfillmentStatus.HasFlag(FulfillmentStatus.Fulfilled)) |
|
{ |
|
return this.NotFulfilledRewardDescription(promotionData, context, fulfillmentStatus); |
|
} |
|
|
|
IEnumerable<ILineItem> lineItems = this.GetLineItems(context.OrderForm); |
|
|
|
IList<string> applicableCodes = this.targetEvaluator.GetApplicableCodes( |
|
lineItems, |
|
promotionData.Condition.Items, |
|
true); |
|
|
|
if (!applicableCodes.Any()) |
|
{ |
|
return this.NotFulfilledRewardDescription(promotionData, context, FulfillmentStatus.NotFulfilled); |
|
} |
|
|
|
IEnumerable<RedemptionDescription> redemptions = this.GetRedemptions( |
|
promotionData, |
|
context, |
|
applicableCodes); |
|
|
|
return RewardDescription.CreateGiftItemsReward( |
|
fulfillmentStatus, |
|
redemptions, |
|
promotionData, |
|
fulfillmentStatus.GetRewardDescriptionText(this.localizationService)); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the items for a promotion. |
|
/// </summary> |
|
/// <param name="promotionData">The promotion data to get items for.</param> |
|
/// <returns>The promotion condition and reward items.</returns> |
|
protected override PromotionItems GetPromotionItems(BuyProductGetGiftItems promotionData) |
|
{ |
|
return new PromotionItems( |
|
promotionData, |
|
new CatalogItemSelection(null, CatalogItemSelectionType.All, true), |
|
new CatalogItemSelection(promotionData.GiftItems, CatalogItemSelectionType.Specific, false)); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the redemptions. |
|
/// </summary> |
|
/// <param name="promotionData">The promotion data.</param> |
|
/// <param name="context">The context.</param> |
|
/// <param name="applicableCodes">The applicable codes.</param> |
|
/// <returns>A list of <see cref="RedemptionDescription"/>.</returns> |
|
/// <exception cref="ArgumentNullException">Line items or applicable codes is null.</exception> |
|
/// <exception cref="OverflowException">The sum for the quantities is larger than <see cref="F:System.Decimal.MaxValue" />.</exception> |
|
protected IEnumerable<RedemptionDescription> GetRedemptions( |
|
BuyProductGetGiftItems promotionData, |
|
PromotionProcessorContext context, |
|
IEnumerable<string> applicableCodes) |
|
{ |
|
decimal quantity = |
|
this.GetLineItems(context.OrderForm) |
|
.Where(li => applicableCodes.Contains(li.Code)) |
|
.Sum(li => li.Quantity); |
|
|
|
if (quantity < promotionData.Condition.RequiredQuantity) |
|
{ |
|
return Enumerable.Empty<RedemptionDescription>(); |
|
} |
|
|
|
AffectedEntries giftItems = this.giftItemFactory.CreateGiftItems(promotionData.GiftItems, context); |
|
|
|
return giftItems == null ? Enumerable.Empty<RedemptionDescription>() : new[] { this.CreateRedemptionDescription(giftItems) }; |
|
} |
|
|
|
/// <summary> |
|
/// Not fulfilled reward description. Will be returned when CanBeFulfilled is false. |
|
/// </summary> |
|
/// <param name="promotionData">The promotion that was evaluated.</param> |
|
/// <param name="context">The context for the promotion processor evaluation.</param> |
|
/// <param name="fulfillmentStatus">The fulfillment level of the promotion.</param> |
|
/// <returns>A <see cref="T:EPiServer.Commerce.Marketing.RewardDescription" /> for the not fulfilled promotion.</returns> |
|
protected override RewardDescription NotFulfilledRewardDescription( |
|
BuyProductGetGiftItems promotionData, |
|
PromotionProcessorContext context, |
|
FulfillmentStatus fulfillmentStatus) |
|
{ |
|
return RewardDescription.CreateGiftItemsReward( |
|
fulfillmentStatus, |
|
Enumerable.Empty<RedemptionDescription>(), |
|
promotionData, |
|
FulfillmentStatus.NotFulfilled.GetRewardDescriptionText(this.localizationService)); |
|
} |
@JoelYourstone commented on Jun 29, 2017, 8:42 AM GMT+2:
Exactly, I added a new property to my GiftWithPurchasePromotion of type
IList<Money>
(renders amount fields per market connected to the campaign automatically). Then just checked for it in my Evaluate and update the fulfillmentstatus.