Hello,
Perhaps a noob question but we are just getting started with Scripts.
We have applied the script for ‘bulk discounts’:
-
2 items get 10%
-
3 items 12.5%
-
4+ items 15%
However, I have 2 main issues:
- Customers can now combine the bulk discounts with the other codes e.g. WELCOME10
- I only want discounts to apply to single-quantity orders and to display the message 'This code is only valid with single-item orders
- During Sale periods i want our Sale discount code to override the volume discounts so they can use SALE20 and get 20% off only when ordering any quantity
Any help would be great
Here is the script for the bulk discounts
================================ Customizable Settings ================================
================================================================
Tiered Product Discount by Quantity
If the total quantity of matching items is greater than (or
equal to) an entered threshold, the associated discount is
applied to each matching item.
- ‘product_selector_match_type’ determines whether we look for
products that do or don’t match the entered selectors. Can
be:
- ‘:include’ to check if the product does match
- ‘:exclude’ to make sure the product doesn’t match
- ‘product_selector_type’ determines how eligible products
will be identified. Can be either:
- ‘:tag’ to find products by tag
- ‘:type’ to find products by type
- ‘:vendor’ to find products by vendor
- ‘:product_id’ to find products by ID
- ‘:variant_id’ to find products by variant ID
- ‘:subscription’ to find subscription products
- ‘:all’ for all products
- ‘product_selectors’ is a list of identifiers (from above) for
qualifying products. Product/Variant ID lists should only
contain numbers (ie. no quotes). If ‘:all’ is used, this
can also be ‘nil’.
- ‘tiers’ is a list of tiers where:
- ‘quantity’ is the minimum quantity you need to buy to
qualify
- ‘discount_type’ is the type of discount to provide. Can be
either:
- ‘:percent’
- ‘:dollar’
- ‘discount_amount’ is the percentage/dollar discount to
apply (per item)
- ‘discount_message’ is the message to show when a discount
is applied
================================================================
PRODUCT_DISCOUNT_TIERS = [
{
product_selector_match_type: :include,
product_selector_type: :all,
tiers: [
{
quantity: 2,
discount_type: :percent,
discount_amount: 10,
discount_message: ‘You saved 10%! Why not add 1 more item to SAVE 12.5%?’
},
{
quantity: 3,
discount_type: :percent,
discount_amount: 12.5,
discount_message: ‘You saved 12.5%! Why not add 1 more item to SAVE 15%’,
},
{
quantity: 4,
discount_type: :percent,
discount_amount: 15,
discount_message: ‘Congrats! You unlocked our biggest discount!’,
},
],
},
]
================================ Script Code (do not edit) ================================
================================================================
ProductSelector
Finds matching products by the entered criteria.
================================================================
class ProductSelector
def initialize(match_type, selector_type, selectors)
@match _type = match_type
@comparator = match_type == :include ? ‘any?’ : ‘none?’
@Selector _type = selector_type
@selectors = selectors
end
def match?(line_item)
if self.respond_to?(@selector_type)
self.send(@selector_type, line_item)
else
raise RuntimeError.new(‘Invalid product selector type’)
end
end
def tag(line_item)
product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip }
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@selectors & product_tags).send(@comparator)
end
def type(line_item)
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip)
end
def vendor(line_item)
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip)
end
def product_id(line_item)
(@match_type == :include) == @selectors.include?(line_item.variant.product.id)
end
def variant_id(line_item)
(@match_type == :include) == @selectors.include?(line_item.variant.id)
end
def subscription(line_item)
!line_item.selling_plan_id.nil?
end
def all(line_item)
true
end
end
================================================================
DiscountApplicator
Applies the entered discount to the supplied line item.
================================================================
class DiscountApplicator
def initialize(discount_type, discount_amount, discount_message)
@discount _type = discount_type
@discount _message = discount_message
@discount _amount = if discount_type == :percent
1 - (discount_amount * 0.01)
else
Money.new(cents: 100) * discount_amount
end
end
def apply(line_item)
new_line_price = if @discount _type == :percent
line_item.line_price * @discount _amount
else
[line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max
end
line_item.change_line_price(new_line_price, message: @discount _message)
end
end
================================================================
TieredProductDiscountByQuantityCampaign
If the total quantity of matching items is greater than (or
equal to) an entered threshold, the associated discount is
applied to each matching item.
================================================================
class TieredProductDiscountByQuantityCampaign
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart)
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
applicable_items = cart.line_items.select { |line_item| product_selector.match?(line_item) }
next if applicable_items.nil?
total_applicable_quantity = applicable_items.map(&:quantity).reduce(0, :+)
tiers = campaign[:tiers].sort_by { |tier| tier[:quantity] }.reverse
applicable_tier = tiers.find { |tier| tier[:quantity] <= total_applicable_quantity }
next if applicable_tier.nil?
discount_applicator = DiscountApplicator.new(
applicable_tier[:discount_type],
applicable_tier[:discount_amount],
applicable_tier[:discount_message]
)
applicable_items.each do |line_item|
discount_applicator.apply(line_item)
end
end
end
end
CAMPAIGNS = [
TieredProductDiscountByQuantityCampaign.new(PRODUCT_DISCOUNT_TIERS),
]
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart)
end
Output.cart = Input.cart