Migrating a percentage off shipping script
The shipping half of Shopify’s own dialect uses the same class name as the line-item half and stores the opposite fraction in it. One keeps what the shopper pays, the other keeps what comes off.
RebuiltIt reduced every delivery rate at checkout by a percentage.
Paste it into Scripts rescue and watch what it rebuilds
- Copy the Ruby with the button beside any Script on this page.
- In your Shopify admin, open Stackable, then Tools, then Scripts rescue.
- Paste it there, read what the tool says it will build, and compare that with the settings on this page.
Scripts rescue is on the Pro plan. Nothing is published until you tell it what your old Script charged and the two figures match to the cent.
The Script
RebuiltDanger pair D16. This file and its partner look almost identical and behave differently, so read both before you decide which one you have.
# ================================ Customizable Settings ================================
DISCOUNT_TYPE = :percent
DISCOUNT_AMOUNT = 10
DISCOUNT_MESSAGE = '10% off shipping'
# ================================ Script Code (do not edit) ================================
class DiscountApplicator
def initialize(discount_type, discount_amount, discount_message)
@discount_type = discount_type
@discount_message = discount_message
@discount_amount = if discount_type == :percent
discount_amount * 0.01
else
Money.new(cents: 100) * discount_amount
end
end
def apply(shipping_rate)
discount_amount = if @discount_type == :percent
shipping_rate.price * @discount_amount
else
@discount_amount > shipping_rate.price ? shipping_rate.price : @discount_amount
end
shipping_rate.apply_discount(discount_amount, message: @discount_message)
end
end
class DiscountRatesCampaign
def initialize(discount_applicator)
@discount_applicator = discount_applicator
end
def run(cart, shipping_rates)
shipping_rates.each do |shipping_rate|
@discount_applicator.apply(shipping_rate)
end
end
end
CAMPAIGNS = [
DiscountRatesCampaign.new(
DiscountApplicator.new(DISCOUNT_TYPE, DISCOUNT_AMOUNT, DISCOUNT_MESSAGE),
),
]
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_ratesRecognised as Shipping discount and rebuilt as a free_shipping offer. These are the real configuration keys the offer is saved with, so you can check your own rebuild against them field by field.
| Setting | Value | Config key |
|---|---|---|
| Offer type | free_shipping | type |
| Counting | per_cart | counting |
| Recurrence | once | recurrence |
| Tier 1 | min spend $0.00 -> 10% off | tiers[0] |
| Target scope | all | target.scope |
| Method | automatic | discountMethod |
| Allocation | standard | stacking.allocation |
| Combines with other discounts | no | stacking |
- Confirm which products this applies to. We could not read product targeting from the script.
- This discounts every shipping rate at checkout, not one named rate.
Built on our public demo store, Meridian Goods, so every price here can be reproduced rather than taken on trust. The discount below is what the same engine that runs at checkout computes for this exact cart.
| Item | Qty | Unit price |
|---|---|---|
| Braided USB-C Cable | 1 | $14.00 |
| Subtotal | $14.00 | |
| Delivery, normally $6.90 | $6.21 | |
| Total | $14.00 | |
Signed out, or signed in as a customer with no tags.
This rebuild only changes shipping. We price shipping against a sample rate rather than the rate your shopper saw, so there is no figure here we could honestly compare. Publishing records that the amount was not checked.
This rule carries no condition at all, so it fires on any cart holding anything and there is no quiet cart to build. The negative check is an empty cart, which the app runs for you. That is correct behaviour, not a failure.
Two files that look the same
Each pair below is one Script shape written two ways. They differ by a line or two and they do different things, so read both before deciding which one you have.
Danger pair D16
Official dialect, shipping applicator (D16)
RebuiltRebuilt as a free_shipping offer.
Delivery saving on its own cart: $0.69
DISCOUNT_MESSAGE = '10% off shipping'
discount_amount * 0.01
def apply(shipping_rate)
discount_amount = if @discount_type == :percent
shipping_rate.price * @discount_amount
@discount_amount > shipping_rate.price ? shipping_rate.price : @discount_amountAnd 8 more differing lines, on its own page.
Official dialect, lineitem applicator (D16)
RebuiltRebuilt as a volume offer.
Discount on its own cart: $1.40
DISCOUNT_MESSAGE = '10% off everything'
1 - (discount_amount * 0.01)
def apply(line_item)
new_line_price = if @discount_type == :percent
line_item.line_price * @discount_amount
[line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].maxAnd 8 more differing lines, on its own page.
Common questions
- Will Stackable rebuild this script?
- Yes. Every spelling on this page is rebuilt today as a free_shipping offer, and the cart above is the one that proves it.
- What cart proves it works?
- 1 x Braided USB-C Cable at $14.00. The engine takes $0.69 off, and checkout charges $14.00 plus $6.21 delivery.
- What will I have to check before publishing?
- Confirm which products this applies to. We could not read product targeting from the script. This discounts every shipping rate at checkout, not one named rate.
Related Script shapes
The dialect Shopify’s own documentation taught, with its settings block above a do-not-edit banner.
A flat sum off the delivery charge, floored at free.
Every delivery rate rewritten to one price rather than reduced by an amount.
Paste your Script and see it rebuilt
The rebuild is checked against the money your old Script charged before you can publish it.