Migrating a script that limited how many units were discounted
The cap is not the trap. The trap is a single sort line: with it the CHEAPEST units are discounted, without it the FIRST ones are, and both files are dense with the same split call that also makes them look like a BOGO.
可重建It discounted only the first few matching units and left the rest at full price.
商家用 3 种不同写法写过这段逻辑,它们的含义并不相同。每种写法都列在下方,各自配有对应的购物车和数字。
把它粘贴到 Scripts 救援,看看会重建成什么
- 用本页任意 Script 旁边的按钮复制 Ruby 代码。
- 在 Shopify 后台打开 Stackable,依次进入工具、Scripts 救援。
- 粘贴进去,读一读工具说它会创建什么,再和本页的设置逐项对照。
Scripts 救援属于 Pro 套餐。在您填写旧 Script 的折扣金额、且两个数字精确到最小货币单位完全一致之前,不会发布任何内容。
Quantity limit first n discounted (D5)
可重建危险配对 D5。这个文件和它的搭档看起来几乎一样,行为却不同,在判断您手上是哪一个之前,请把两份都读一遍。
# GENERATED BY THE SHOPIFY SCRIPT CREATOR APP
class ConditionalDiscount < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, line_item_selector, discount, max_discounts)
super(condition, customer_qualifier, cart_qualifier, line_item_selector)
@discount = discount
@items_to_discount = max_discounts == 0 ? nil : max_discounts
end
def run(cart)
return unless qualifies?(cart)
applicable_items = cart.line_items.select { |item| @line_item_selector.nil? || @line_item_selector.match?(item) }
applicable_items.each do |item|
break if @items_to_discount == 0
if !@items_to_discount.nil? && (item.quantity > @items_to_discount)
new_item = item.split({ take: @items_to_discount })
@discount.apply(new_item)
position = cart.line_items.find_index(item)
cart.line_items.insert(position + 1, new_item)
@items_to_discount = 0
else
@discount.apply(item)
@items_to_discount -= item.quantity unless @items_to_discount.nil?
end
end
end
end
CAMPAIGNS = [
ConditionalDiscount.new(
:all, nil, nil,
ProductTypeSelector.new(:does, ["Sale"]),
PercentageDiscount.new(30, "30% off first 2"),
2
),
].freeze
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart)
end
Output.cart = Input.cart识别为 Discount on the first few units,重建为 bxgy 类型的优惠。下面是优惠实际保存时使用的配置键,您可以逐项核对自己的重建结果。
| 设置项 | 值 | 配置键 |
|---|---|---|
| Offer type | bxgy | type |
| Counting | per_variant | counting |
| Recurrence | once | recurrence |
| Tier 1 | min qty 1 -> free item | tiers[0] |
| Buy quantity | 1 | bxgy.buyQty |
| Get quantity | 2 | bxgy.getQty |
| Get selection | same_item | bxgy.getSelection |
| Reward on the get units | 30% off | bxgy.getDiscountPct |
| Free units are additional | false | bxgy.freeUnitsAreAdditional |
| Target scope | product_types | target.scope |
| Target includes | Sale | target.includeIds |
| Method | automatic | discountMethod |
| Allocation | standard | stacking.allocation |
| Combines with other discounts | no | stacking |
- Your Script limited this to a tag, vendor, or product type. We carried that filter over, so confirm it selects the products you expect.
- The unit limit counts per matching group, not per cart line, so a cart with two separate lines can reach the limit twice.
基于我们的公开演示店铺 Meridian Goods 搭建,因此这里的每个价格都可以复现,而不必凭信任接受。下方的折扣金额,是结账时运行的同一个引擎针对这个购物车算出的结果。
- No Meridian Goods product carries the type Sale. Set it on Aria Wireless Earbuds in Shopify before you build the cart, and on nothing else.
| 商品 | 数量 | 单价 |
|---|---|---|
| Aria Wireless Earbuds | 1 | $79.00 |
| 小计 | $79.00 | |
| 折扣 | -$23.70 | |
| 总额 | $55.30 | |
未登录,或以没有标签的客户身份登录。
发布之前,工具会询问您原来的 Script 对一个现有购物车做了什么。把它设为 1 件 Aria Wireless Earbuds,单价 $79.00,答案就是固定的。
折扣金额为 $23.70。顾客实际支付的总额为 $55.30。
比对精确到您所用货币的最小单位。差一分钱,发布就仍然被拦住,这正是这一步的意义。
- swap the cart for a single Braided USB-C Cable
| 商品 | 数量 | 单价 |
|---|---|---|
| Braided USB-C Cable | 1 | $14.00 |
| 小计 | $14.00 | |
| 总额 | $14.00 | |
未登录,或以没有标签的客户身份登录。
Quantity limit cheapest n (D5)
可重建危险配对 D5。这个文件和它的搭档看起来几乎一样,行为却不同,在判断您手上是哪一个之前,请把两份都读一遍。
# GENERATED BY THE SHOPIFY SCRIPT CREATOR APP
class ConditionalDiscount < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, line_item_selector, discount, max_discounts)
super(condition, customer_qualifier, cart_qualifier, line_item_selector)
@discount = discount
@items_to_discount = max_discounts == 0 ? nil : max_discounts
end
def run(cart)
return unless qualifies?(cart)
applicable_items = cart.line_items.select { |item| @line_item_selector.nil? || @line_item_selector.match?(item) }
applicable_items = applicable_items.sort_by { |item| item.variant.price }
applicable_items.each do |item|
break if @items_to_discount == 0
if !@items_to_discount.nil? && (item.quantity > @items_to_discount)
new_item = item.split({ take: @items_to_discount })
@discount.apply(new_item)
position = cart.line_items.find_index(item)
cart.line_items.insert(position + 1, new_item)
@items_to_discount = 0
else
@discount.apply(item)
@items_to_discount -= item.quantity unless @items_to_discount.nil?
end
end
end
end
CAMPAIGNS = [
ConditionalDiscount.new(
:all, nil, nil,
ProductTypeSelector.new(:does, ["Sale"]),
PercentageDiscount.new(30, "30% off your 2 cheapest"),
2
),
].freeze
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart)
end
Output.cart = Input.cart识别为 Discount on the first few units,重建为 bxgy 类型的优惠。下面是优惠实际保存时使用的配置键,您可以逐项核对自己的重建结果。
| 设置项 | 值 | 配置键 |
|---|---|---|
| Offer type | bxgy | type |
| Counting | per_group | counting |
| Recurrence | once | recurrence |
| Tier 1 | min qty 1 -> free item | tiers[0] |
| Buy quantity | 1 | bxgy.buyQty |
| Get quantity | 2 | bxgy.getQty |
| Get selection | cheapest_eligible | bxgy.getSelection |
| Reward on the get units | 30% off | bxgy.getDiscountPct |
| Free units are additional | false | bxgy.freeUnitsAreAdditional |
| Target scope | product_types | target.scope |
| Target includes | Sale | target.includeIds |
| Method | automatic | discountMethod |
| Allocation | standard | stacking.allocation |
| Combines with other discounts | no | stacking |
- Your Script limited this to a tag, vendor, or product type. We carried that filter over, so confirm it selects the products you expect.
- The unit limit counts per matching group, not per cart line, so a cart with two separate lines can reach the limit twice.
基于我们的公开演示店铺 Meridian Goods 搭建,因此这里的每个价格都可以复现,而不必凭信任接受。下方的折扣金额,是结账时运行的同一个引擎针对这个购物车算出的结果。
- No Meridian Goods product carries the type Sale. Set it on Aria Wireless Earbuds and Impact Phone Case in Shopify before you build the cart, and on nothing else.
| 商品 | 数量 | 单价 |
|---|---|---|
| Impact Phone Case | 1 | $24.00 |
| Aria Wireless Earbuds | 1 | $79.00 |
| 小计 | $103.00 | |
| 折扣 | -$30.90 | |
| 总额 | $72.10 | |
未登录,或以没有标签的客户身份登录。
发布之前,工具会询问您原来的 Script 对一个现有购物车做了什么。把它设为 1 件 Impact Phone Case,单价 $24.00,答案就是固定的。
折扣金额为 $7.20。顾客实际支付的总额为 $16.80。
比对精确到您所用货币的最小单位。差一分钱,发布就仍然被拦住,这正是这一步的意义。
- swap the cart for a single Braided USB-C Cable
| 商品 | 数量 | 单价 |
|---|---|---|
| Braided USB-C Cable | 1 | $14.00 |
| 小计 | $14.00 | |
| 总额 | $14.00 | |
未登录,或以没有标签的客户身份登录。
Quantity limit first n discounted (D6)
可重建危险配对 D6。这个文件和它的搭档看起来几乎一样,行为却不同,在判断您手上是哪一个之前,请把两份都读一遍。
DISCOUNT_PERCENTAGE = 30
MAX_UNITS = 2
num_to_discount = MAX_UNITS
Input.cart.line_items.each_with_index do |line_item, position|
break if num_to_discount <= 0
next unless line_item.variant.product.tags.include?("limited")
if line_item.quantity > num_to_discount
split_line_item = line_item.split(take: num_to_discount)
Input.cart.line_items.insert(position + 1, split_line_item)
line_item = split_line_item
end
line_item.change_line_price(
line_item.line_price * (1.0 - (DISCOUNT_PERCENTAGE / 100.0)),
message: "30% off your first 2"
)
num_to_discount -= line_item.quantity
end
Output.cart = Input.cart识别为 Discount on the first few units,重建为 bxgy 类型的优惠。下面是优惠实际保存时使用的配置键,您可以逐项核对自己的重建结果。
| 设置项 | 值 | 配置键 |
|---|---|---|
| Offer type | bxgy | type |
| Counting | per_variant | counting |
| Recurrence | once | recurrence |
| Tier 1 | min qty 1 -> free item | tiers[0] |
| Buy quantity | 1 | bxgy.buyQty |
| Get quantity | 2 | bxgy.getQty |
| Get selection | same_item | bxgy.getSelection |
| Reward on the get units | 30% off | bxgy.getDiscountPct |
| Free units are additional | false | bxgy.freeUnitsAreAdditional |
| Target scope | tags | target.scope |
| Target includes | limited | target.includeIds |
| Method | automatic | discountMethod |
| Allocation | standard | stacking.allocation |
| Combines with other discounts | no | stacking |
- Your Script limited this to a tag, vendor, or product type. We carried that filter over, so confirm it selects the products you expect.
- The unit limit counts per matching group, not per cart line, so a cart with two separate lines can reach the limit twice.
基于我们的公开演示店铺 Meridian Goods 搭建,因此这里的每个价格都可以复现,而不必凭信任接受。下方的折扣金额,是结账时运行的同一个引擎针对这个购物车算出的结果。
- No Meridian Goods product carries the tag limited. Set it on Aria Wireless Earbuds in Shopify before you build the cart, and on nothing else.
| 商品 | 数量 | 单价 |
|---|---|---|
| Aria Wireless Earbuds | 1 | $79.00 |
| 小计 | $79.00 | |
| 折扣 | -$23.70 | |
| 总额 | $55.30 | |
未登录,或以没有标签的客户身份登录。
发布之前,工具会询问您原来的 Script 对一个现有购物车做了什么。把它设为 1 件 Aria Wireless Earbuds,单价 $79.00,答案就是固定的。
折扣金额为 $23.70。顾客实际支付的总额为 $55.30。
比对精确到您所用货币的最小单位。差一分钱,发布就仍然被拦住,这正是这一步的意义。
- swap the cart for a single Braided USB-C Cable
| 商品 | 数量 | 单价 |
|---|---|---|
| Braided USB-C Cable | 1 | $14.00 |
| 小计 | $14.00 | |
| 总额 | $14.00 | |
未登录,或以没有标签的客户身份登录。
两个看起来一样的文件
下面每一对都是同一种 Script 写法的两个版本。它们只差一两行,效果却不同,所以在判断自己手上是哪一个之前,请把两个都读一遍。
危险配对 D5
Quantity limit first n discounted (D5)
可重建重建为 bxgy 优惠。
在它自己的购物车中的折扣:$23.70
PercentageDiscount.new(30, "30% off first 2"),Quantity limit cheapest n (D5)
可重建重建为 bxgy 优惠。
在它自己的购物车中的折扣:$30.90
applicable_items = applicable_items.sort_by { |item| item.variant.price }
PercentageDiscount.new(30, "30% off your 2 cheapest"),危险配对 D6
Quantity limit first n discounted (D6)
可重建重建为 bxgy 优惠。
在它自己的购物车中的折扣:$23.70
DISCOUNT_PERCENTAGE = 30
MAX_UNITS = 2
num_to_discount = MAX_UNITS
Input.cart.line_items.each_with_index do |line_item, position|
break if num_to_discount <= 0
next unless line_item.variant.product.tags.include?("limited")另有 9 行差异,在它自己的页面上。
Quantity limit purchase cap (D6)
另一种 Shopify API不会重建。This needs a different kind of Shopify app
# GENERATED BY THE SHOPIFY SCRIPT CREATOR APP
class QuantityLimit < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, line_item_selector, limit_by, limit)
super(condition, customer_qualifier, cart_qualifier, line_item_selector)
@limit_by = limit_by
@limit = limit另有 26 行差异,在它自己的页面上。
常见问题
- Will Stackable rebuild this script?
- Yes. Every spelling on this page is rebuilt today as a bxgy offer, and the cart above is the one that proves it.
- What cart proves it works?
- 1 x Aria Wireless Earbuds at $79.00. The engine takes $23.70 off, and checkout charges $55.30.
- What will I have to check before publishing?
- Your Script limited this to a tag, vendor, or product type. We carried that filter over, so confirm it selects the products you expect. The unit limit counts per matching group, not per cart line, so a cart with two separate lines can reach the limit twice.
相关的 Script 类型
A cap on how many units a shopper could buy, enforced by trimming the cart.
A set of paid units earns an extra unit at no charge.
The same buy-and-get offer, counted so the reward sits inside each set rather than beside it.