All things Shopify and commerce
Hi there.
Is there any way to make shopify calculate the shipping rate BEFORE applying the discount and not after?
1) On our store we offer free shipping for over 49
2) Customers add 49 worth of goods and proceed to checkout thinking they have free shipping
3) Apply discount % and total goes to 44
4) Shopify calculate shipping rate base on 44, and customer end up spending 51.
They spend more with a discount code than without it, because shopify erranously calculate shipping cost on the net discounted and not on the price before discount
5) We lose 50-100 sales a month for this and we receive 10-15 mails a week of people complaining about it and frustrated about it
6) Shopify does absolutely nothing about it and keeps saying it cannot be changed, while litterally would take 10 minutes of coding to add an option allowing merchants to decide this.
Anything we can do ? I will surely move away from it if this does not get changed before EOY
Hey @Agolab!
Happy to help out today. It sounds like you are using a percentage-based discount to account for the potential cost of shipping? The issue you will have with that is different orders come from different locations, the orders are weighted different, etc. so unless you are using flat based shipping rates (Ex. $10 flat-rate) you won't be able to use a percentage or flat rate discount to match the calculated cost of shipping.
In this case, you would want to create a 'Free Shipping' discount. The free shipping discount, once entered, will zero out any shipping cost to the customer as long as they meet the discount requirements that you set up. We have a guide on setting that up here.
Let me know if this helps. If there is anything else I can help you with, please let me know.
Dirk | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Hi Dirk,
This is another big issue with shopify: we cannot stack discounts.
I would be more than glad to offer a coupon for free shipping to our customers, but they cannot apply it with another coupon based on % off the total order. They can only use one at the checkout, another thing that is really really annoying and shows how much shopify is behind its competitors.
Anyway we ship only to Italy and our shipping rate is a flat rate of 6,50.
The thing is WE SHOULD NOT LOOK for workarounds to this problem. This problem should by fixed by shopify, allowing merchants to calculate shipping rates before the discounts are applied, like on many many many stores worldwide.
Is this possible at least with shopify PLUS ? I've heard you can customize more the checkout with that plan.
Great question, using an app such as Stackable Discounts would provide you with that functionality you're looking for to stack multiple discounts together. Including both manual, and automatic discounts.
Additionally, the fixed value and percentage-based discounts apply to the products in an order, but don't apply to shipping costs. The free shipping discount code is intended for that. Feel free to learn more about our discount system in greater detail here.
With that said, Shopify Plus does provide you with the ability to make more changes to your checkout and includes a script editor tool that allows you to stack discounts as well. With that said, the systematic order in which our checkout functions (items added to cart > cart pushed to checkout > personal info > shipping rates and order total > order confirmation) remain the same. Which is standard practice in ecommerce.
I hope this helps! If there is anything else I can help you with, please let me know.
Dirk | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Dirk, I don't think what you are proposing is a solution. The shipping rate should be based on the subtotal and not the total (after the discount is applied). It is honestly just common sense, and trying to find ways around it is just NOT a solution, and this should be addressed with your team. We are having the same issue, and WE ARE LOSING SALES on a daily basis because of this issue. We just migrated from Bigcommerce, thinking that Shopify would be a better platform. Please address with your technical team. Thank you!
This is not a solution. We are also losing so many customers cause they go over the minimum amount for free shipping and then apply their welcome coupon for %10. Goes under the minimum value and then they have to pay shipping.
Shipping fee calculation should exclude coupons. Or at least give us the option when setting up shipping to include coupons at calculation or not
I am sorry to say that the “work around” you explained is not a work around. It’s just doesn’t work. At all.
I’ll explain.
I set up a discount code for amount off order for our ship cost of $6.95 to be added automatically to all orders over $60.
This code comes off the subtotal like we want, but then if an actual discount code is used on the order, for example 20% off, the 20% comes off and could drop the order total below $60 and then the shipping cost set up in the shipping options will add back in. See attached.
In the shipping and delivery settings, there’s no way to adjust it properly to account for utilizing the discount code option for amount off order at a certain dollar amount because if you set to add shipping at a flat rate to all orders, thinking the discount code that is set up to add automatically at orders $60 and over, if the order total isn’t high enough and the customer uses a discount code, entered at checkout and the subtotal drops below $60, the flat rate shipping cost will be added back in.
Theres no way to make this work. At all.
How is it even possible that Shopify was set up this way without thinking about this when creating the options that would be offered to merchants in the shipping and delivery section in settings. It’s truly mind blowing, and also forcing us to rip off our customers. Because that’s exactly what it is, a rip off.
and now I feel terrible that there’s an undetermined amount of customers that technically over paid on their purchases with us.
this is an even bigger deal if merchants have higher flat rate costs above $6.95, because at some point, the shipping cost becomes more than the discount amount calculated when a customer is entering a code.
And that is an even bigger rip off because they would actually pay less for their order by not using the discount code at all, and getting the free shipping.
So, the next question becomes;
Why would merchants ever offer discount codes to our customers when they aren’t actually getting a discount and has in turn, makes the merchants discount code announcements to entice customers and help drive sales for merchants, totally false.
And Shopify has made all of their merchants lose sales and look like idiots to their customers, because they have no idea the merchant didn’t actually set it up that way and it’s really the poorly developed options in the platform we are using.
Even more shocking it that shop if I hasn’t fixed this already and available for all plans offered.
you should actually be really embarrassed that you suggest that Shopify plus has more options for changes and set up, because merchants shouldn’t have to pay more money giving up revenue to try to drive sales using discounts.
You should want to provide tools your merchants can use to be as successful as possible but you are hindering all of our success, and yours.
We found a temporary solution to resolve this issue: an app called discountyard. It allows you to setup free shipping based on the subtotal and not the total. Hopefully Shopify developers will eventually figure a solution and fix this bug since it is misleading to our customers to offer free shipping above a certain amount, and end up charging them a fee if a discount puts them under the threshold. Hope this app helps you!
Great to know . I actually wanted to come and update here as well.
We are on shopify plus and managed to use their scripting options to change this. So no app.
Let me know if you want the script here. It checks the values before the discount code. If the discount code then drops the order below the minimum order value for free shipping it will then just update the shipping value to 0 as it should be.
Here is the Code. At the bottom you will see I have 2 " Campaigns" You can add more if needed.
Free shipping cause I hit R450
Still Free shipping after discount dropped me below the threshold ( Scripts Controlled this )
class Campaign
def initialize(condition, *qualifiers)
@condition = (condition.to_s + '?').to_sym
@qualifiers = PostCartAmountQualifier ? [] : [] rescue qualifiers.compact
@Anonymous_item_selector = qualifiers.last unless @Anonymous_item_selector
qualifiers.compact.each do |qualifier|
is_multi_select = qualifier.instance_variable_get(:@conditions).is_a?(Array)
if is_multi_select
qualifier.instance_variable_get(:@conditions).each do |nested_q|
@post_amount_qualifier = nested_q if nested_q.is_a?(PostCartAmountQualifier)
@qualifiers << qualifier
end
else
@post_amount_qualifier = qualifier if qualifier.is_a?(PostCartAmountQualifier)
@qualifiers << qualifier
end
end if @qualifiers.empty?
end
def qualifies?(cart)
return true if @qualifiers.empty?
@unmodified_line_items = cart.line_items.map do |item|
new_item = item.dup
new_item.instance_variables.each do |var|
val = item.instance_variable_get(var)
new_item.instance_variable_set(var, val.dup) if val.respond_to?(:dup)
end
new_item
end if @post_amount_qualifier
@qualifiers.send(@condition) do |qualifier|
is_selector = false
if qualifier.is_a?(Selector) || qualifier.instance_variable_get(:@conditions).any? { |q| q.is_a?(Selector) }
is_selector = true
end rescue nil
if is_selector
raise "Missing line item match type" if @Li_match_type.nil?
cart.line_items.send(@li_match_type) do |item|
next false if item.nil?
qualifier.match?(item)
end
else
qualifier.match?(cart, @Anonymous_item_selector)
end
end
end
def run_with_hooks(cart)
before_run(cart) if respond_to?(:before_run)
run(cart)
after_run(cart)
end
def after_run(cart)
@discount.apply_final_discount if @discount && @discount.respond_to?(:apply_final_discount)
revert_changes(cart) unless @post_amount_qualifier.nil? || @post_amount_qualifier.match?(cart)
end
def revert_changes(cart)
cart.instance_variable_set(:@line_items, @unmodified_line_items)
end
end
class ShippingDiscount < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, li_match_type, line_item_qualifier, rate_selector, discount)
super(condition, customer_qualifier, cart_qualifier, line_item_qualifier)
@Li_match_type = (li_match_type.to_s + '?').to_sym
@rate_selector = rate_selector
@discount = discount
end
def run(rates, cart)
raise "Campaign requires a discount" unless @discount
return unless qualifies?(cart)
rates.each do |rate|
next unless @rate_selector.nil? || @rate_selector.match?(rate)
@discount.apply(rate)
end
end
end
class Qualifier
def partial_match(match_type, item_info, possible_matches)
match_type = (match_type.to_s + '?').to_sym
if item_info.kind_of?(Array)
possible_matches.any? do |possibility|
item_info.any? do |search|
search.send(match_type, possibility)
end
end
else
possible_matches.any? do |possibility|
item_info.send(match_type, possibility)
end
end
end
def compare_amounts(compare, comparison_type, compare_to)
case comparison_type
when :greater_than
return compare > compare_to
when :greater_than_or_equal
return compare >= compare_to
when :less_than
return compare < compare_to
when :less_than_or_equal
return compare <= compare_to
when :equal_to
return compare == compare_to
else
raise "Invalid comparison type"
end
end
end
class CartAmountQualifier < Qualifier
def initialize(behaviour, comparison_type, amount)
@behaviour = behaviour
@comparison_type = comparison_type
@amount = Money.new(cents: amount * 100)
end
def match?(cart, selector = nil)
total = cart.subtotal_price
if @behaviour == :item || @behaviour == :diff_item
total = cart.line_items.reduce(Money.zero) do |total, item|
total + (selector&.match?(item) ? item.line_price : Money.zero)
end
end
case @behaviour
when :cart, :item
compare_amounts(total, @comparison_type, @amount)
when :diff_cart
compare_amounts(cart.subtotal_price_was - @amount, @comparison_type, total)
when :diff_item
original_line_total = cart.line_items.reduce(Money.zero) do |total, item|
total + (selector&.match?(item) ? item.original_line_price : Money.zero)
end
compare_amounts(original_line_total - @amount, @comparison_type, total)
end
end
end
class Selector
def partial_match(match_type, item_info, possible_matches)
match_type = (match_type.to_s + '?').to_sym
if item_info.kind_of?(Array)
possible_matches.any? do |possibility|
item_info.any? do |search|
search.send(match_type, possibility)
end
end
else
possible_matches.any? do |possibility|
item_info.send(match_type, possibility)
end
end
end
end
class RateNameSelector < Selector
def initialize(match_type, match_condition, names)
@match_condition = match_condition
@invert = match_type == :does_not
@names = names.map(&:downcase)
end
def match?(shipping_rate)
name = shipping_rate.name.downcase
case @match_condition
when :match
return @invert ^ @names.include?(name)
else
return @invert ^ partial_match(@match_condition, name, @names)
end
end
end
class PercentageDiscount
def initialize(percent, message)
@percent = Decimal.new(percent) / 100
@message = message
end
def apply(rate)
rate.apply_discount(rate.price * @percent, { message: @message })
end
end
CAMPAIGNS = [
ShippingDiscount.new(
:any,
nil,
CartAmountQualifier.new(
:cart,
:greater_than_or_equal,
450
),
:any,
nil,
RateNameSelector.new(
:does,
:match,
["Deliver to my door via courier."]
),
PercentageDiscount.new(
100,
"Congratulations! Your order qualifies for free shipping."
)
),
ShippingDiscount.new(
:any,
nil,
CartAmountQualifier.new(
:cart,
:less_than,
450
),
:any,
nil,
RateNameSelector.new(
:does,
:match,
["Deliver to my door via courier."]
),
PercentageDiscount.new(
0,
"Free shipping on orders over R450 Ts & Cs apply."
)
)
].freeze
CAMPAIGNS.each do |campaign|
campaign.run(Input.shipping_rates, Input.cart)
end
Output.shipping_rates = Input.shipping_rates
Is this only for shopify plus merchant ? Where I am supposed to put this script and do I need to change any line of code to make it work in my theme ? I guess a lot as I use euro and 49 as free shipping thresold.
Only Shopify plus Merchants.
Under Script Editor. Yes you will have to add a script to Shipping tab.
Yes you will have to change some line in the bottom section.
450 is my free shipping threshold on the amount before discount codes apply.
["Deliver to my door via courier."] is my Shipping method name. This needs to match in my case cause my international has diff names. This must be changed to match.
Percentage discount is 100 cause I am giving you free shipping if above is good.
This is a short description on what to do.
ShippingDiscount.new(
:any,
nil,
CartAmountQualifier.new(
:cart,
:greater_than_or_equal,
450
),
:any,
nil,
RateNameSelector.new(
:does,
:match,
["Deliver to my door via courier."]
),
PercentageDiscount.new(
100,
"Congratulations! Your order qualifies for free shipping."
)
)
That worked perfect and the messages into the Shipping Options is a great touch.
Hei how this works ? Are you sure the app does allow your customer to calculate shipping on subtotal and not total after discount ? Cause that's a function on shopify checkout system and we cannot touch that.
I'm also looking for a solution on that issue.
I would like to have an option to set the free shipping based on the original total price (technically described here). With that, the discounts wouldn't be considered when calculating the shipping costs.
@Dirk Free shipping discounts aren't a solution nor a workaround for this issue.
Same here. We give people big discounts on black friday, lets say 30%, ant by default free shipping is anything above 70 EUR originally, at the end of the day they pay let's say 60 euros and still get a free shipping, because the value is calculated before, not after applying discounts and we end up giving 30% + let's say another 10% if the shipping cost for us is 6 eur. And 40%value we can't give as we go negative in profits.
I'm trying to actually fix the opposite issue (in a shipping app) of having Shipping Rate rules to be applied after a discount has been applied to an order rather than before. I don't think it's deceiving at all if you're offering Free Shipping on total cart value, rather than subtotal (or individual items). I think the later is double dipping. If you visit an online store who offers Free Shipping on orders over $100 and see an item showing the price as Was $110, Now $90, you wouldn't expect Free shipping (just because it used to cost $110), so why would you with a discount code?
@Agolab @bruksnys @DeonSmit
Advanced Free Shipping allows you to create shipping discounts based on checkout subtotal (that is, total after discounts are applied).
Let me know if I can help further. (No need for scripts).
I cannot recreate every single of the hundreds of discounts code we have in your app to have this applied. I need a script or a solution to fix it.. 4 years later still no solutions.
Starting a B2B store is a big undertaking that requires careful planning and execution. W...
By JasonH Sep 23, 2024By investing 30 minutes of your time, you can unlock the potential for increased sales,...
By Jacqui Sep 11, 2024We appreciate the diverse ways you participate in and engage with the Shopify Communi...
By JasonH Sep 9, 2024