/// <summary> /// Gets the discount amount for the specified value /// </summary> /// <param name="discount">Discount</param> /// <param name="amount">Amount</param> /// <returns>The discount amount</returns> public virtual decimal GetDiscountAmount(DiscountForCaching discount, decimal amount) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } //calculate discount amount decimal result; if (discount.UsePercentage) { result = (decimal)((float)amount * (float)discount.DiscountPercentage / 100f); } else { result = discount.DiscountAmount; } //validate maximum discount amount if (discount.UsePercentage && discount.MaximumDiscountAmount.HasValue && result > discount.MaximumDiscountAmount.Value) { result = discount.MaximumDiscountAmount.Value; } if (result < decimal.Zero) { result = decimal.Zero; } return(result); }
/// <summary> /// Validate discount /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Discount validation result</returns> public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException("discount"); } if (customer == null) { throw new ArgumentNullException("customer"); } string[] couponCodesToValidate = customer.ParseAppliedDiscountCouponCodes(); return(ValidateDiscount(discount, customer, couponCodesToValidate)); }
/// <summary> /// Validate discount /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Discount validation result</returns> public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } if (customer == null) { throw new ArgumentNullException(nameof(customer)); } var couponCodesToValidate = _customerService.ParseAppliedDiscountCouponCodes(customer); return(ValidateDiscount(discount, customer, couponCodesToValidate)); }
/// <summary> /// Get category identifiers to which a discount is applied /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Category identifiers</returns> public virtual IList <int> GetAppliedCategoryIds(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } var discountId = discount.Id; var cacheKey = string.Format(NopDiscountDefaults.DiscountCategoryIdsModelCacheKey, discountId, string.Join(",", customer.GetCustomerRoleIds()), _storeContext.CurrentStore.Id); var result = _cacheManager.Get(cacheKey, () => { var ids = new List <int>(); var rootCategoryIds = _discountRepository.Table.Where(x => x.Id == discountId) .SelectMany(x => x.DiscountCategoryMappings.Select(mapping => mapping.CategoryId)) .ToList(); foreach (var categoryId in rootCategoryIds) { if (!ids.Contains(categoryId)) { ids.Add(categoryId); } if (!discount.AppliedToSubCategories) { continue; } //include subcategories foreach (var childCategoryId in _categoryService.GetChildCategoryIds(categoryId, _storeContext.CurrentStore.Id)) { if (!ids.Contains(childCategoryId)) { ids.Add(childCategoryId); } } } return(ids); }); return(result); }
/// <summary> /// Get category identifiers to which a discount is applied /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Category identifiers</returns> public virtual IList <string> GetAppliedCategoryIds(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } var discountId = discount.Id; var cacheKey = string.Format(DiscountEventConsumer.DISCOUNT_CATEGORY_IDS_MODEL_KEY, discountId, string.Join(",", customer.GetCustomerRoleIds()), 0); var result = _cacheManager.Get(cacheKey, () => { var ids = new List <string>(); var rootCategoryIds = _discountRepository.Table.Where(x => x.Id == discountId) .SelectMany(x => x.AppliedToCategories.Select(c => c.CategoryId)) .ToList(); foreach (var categoryId in rootCategoryIds) { if (!ids.Contains(categoryId)) { ids.Add(categoryId); } if (discount.AppliedToSubCategories) { //include subcategories foreach (var childCategoryId in _categoryService .GetAllCategoriesByParentCategoryId(categoryId, false, true) .Select(x => x.CategoryId)) { if (!ids.Contains(childCategoryId)) { ids.Add(childCategoryId); } } } } return(ids); }); return(result); }
/// <summary> /// Get manufacturer identifiers to which a discount is applied /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Manufacturer identifiers</returns> public virtual IList <int> GetAppliedManufacturerIds(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } var discountId = discount.Id; var cacheKey = string.Format(NopDiscountDefaults.DiscountManufacturerIdsModelCacheKey, discountId, string.Join(",", customer.GetCustomerRoleIds()), _storeContext.CurrentStore.Id); var result = _cacheManager.Get(cacheKey, () => { return(_discountRepository.Table.Where(x => x.Id == discountId) .SelectMany(x => x.DiscountManufacturerMappings.Select(mapping => mapping.ManufacturerId)) .ToList()); }); return(result); }
/// <summary> /// Get manufacturer identifiers to which a discount is applied /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Manufacturer identifiers</returns> public virtual IList <int> GetAppliedManufacturerIds(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } var discountId = discount.Id; var cacheKey = string.Format(DiscountEventConsumer.DISCOUNT_MANUFACTURER_IDS_MODEL_KEY, discountId, string.Join(",", customer.GetCustomerRoleIds()), 0); var result = _cacheManager.Get(cacheKey, () => { return(_discountRepository.Table.Where(x => x.Id == discountId) .SelectMany(x => x.AppliedToManufacturers.Select(c => c.Id)) .ToList()); }); return(result); }
/// <summary> /// Get destination identifiers to which a discount is applied /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <returns>Destination identifiers</returns> public virtual IList <int> GetAppliedDestinationIds(DiscountForCaching discount, Customer customer) { if (discount == null) { throw new ArgumentNullException("discount"); } var discountId = discount.Id; var cacheKey = string.Format(DiscountEventConsumer.DISCOUNT_DESTINATION_IDS_MODEL_KEY, discountId, string.Join(",", customer.GetCustomerRoleIds()), _storeContext.CurrentStore.Id); var result = _cacheManager.Get(cacheKey, () => { return(_discountRepository.Table.Where(x => x.Id == discountId) .SelectMany(x => x.AppliedToDestinations.Select(c => c.Id)) .ToList()); }); return(result); }
/// <summary> /// Check whether a list of discounts already contains a certain discount instance /// </summary> /// <param name="discounts">A list of discounts</param> /// <param name="discount">Discount to check</param> /// <returns>Result</returns> public virtual bool ContainsDiscount(IList <DiscountForCaching> discounts, DiscountForCaching discount) { if (discounts == null) { throw new ArgumentNullException(nameof(discounts)); } if (discount == null) { throw new ArgumentNullException(nameof(discount)); } foreach (var dis1 in discounts) { if (discount.Id == dis1.Id) { return(true); } } return(false); }
/// <summary> /// Check whether a list of discounts already contains a certain discount intance /// </summary> /// <param name="discounts">A list of discounts</param> /// <param name="discount">Discount to check</param> /// <returns>Result</returns> public static bool ContainsDiscount(this IList <DiscountForCaching> discounts, DiscountForCaching discount) { if (discounts == null) { throw new ArgumentNullException("discounts"); } if (discount == null) { throw new ArgumentNullException("discount"); } foreach (var dis1 in discounts) { if (discount.Id == dis1.Id) { return(true); } } return(false); }
/// <summary> /// Validate discount /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <param name="couponCodesToValidate">Coupon codes to validate</param> /// <returns>Discount validation result</returns> public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer, string[] couponCodesToValidate) { if (discount == null) { throw new ArgumentNullException(nameof(discount)); } if (customer == null) { throw new ArgumentNullException(nameof(customer)); } //invalid by default var result = new DiscountValidationResult(); //check coupon code if (discount.RequiresCouponCode) { if (string.IsNullOrEmpty(discount.CouponCode)) { return(result); } if (couponCodesToValidate == null) { return(result); } if (!couponCodesToValidate.Any(x => x.Equals(discount.CouponCode, StringComparison.InvariantCultureIgnoreCase))) { return(result); } } //Do not allow discounts applied to order subtotal or total when a customer has gift cards in the cart. //Otherwise, this customer can purchase gift cards with discount and get more than paid ("free money"). if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal || discount.DiscountType == DiscountType.AssignedToOrderTotal) { var cart = customer.ShoppingCartItems .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart) .LimitPerStore(_storeContext.CurrentStore.Id) .ToList(); var hasGiftCards = cart.Any(x => x.Product.IsGiftCard); if (hasGiftCards) { result.Errors = new List <string> { _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedWithGiftCards") }; return(result); } } //check date range var now = DateTime.UtcNow; if (discount.StartDateUtc.HasValue) { var startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc); if (startDate.CompareTo(now) > 0) { result.Errors = new List <string> { _localizationService.GetResource("ShoppingCart.Discount.NotStartedYet") }; return(result); } } if (discount.EndDateUtc.HasValue) { var endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc); if (endDate.CompareTo(now) < 0) { result.Errors = new List <string> { _localizationService.GetResource("ShoppingCart.Discount.Expired") }; return(result); } } //discount limitation switch (discount.DiscountLimitation) { case DiscountLimitationType.NTimesOnly: { var usedTimes = GetAllDiscountUsageHistory(discount.Id, null, null, 0, 1).TotalCount; if (usedTimes >= discount.LimitationTimes) { return(result); } } break; case DiscountLimitationType.NTimesPerCustomer: { if (customer.IsRegistered()) { var usedTimes = GetAllDiscountUsageHistory(discount.Id, customer.Id, null, 0, 1).TotalCount; if (usedTimes >= discount.LimitationTimes) { result.Errors = new List <string> { _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedAnymore") }; return(result); } } } break; case DiscountLimitationType.Unlimited: default: break; } //discount requirements var key = string.Format(NopDiscountDefaults.DiscountRequirementModelCacheKey, discount.Id); var requirementsForCaching = _cacheManager.Get(key, () => { var requirements = GetAllDiscountRequirements(discount.Id, true); return(GetReqirementsForCaching(requirements)); }); //get top-level group var topLevelGroup = requirementsForCaching.FirstOrDefault(); if (topLevelGroup == null || (topLevelGroup.IsGroup && !topLevelGroup.ChildRequirements.Any()) || !topLevelGroup.InteractionType.HasValue) { //there are no requirements, so discount is valid result.IsValid = true; return(result); } //requirements exist, let's check them var errors = new List <string>(); result.IsValid = GetValidationResult(requirementsForCaching, topLevelGroup.InteractionType.Value, customer, errors); //set errors if result is not valid if (!result.IsValid) { result.Errors = errors; } return(result); }
/// <summary> /// Validate discount /// </summary> /// <param name="discount">Discount</param> /// <param name="customer">Customer</param> /// <param name="couponCodesToValidate">Coupon codes to validate</param> /// <returns>Discount validation result</returns> public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer, string[] couponCodesToValidate) { if (discount == null) { throw new ArgumentNullException("discount"); } if (customer == null) { throw new ArgumentNullException("customer"); } //invalid by default var result = new DiscountValidationResult(); //check coupon code if (discount.RequiresCouponCode) { if (String.IsNullOrEmpty(discount.CouponCode)) { return(result); } if (couponCodesToValidate == null) { return(result); } if (!couponCodesToValidate.Any(x => x.Equals(discount.CouponCode, StringComparison.InvariantCultureIgnoreCase))) { return(result); } } //Do not allow discounts applied to order subtotal or total when a customer has gift cards in the cart. //Otherwise, this customer can purchase gift cards with discount and get more than paid ("free money"). if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal || discount.DiscountType == DiscountType.AssignedToOrderTotal) { var cart = customer.ShoppingCartItems .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart) .LimitPerStore(_storeContext.CurrentStore.Id) .ToList(); var hasGiftCards = cart.Any(x => x.Product.IsGiftCard); if (hasGiftCards) { result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedWithGiftCards"); return(result); } } //check date range DateTime now = DateTime.UtcNow; if (discount.StartDateUtc.HasValue) { DateTime startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc); if (startDate.CompareTo(now) > 0) { result.UserError = _localizationService.GetResource("ShoppingCart.Discount.NotStartedYet"); return(result); } } if (discount.EndDateUtc.HasValue) { DateTime endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc); if (endDate.CompareTo(now) < 0) { result.UserError = _localizationService.GetResource("ShoppingCart.Discount.Expired"); return(result); } } //discount limitation switch (discount.DiscountLimitation) { case DiscountLimitationType.NTimesOnly: { var usedTimes = GetAllDiscountUsageHistory(discount.Id, null, null, 0, 1).TotalCount; if (usedTimes >= discount.LimitationTimes) { return(result); } } break; case DiscountLimitationType.NTimesPerCustomer: { if (customer.IsRegistered()) { var usedTimes = GetAllDiscountUsageHistory(discount.Id, customer.Id, null, 0, 1).TotalCount; if (usedTimes >= discount.LimitationTimes) { result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedAnymore"); return(result); } } } break; case DiscountLimitationType.Unlimited: default: break; } //discount requirements string key = string.Format(DiscountEventConsumer.DISCOUNT_REQUIREMENT_MODEL_KEY, discount.Id); var requirements = _cacheManager.Get(key, () => { var cachedRequirements = new List <DiscountRequirementForCaching>(); foreach (var dr in GetAllDiscountRequirements(discount.Id)) { cachedRequirements.Add(new DiscountRequirementForCaching { Id = dr.Id, SystemName = dr.DiscountRequirementRuleSystemName }); } return(cachedRequirements); }); foreach (var req in requirements) { //load a plugin var requirementRulePlugin = LoadDiscountRequirementRuleBySystemName(req.SystemName); if (requirementRulePlugin == null) { continue; } if (!_pluginFinder.AuthorizedForUser(requirementRulePlugin.PluginDescriptor, customer)) { continue; } if (!_pluginFinder.AuthenticateStore(requirementRulePlugin.PluginDescriptor, _storeContext.CurrentStore.Id)) { continue; } var ruleRequest = new DiscountRequirementValidationRequest { DiscountRequirementId = req.Id, Customer = customer, Store = _storeContext.CurrentStore }; var ruleResult = requirementRulePlugin.CheckRequirement(ruleRequest); if (!ruleResult.IsValid) { result.UserError = ruleResult.UserError; return(result); } } result.IsValid = true; return(result); }