public void Can_limit_only_relative_rewards(int amount, int maxLimit, decimal expected, AmountType type) { var currency = new Currency(new Language("en-US"), "USD (840)"); var money = new Money(100m, currency); //Arrange var reward = new PromotionReward() { Amount = amount, AmountType = type, MaxLimit = maxLimit, Promotion = new Promotion() { Id = "id", Description = "" } }; //Act var discount = new Discount(); discount = reward.ToDiscountModel(money); //Assert var expectedAmount = new Money(expected, currency); Assert.Equal(discount.Amount, expectedAmount); }
public static PromotionReward ToPromotionReward(this marketingDto.PromotionReward rewardDto, Currency currency) { var result = new PromotionReward { CategoryId = rewardDto.CategoryId, Coupon = rewardDto.Coupon, Description = rewardDto.Description, IsValid = rewardDto.IsValid ?? false, LineItemId = rewardDto.LineItemId, MeasureUnit = rewardDto.MeasureUnit, ProductId = rewardDto.ProductId, PromotionId = rewardDto.PromotionId, Quantity = rewardDto.Quantity ?? 0, MaxLimit = (decimal)(rewardDto.MaxLimit ?? 0), Amount = (decimal)(rewardDto.Amount ?? 0), AmountType = EnumUtility.SafeParse(rewardDto.AmountType, AmountType.Absolute), CouponAmount = new Money(rewardDto.CouponAmount ?? 0, currency), CouponMinOrderAmount = new Money(rewardDto.CouponMinOrderAmount ?? 0, currency), Promotion = rewardDto.Promotion.ToPromotion(), RewardType = EnumUtility.SafeParse(rewardDto.RewardType, PromotionRewardType.CatalogItemAmountReward), ShippingMethodCode = rewardDto.ShippingMethod, ConditionalProductId = rewardDto.ConditionalProductId, ForNthQuantity = rewardDto.ForNthQuantity, InEveryNthQuantity = rewardDto.InEveryNthQuantity, }; return(result); }
private void AddDiscountToEntity(StorageEntity entity, PromotionReward reward, decimal discountAmount) { var orderForm = entity as OrderForm; var lineItem = entity as LineItem; var shipment = entity as Shipment; if (orderForm != null && reward is CartSubtotalReward) { var discount = orderForm.Discounts.FirstOrDefault(x => x.PromotionId == reward.PromotionId); if (discount == null) { discount = new OrderFormDiscount { PromotionId = reward.PromotionId, DiscountName = reward.Promotion.Name, DisplayMessage = reward.Promotion.Description, OrderFormId = orderForm.OrderFormId, DiscountCode = reward.Promotion.Coupon != null ? reward.Promotion.Coupon.Code : null }; orderForm.Discounts.Add(discount); } discount.DiscountAmount += discountAmount; } else if (lineItem != null && reward is CatalogItemReward) { var discount = lineItem.Discounts.FirstOrDefault(x => x.PromotionId == reward.PromotionId); if (discount == null) { discount = new LineItemDiscount { PromotionId = reward.PromotionId, DiscountName = reward.Promotion.Name, DisplayMessage = reward.Promotion.Description, LineItemId = lineItem.LineItemId, DiscountCode = reward.Promotion.Coupon != null ? reward.Promotion.Coupon.Code : null }; lineItem.Discounts.Add(discount); } discount.DiscountAmount += discountAmount; } else if (shipment != null && reward is ShipmentReward) { var discount = shipment.Discounts.FirstOrDefault(x => x.PromotionId == reward.PromotionId); if (discount == null) { discount = new ShipmentDiscount { PromotionId = reward.PromotionId, DiscountName = reward.Promotion.Name, DisplayMessage = reward.Promotion.Description, ShipmentId = shipment.ShipmentId, DiscountCode = reward.Promotion.Coupon != null ? reward.Promotion.Coupon.Code : null }; shipment.Discounts.Add(discount); } discount.DiscountAmount += discountAmount; } }
/// <summary> /// Adds the promotion item record. /// </summary> /// <param name="reward">The reward.</param> /// <param name="entriesCollection">The entries collection.</param> /// <returns></returns> public void AddPromotionItemRecord(PromotionReward reward, params PromotionEntriesSet[] entrySetsCollection) { foreach (PromotionEntriesSet entrySet in entrySetsCollection) { PromotionItemRecord record = new PromotionItemRecord(this.PromotionContext.TargetEntriesSet, entrySet, reward); record.PromotionItem = PromotionContext.CurrentPromotion; PromotionContext.PromotionResult.PromotionRecords.Add(record); } }
public PromotionReward[] GetRewards() { var retVal = new PromotionReward[] { }; if (Children != null) { retVal = Children.OfType <IRewardExpression>().SelectMany(x => x.GetRewards()).ToArray(); } return(retVal); }
public static PromotionReward ToWebModel(this VirtoCommerceMarketingModuleWebModelPromotionReward serviceModel, Currency currency) { var webModel = new PromotionReward(); webModel.InjectFrom<NullableAndEnumValueInjecter>(serviceModel); webModel.Amount = new Money(serviceModel.Amount ?? 0, currency.Code); webModel.AmountType = EnumUtility.SafeParse(serviceModel.AmountType, AmountType.Absolute); webModel.CouponAmount = new Money(serviceModel.CouponAmount ?? 0, currency.Code); webModel.CouponMinOrderAmount = new Money(serviceModel.CouponMinOrderAmount ?? 0, currency.Code); webModel.Promotion = serviceModel.Promotion.ToWebModel(); webModel.RewardType = EnumUtility.SafeParse(serviceModel.RewardType, PromotionRewardType.CatalogItemAmountReward); return webModel; }
public static PromotionReward ToWebModel(this MarketingModule.Client.Model.PromotionReward serviceModel, Currency currency) { var webModel = new PromotionReward(); webModel.InjectFrom <NullableAndEnumValueInjecter>(serviceModel); webModel.Amount = (decimal)(serviceModel.Amount ?? 0); webModel.AmountType = EnumUtility.SafeParse(serviceModel.AmountType, AmountType.Absolute); webModel.CouponAmount = new Money(serviceModel.CouponAmount ?? 0, currency); webModel.CouponMinOrderAmount = new Money(serviceModel.CouponMinOrderAmount ?? 0, currency); webModel.Promotion = serviceModel.Promotion.ToWebModel(); webModel.RewardType = EnumUtility.SafeParse(serviceModel.RewardType, PromotionRewardType.CatalogItemAmountReward); webModel.ShippingMethodCode = serviceModel.ShippingMethod; return(webModel); }
/// <summary> /// Gets the discount amount for one entry only. /// </summary> /// <param name="record">The record.</param> /// <param name="reward">The reward.</param> /// <returns></returns> private static decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward) { decimal discountAmount = 0; if (reward.RewardType == PromotionRewardType.EachAffectedEntry || reward.RewardType == PromotionRewardType.AllAffectedEntries) { if (reward.AmountType == PromotionRewardAmountType.Percentage) { discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100; } else // need to split discount between all items { discountAmount += reward.AmountOff; // since we assume only one entry in affected items } } return(Math.Round(discountAmount, 2)); }
public void TestToDiscountModel() { //Arrange var samplePromotion = new Promotion { Id = "PromotionId", Description = "Description" }; var promotionReward = new PromotionReward { Amount = 10m, AmountType = AmountType.Relative, Quantity = 1, IsValid = true, Promotion = samplePromotion }; var currency = new Currency(Language.InvariantLanguage, "USD"); //Act var discount = promotionReward.ToDiscountModel(new Money(4.6m, currency), 1); //Assert Assert.Equal(0.46m, discount.Amount.Amount); }
private decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward) { decimal discountAmount = 0; if (reward.RewardType != PromotionRewardType.EachAffectedEntry && reward.RewardType != PromotionRewardType.AllAffectedEntries) { return(Math.Round(discountAmount, 2)); } if (reward.AmountType == PromotionRewardAmountType.Percentage) { discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100; } else { discountAmount += reward.AmountOff; } return(Math.Round(discountAmount, 2)); }
public static Discount ToDiscountWebModel(this PromotionReward reward, decimal amount, int quantity, Currency currency) { var discount = new Discount(); decimal absoluteDiscountAmount = 0; if (reward.AmountType == AmountType.Absolute) { absoluteDiscountAmount = reward.Amount.Amount * quantity; } if (reward.AmountType == AmountType.Relative) { absoluteDiscountAmount = (amount * quantity * reward.Amount.Amount) / 100; } discount.Amount = new Money(absoluteDiscountAmount, currency.Code); discount.Description = reward.Promotion.Description; discount.PromotionId = reward.Promotion.Id; discount.Type = reward.RewardType; return discount; }
public virtual PromotionReward ToPromotionReward(marketingDto.PromotionReward serviceModel, Currency currency) { var result = new PromotionReward(); result.CategoryId = serviceModel.CategoryId; result.Coupon = serviceModel.Coupon; result.Description = serviceModel.Description; result.IsValid = serviceModel.IsValid ?? false; result.LineItemId = serviceModel.LineItemId; result.MeasureUnit = serviceModel.MeasureUnit; result.ProductId = serviceModel.ProductId; result.PromotionId = serviceModel.PromotionId; result.Quantity = serviceModel.Quantity ?? 0; result.Amount = (decimal)(serviceModel.Amount ?? 0); result.AmountType = EnumUtility.SafeParse(serviceModel.AmountType, AmountType.Absolute); result.CouponAmount = new Money(serviceModel.CouponAmount ?? 0, currency); result.CouponMinOrderAmount = new Money(serviceModel.CouponMinOrderAmount ?? 0, currency); result.Promotion = serviceModel.Promotion.ToWebModel(); result.RewardType = EnumUtility.SafeParse(serviceModel.RewardType, PromotionRewardType.CatalogItemAmountReward); result.ShippingMethodCode = serviceModel.ShippingMethod; return(result); }
protected virtual void EvaluateReward(PromotionEvaluationContext promoContext, bool couponIsValid, PromotionReward reward) { reward.Promotion = this; reward.IsValid = couponIsValid && (DynamicExpression?.IsSatisfiedBy(promoContext) ?? false); //Set productId for catalog item reward if (reward is CatalogItemAmountReward catalogItemReward && catalogItemReward.ProductId == null) { catalogItemReward.ProductId = promoContext.PromoEntry.ProductId; } }
private decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward) { decimal discountAmount = 0; if (reward.RewardType != PromotionRewardType.EachAffectedEntry && reward.RewardType != PromotionRewardType.AllAffectedEntries) { return Math.Round(discountAmount, 2); } if (reward.AmountType == PromotionRewardAmountType.Percentage) { discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100; } else { discountAmount += reward.AmountOff; } return Math.Round(discountAmount, 2); }
protected virtual void EvaluateReward(PromotionEvaluationContext promoContext, bool couponIsValid, PromotionReward reward) { reward.Promotion = this; reward.IsValid = couponIsValid && Condition(promoContext); //Set productId for catalog item reward if (reward is CatalogItemAmountReward catalogItemReward && catalogItemReward.ProductId == null) { catalogItemReward.ProductId = promoContext.PromoEntry.ProductId; } }
/// <summary> /// Evaluates the promotions. /// </summary> /// <param name="context">The context.</param> /// <param name="promotions">The promotions.</param> /// <param name="filter">The filter.</param> /// <returns>Collection of promotions that were applied. Look inside PromotionContext for actual rewards and for items /// that have been affected by these promotions.</returns> public PromotionItemCollection EvaluatePromotions(PromotionContext context, PromotionItemCollection promotions, PromotionFilter filter) { // Start checking discounts List <int> rowIndexes = new List <int>(); // Retrieve all the coupons customer entered List <string> coupons = context.Coupons; // Retrieve customer segments, it should be initialized beforehand List <int> segments = context.Segments; // Retrieve customer id, it should be initialized beforehand Guid customerId = context.CustomerId; foreach (PromotionItem item in promotions) { // Set currently executed promotion context.CurrentPromotion = item; // If discount is global and other discount has been applied already, skip it if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel) && rowIndexes.Count != 0) { continue; } // Check if it belongs to a group specified if (!String.IsNullOrEmpty(context.TargetGroup) && !context.TargetGroup.Equals(item.DataRow.PromotionGroup, StringComparison.OrdinalIgnoreCase)) { continue; } // Check group exclusivity if (context.ExclusiveGroups.Contains(item.DataRow.PromotionGroup)) { continue; } // Check limits here int currentOrderPromotionCount = context.PromotionResult.GetCount(item.DataRow.PromotionId); // Start with per order limit if (item.DataRow.PerOrderLimit > 0 && currentOrderPromotionCount >= item.DataRow.PerOrderLimit) { continue; } // Check application limit limit, only check when limit is set if (item.DataRow.ApplicationLimit > 0 && item.TotalUsedCount - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.ApplicationLimit) { continue; } // Check customer limit, only check when limit is set and customer id is set if ((item.DataRow.CustomerLimit > 0 && customerId == Guid.Empty) || item.DataRow.CustomerLimit > 0 && item.GetCustomerUsageCount(customerId) - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.CustomerLimit) { continue; } // First do simply checks that will take little time and save us from wasting processor time // ----------------------------------------------------------------------------------------- if (!filter.IncludeInactive) { // Skip if start date is past now if (!item.Campaign.IsActive) { continue; } if (item.Campaign.StartDate > FrameworkContext.Current.CurrentDateTime) { continue; } // Skip if end date is in the past if (item.Campaign.EndDate < FrameworkContext.Current.CurrentDateTime) { continue; } // Skip if start date is past now if (item.DataRow.StartDate > FrameworkContext.Current.CurrentDateTime) { continue; } // Skip if end date is in the past if (item.DataRow.EndDate < FrameworkContext.Current.CurrentDateTime) { continue; } // Check promotion status if (!item.DataRow.Status.Equals(PromotionStatus.Active)) { continue; } } if (!filter.IncludeCoupons) { // Check coupons string couponCode = item.DataRow.CouponCode; if (!String.IsNullOrEmpty(couponCode)) { if (coupons == null) { continue; } bool foundCoupon = false; foreach (string coupon in coupons) { if (couponCode.Equals(coupon, StringComparison.OrdinalIgnoreCase)) { foundCoupon = true; } } if (!foundCoupon) { continue; } } } // Check catalog / node / entry filtering if (context.TargetEntriesSet.Entries.Count > 0) { bool isValid = true; foreach (PromotionEntry entry in context.TargetEntriesSet.Entries) { string catalogEntryId = entry.CatalogEntryCode; string catalogNodeId = entry.CatalogNodeCode; string catalogName = entry.CatalogName; if (!String.IsNullOrEmpty(catalogEntryId) || !String.IsNullOrEmpty(catalogNodeId) || !String.IsNullOrEmpty(catalogName)) { PromotionDto.PromotionConditionRow[] conditions = item.DataRow.GetPromotionConditionRows(); if (conditions != null && conditions.Length > 0) { foreach (PromotionDto.PromotionConditionRow condition in conditions) { if (!String.IsNullOrEmpty(catalogEntryId) && !condition.IsCatalogEntryIdNull() && !condition.CatalogEntryId.Equals(catalogEntryId)) { isValid = false; break; } else if (!String.IsNullOrEmpty(catalogNodeId) && !condition.IsCatalogNodeIdNull() && !condition.CatalogNodeId.Equals(catalogNodeId)) { isValid = false; break; } else if (!String.IsNullOrEmpty(catalogName) && !condition.IsCatalogNameNull() && !condition.CatalogName.Equals(catalogName)) { isValid = false; break; } } if (!isValid) { continue; } } } } if (!isValid) { continue; } } // Start doing more expensive checks here // ----------------------------------------------------------------------------------------- if (!filter.IgnoreSegments) { // Check customer segments, customer should belong to a segment for promotion to apply CampaignDto.CampaignSegmentRow[] segmentRows = item.Campaign.GetCampaignSegmentRows(); // if there are no segments defined assume it applies to everyone if (segmentRows != null && segmentRows.Length > 0) { // customer is not within any segment, so promotion does not apply if (segments == null || segments.Count == 0) { continue; } // start checking segments bool apply = false; foreach (CampaignDto.CampaignSegmentRow row in segmentRows) { if (segments.Contains(row.SegmentId)) { // mark promotion as apply and leave loop apply = true; break; } } // if does not apply continue with a next promotion if (!apply) { continue; } } } if (!filter.IgnoreConditions) { // Validate expressions if (item.Expressions.Count > 0) { bool isValid = true; foreach (ExpressionDto.ExpressionRow expression in item.Expressions) { if (!String.IsNullOrEmpty(expression.ExpressionXml)) { ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context); if (!result.IsValid) { isValid = false; break; } } } if (!isValid) { continue; } } } else { // Create Award manually based on default settings PromotionReward reward = new PromotionReward(PromotionRewardType.EachAffectedEntry, item.DataRow.OfferAmount, item.DataRow.OfferType == 0 ? PromotionRewardAmountType.Percentage : PromotionRewardAmountType.Value); PromotionItemRecord record = new PromotionItemRecord(context.TargetEntriesSet, context.TargetEntriesSet, reward); record.PromotionItem = context.CurrentPromotion; context.PromotionResult.PromotionRecords.Add(record); } if (!filter.IgnorePolicy) { // Validate store policies if (item.PolicyExpressions.Count > 0) { bool isValid = true; foreach (ExpressionDto.ExpressionRow expression in item.PolicyExpressions) { if (!String.IsNullOrEmpty(expression.ExpressionXml)) { ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context); if (!result.IsValid) { isValid = false; break; } } } if (!isValid) { // Invalidates all records added during this evaluation sequence context.RejectRecords(); continue; } } } // Commits all records added during this evaluation sequence context.CommitRecords(); // Apply item rowIndexes.Add(item.RowIndex); // Add item to a group if it is applied if (item.DataRow.ExclusivityType.Equals(ExclusionType.GroupLevel)) { context.ExclusiveGroups.Add(item.DataRow.PromotionGroup); } // Finish processing if global level item has been added if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel)) { break; } } // Assign curren promotion to null context.CurrentPromotion = null; return(new PromotionItemCollection(promotions, rowIndexes.ToArray())); }