Solved

How to prevent discount stacking in tiered discount code script?

Rastaclat
Tourist
4 0 1

Hey!

Our store is trying to implement a tiered discount based on spend and found the below script which executes fairly well for us.  The problem that we're running into is that it allows a user to enter in a discount code at checkout that stacks upon the existing discount.  I'm wondering if anyone has an example script where a single discount code is required in order to execute the below.  The other alternative would be for us to disable entering in a coupon code altogether when we run a promo like this, however we would prefer to track this + allow users from other channels (e.g. ambassadors) to be able to use codes that have a higher % off:

TyTyTy for any help / tips here! 

 

# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
#   - 'threshold' is the spend amount needed 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
# ================================================================
SPENDING_THRESHOLDS = [
  {
    threshold: 30,
    discount_type: :percent,
    discount_amount: 10,
    discount_message: 'Spend $30 and get 10% off!',
  },
  {
    threshold: 50,
    discount_type: :percent,
    discount_amount: 15,
    discount_message: 'Spend $50 and get 15% off!',
  },
  {
    threshold: 100,
    discount_type: :percent,
    discount_amount: 20,
    discount_message: 'Spend $100 and get 20% off!',
  },
]

# ================================ Script Code (do not edit) ================================
# ================================================================
# 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

# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
  def initialize(tiers)
    @Tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
  end

  def run(cart)
    applicable_tier = @Tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
    return if applicable_tier.nil?

    discount_applicator = DiscountApplicator.new(
      applicable_tier[:discount_type],
      applicable_tier[:discount_amount],
      applicable_tier[:discount_message]
    )

    cart.line_items.each do |line_item|
      next if line_item.variant.product.gift_card?
      discount_applicator.apply(line_item)
    end
  end
end

CAMPAIGNS = [
  TieredDiscountBySpendCampaign.new(SPENDING_THRESHOLDS),
]

CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

Output.cart = Input.cart
Accepted Solution (1)
playwright-mike
Shopify Partner
72 18 33

This is an accepted solution.

Hi Sam,

Those codes are for 0% off. The script takes care of the actual discounting. So you just need one code per tiered pricing scheme.

And for extra clarification, this script supports two different codes (currently STANDARD_CODE and AMBASSADOR_CODE). You can change those codes to match the ones you create in the Shopify Admin > Discounts area. Here is a screen shots of my discount codes:

original_codes.png

 

However, if I wanted to change the codes, I would edit this area of the code I supplied you.

DISCOUNT_CODES = {
  'STANDARD_CODE' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

 

Instead I might use a new code for the standard discount called "TIERED_SPECIAL". If so, my code would look like this:

DISCOUNT_CODES = {
  'TIERED_SPECIAL' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

And then I would need to add a new 0% off discount code to match:

new_code.png

In any case, the discount code is only used to activate the portion of the script that creates the actual tiered discounts. 

Hopefully that works for you. If so, feel free to mark this as the accepted solution.

Thanks!
Matthew

Playwright | Create Shopify Scripts without writing code | https://playwrightapp.com
- Was my reply helpful? Please Like and Accept Solution.

View solution in original post

Replies 13 (13)

playwright-mike
Shopify Partner
72 18 33

Hi @Rastaclat

I created an app that lets you create scripts like this without having to write code . It has a "tiered discount" feature, so I borrowed some ideas from that.

Here is an updated script that should allow you to create two different discount codes and point them to different discount tiers. 

 

# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
#   - 'threshold' is the spend amount needed 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
# ================================================================
SPENDING_THRESHOLDS_STANDARD = [
  {
    threshold: 30,
    discount_type: :percent,
    discount_amount: 10,
    discount_message: 'Spend $30 and get 10% off!',
  },
  {
    threshold: 50,
    discount_type: :percent,
    discount_amount: 15,
    discount_message: 'Spend $50 and get 15% off!',
  },
  {
    threshold: 100,
    discount_type: :percent,
    discount_amount: 20,
    discount_message: 'Spend $100 and get 20% off!',
  },
]

SPENDING_THRESHOLDS_AMBASSADOR = [
  {
    threshold: 30,
    discount_type: :percent,
    discount_amount: 12.5,
    discount_message: 'Spend $30 and get 12.5% off!',
  },
  {
    threshold: 50,
    discount_type: :percent,
    discount_amount: 17.5,
    discount_message: 'Spend $50 and get 17.5% off!',
  },
  {
    threshold: 100,
    discount_type: :percent,
    discount_amount: 22.5,
    discount_message: 'Spend $100 and get 22.5% off!',
  },
]

DISCOUNT_CODES = {
  'STANDARD_CODE' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

# ================================ Script Code (do not edit) ================================
# ================================================================
# 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

# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
  def initialize(tiers)
    @tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
  end

  def run(cart)
    applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
    return if applicable_tier.nil?

    discount_applicator = DiscountApplicator.new(
      applicable_tier[:discount_type],
      applicable_tier[:discount_amount],
      applicable_tier[:discount_message]
    )

    cart.line_items.each do |line_item|
      next if line_item.variant.product.gift_card?
      discount_applicator.apply(line_item)
    end
  end
end

def discount_code_present(cart, code)
  !cart.discount_code.nil? and (cart.discount_code.code.upcase == code.upcase)
end

CAMPAIGNS = []

DISCOUNT_CODES.each do |discount_code|
  if discount_code_present(Input.cart, discount_code[0])
    CAMPAIGNS = [
      TieredDiscountBySpendCampaign.new(discount_code[1]),
    ]
  end
end

CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

Output.cart = Input.cart

 

 

Here is a screen shot of it working for me:

tiered-discounts.png

Don't forget to create the actual discount codes in the Shopify Admin > Discounts screen.

 

Hope that helps!

Matthew 

Playwright | Create Shopify Scripts without writing code | https://playwrightapp.com
- Was my reply helpful? Please Like and Accept Solution.

Rastaclat
Tourist
4 0 1

Hey Matthew,

Thank you for your help here!  The below script worked amazing as far as requiring a discount code to be entered vs. automatically applying.  I just have a question about having the code apply the correct % off depending on the $ threshold.  If I create this coupon in the backend, I'm only able to assign one % off, as Shopify doesn't allow me to create multiple codes with the same discount code name for each % off.  Do you have a workaround for this?

Thanks again!

Sam

playwright-mike
Shopify Partner
72 18 33

This is an accepted solution.

Hi Sam,

Those codes are for 0% off. The script takes care of the actual discounting. So you just need one code per tiered pricing scheme.

And for extra clarification, this script supports two different codes (currently STANDARD_CODE and AMBASSADOR_CODE). You can change those codes to match the ones you create in the Shopify Admin > Discounts area. Here is a screen shots of my discount codes:

original_codes.png

 

However, if I wanted to change the codes, I would edit this area of the code I supplied you.

DISCOUNT_CODES = {
  'STANDARD_CODE' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

 

Instead I might use a new code for the standard discount called "TIERED_SPECIAL". If so, my code would look like this:

DISCOUNT_CODES = {
  'TIERED_SPECIAL' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

And then I would need to add a new 0% off discount code to match:

new_code.png

In any case, the discount code is only used to activate the portion of the script that creates the actual tiered discounts. 

Hopefully that works for you. If so, feel free to mark this as the accepted solution.

Thanks!
Matthew

Playwright | Create Shopify Scripts without writing code | https://playwrightapp.com
- Was my reply helpful? Please Like and Accept Solution.

Chris_Turner
Visitor
2 0 0

Im not sure why this is happening? Did I miss something?

 Screen Shot 2021-11-08 at 1.00.44 PM.png

# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
#   - 'threshold' is the spend amount needed 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
# ================================================================
SPENDING_THRESHOLDS_STANDARD = [
  {
    threshold: 100,
    discount_type: :dollar,
    discount_amount: 15,
    discount_message: 'Spend $100 and get $15 off!',
  },
  {
    threshold: 200,
    discount_type: :dollar,
    discount_amount: 40,
    discount_message: 'Spend $200 and get $40 off!',
  },
  {
    threshold: 400,
    discount_type: :dollar,
    discount_amount: 100,
    discount_message: 'Spend $400 and get $100 off!',
  },
]

SPENDING_THRESHOLDS_AMBASSADOR = [
  {
    threshold: 30,
    discount_type: :percent,
    discount_amount: 12.5,
    discount_message: 'Spend $30 and get 12.5% off!',
  },
  {
    threshold: 50,
    discount_type: :percent,
    discount_amount: 17.5,
    discount_message: 'Spend $50 and get 17.5% off!',
  },
  {
    threshold: 100,
    discount_type: :percent,
    discount_amount: 22.5,
    discount_message: 'Spend $100 and get 22.5% off!',
  },
]

DISCOUNT_CODES = {
  'CYBER' => SPENDING_THRESHOLDS_STANDARD,
  'AMBASSADOR_CODE' => SPENDING_THRESHOLDS_AMBASSADOR
}

# ================================ Script Code (do not edit) ================================
# ================================================================
# 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

# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
  def initialize(tiers)
    @tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
  end

  def run(cart)
    applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
    return if applicable_tier.nil?

    discount_applicator = DiscountApplicator.new(
      applicable_tier[:discount_type],
      applicable_tier[:discount_amount],
      applicable_tier[:discount_message]
    )

    cart.line_items.each do |line_item|
      next if line_item.variant.product.gift_card?
      discount_applicator.apply(line_item)
    end
  end
end

def discount_code_present(cart, code)
  !cart.discount_code.nil? and (cart.discount_code.code.upcase == code.upcase)
end

CAMPAIGNS = []

DISCOUNT_CODES.each do |discount_code|
  if discount_code_present(Input.cart, discount_code[0])
    CAMPAIGNS = [
      TieredDiscountBySpendCampaign.new(discount_code[1]),
    ]
  end
end

CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

Output.cart = Input.cart

 

japple
Visitor
2 0 1

I am looking for a code that works on the cart subtotal not line item price.

For example I used the code provided but if the cart reaches $75 it is giving $10 off each item in the cart instead of just $10 off the order

CRMW
Shopify Partner
12 0 6

We also have the same question – Is there a way to discount the cart subtotal, rather than each individual line item if the cart threshold is met? Specifically, this script doesn't work if we wanted to take $10 off $100, as it would discount $10 for each line item. Thank you!

Derek_Morin
Shopify Expert
216 1 34

@CRMW @japple I know it's not a PLUS script, but our app can apply tiered discounts on the subtotal, rather than on each line_item. Example here
The app works alongside scripts that use discount codes, which means you can stack a tiered discount applied with our app with a discount applied via Script. 

nladart
New Member
4 0 0

I'm having the same issue where the script works but it shows Discount under the subtotal as $0, which I think will confuse customers. Has anyone figured out how to fix this?

andy_cr
Visitor
1 0 0

I was looking into this code and was wondering if it could be modified to restrict the eligible items? Similar to this solution https://community.shopify.com/c/shopify-scripts/script-tiered-discounts-w-collection-condition/m-p/6... but with your code? Thanks!

Casey_Samson
Explorer
47 0 9

Hi @playwright-mike 

Hoping you can help. I am trying to use this code, but it does nothing to the cart. Any idea what is going on? I even called into tech support and they could not figure it out. They did say something about it being older, and there may be an update to the code necessary for it to work.

 

 

# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
# - 'threshold' is the spend amount needed 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
# ================================================================
SPENDING_THRESHOLDS_150 = [
{
threshold: 150,
discount_type: :percent,
discount_amount: 15,
discount_message: '15% off!',
},
{
threshold: 200,
discount_type: :percent,
discount_amount: 20,
discount_message: '20% off!',
},
{
threshold: 250,
discount_type: :percent,
discount_amount: 25,
discount_message: '25% off!',
},
]

SPENDING_THRESHOLDS_200 = [
{
threshold: 200,
discount_type: :percent,
discount_amount: 20,
discount_message: '20% off!',
},
]

SPENDING_THRESHOLDS_250 = [
{
threshold: 250,
discount_type: :percent,
discount_amount: 25,
discount_message: '25% off!',
},
]

DISCOUNT_CODES = {
'CMTEST15' => SPENDING_THRESHOLDS_150,
'CMTEST20' => SPENDING_THRESHOLDS_200,
'CMTEST25' => SPENDING_THRESHOLDS_250,

}

# ================================ Script Code (do not edit) ================================
# ================================================================
# 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

# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
def initialize(tiers)
@tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
end

def run(cart)
applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
return if applicable_tier.nil?

discount_applicator = DiscountApplicator.new(
applicable_tier[:discount_type],
applicable_tier[:discount_amount],
applicable_tier[:discount_message]
)

cart.line_items.each do |line_item|
next if line_item.variant.product.gift_card?
discount_applicator.apply(line_item)
end
end
end

def discount_code_present(cart, code)
!cart.discount_code.nil? and (cart.discount_code.code.upcase == code.upcase)
end

CAMPAIGNS = []

DISCOUNT_CODES.each do |discount_code|
if discount_code_present(Input.cart, discount_code[0])
CAMPAIGNS = [
TieredDiscountBySpendCampaign.new(discount_code[1]),
]
end
end

CAMPAIGNS.each do |campaign|
campaign.run(Input.cart)
end

Output.cart = Input.cart

kylemoloo
Shopify Partner
13 0 6

If you also wanted to add Free Shipping using a code that applies the discount tiers, how would you adjust that script?

Kyle Moloo | Sr. Director of Ecommerce
jschmaing
Visitor
1 0 0

Hey Matt,

Can you point me in the right direction on where to paste this script. I have tried the theme.liquid and the cart.liquid but no luck.

 

Thank you,

Jerry

WhiteWater_Web
Shopify Expert
457 17 42

Hi Jerry - Shopify Scripts like these are added via the Script Editor app, which is exclusive to Plus clients. If you are a Plus client, and you don’t have the now ‘offline’ Script Editor app installed already, there are some ways to still get it.

 


Note though that scripts like these are being deprecated in 2025, as Shopify wants checkout customizations to be made using Functions, authorized Checkout Apps, etc.

 

Cheers.

 

WhiteWater Web

A certified Shopify Partner and Expert, WhiteWater Web (WWW) is a premium digital solutions company specializing in advanced Shopify Dev, Usability/Design, and Online Strategy. WWW has been working with the Shopify platform since 2006.
info@whitewatersolutions.com