Access a community of over 900,000 Shopify Merchants and Partners and engage in meaningful conversations with your peers.
Hi all,
I am fairly new to Shopify scripts and I was able to create 2 scripts that help me solve my problem. But as I was publishing them, I just found out I can't have multiple scripts running at once for the same type, so I would love to get someone's help with this.
Some of my products are tagged with "status-special-order" and require 10-15 business days to ship, while all other items are in stock and available to ship within 1 business day.
When a user adds both stocked item(s) AND special order items, I want to show these (2) specific shipping rates so the user can pick one of these options:
- Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.
- Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint.
I was able to tweak an existing Shopify script so I would see these options, and it would hide all of my other custom and carrier shipping rates whenever a special order item is in the cart. However I would like to hide these (2) shipping rates (listed above) when there is no special order item in the cart.
I wish I could just add another condition somewhere saying that if the product tag "status-special-order" is not included, then it should hide the (2) custom shipping rates I listed higher in my message.
Any help would be very much appreciated!
Thank you!
HIDE_RATES_FOR_PRODUCT = [
{
product_selector_match_type: :include,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost
","Priority"],
},
]
# ================================================================
# 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?'
_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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_RATES_FOR_PRODUCT),
]
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
Solved! Go to the solution
This is an accepted solution.
Good catch. I've modified the script below. It requires an extra loop through the shipping rates, but not too bad.
HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER = [
{
product_selector_match_type: :include,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority"],
},
]
HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER = [
{
product_selector_match_type: :exclude,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."],
},
]
# ================================================================
# 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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
campaign_satisified = false
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.each do |shipping_rate|
if rate_name_selector.match?(shipping_rate)
campaign_satisified = true
end
end
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
return campaign_satisified
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER),
HideRatesForProduct.new(HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER)
]
CAMPAIGNS.each do |campaign|
break if campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
This is an accepted solution.
Again, check your exact shipping names to make sure they are the same, but I've added a new parameter called product_selector_match_scope that can take "any" or "all" as values:
HIDE_RATES_FOR_ONLY_SPECIAL_ORDER = [
{
product_selector_match_type: :include,
product_selector_match_scope: :all,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority","Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."],
},
]
HIDE_RATES_FOR_MIXED_ORDER = [
{
product_selector_match_type: :include,
product_selector_match_scope: :any,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority","Free Shipping: special order items usually take 10 to 15 business days."],
},
]
HIDE_RATES_FOR_STOCK_ORDER = [
{
product_selector_match_type: :exclude,
product_selector_match_scope: :any,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint.","Free Shipping: special order items usually take 10 to 15 business days."],
},
]
# ================================================================
# 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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
campaign_satisified = false
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
if campaign[:product_selector_match_scope] == :all
product_match = cart.line_items.all? { |line_item| product_selector.match?(line_item) }
else
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
end
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.each do |shipping_rate|
if rate_name_selector.match?(shipping_rate)
campaign_satisified = true
end
end
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
return campaign_satisified
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_RATES_FOR_ONLY_SPECIAL_ORDER),
HideRatesForProduct.new(HIDE_RATES_FOR_MIXED_ORDER),
HideRatesForProduct.new(HIDE_RATES_FOR_STOCK_ORDER)
]
CAMPAIGNS.each do |campaign|
break if campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
Let me know if that works as expected!
Matthew
Hi @M0w45,
I haven't been able to test this (since it would require setting up products and shipping configuration like yours), but I think a small modification could make this work. Being able to create multiple rules in the same script is one of the reasons I work on apps like Playwright. Anyway, onto your script...
You may need to adjust the exact names of the shipping methods if they do not match your shipping configuration. Try this updated script and let me know if it works for you:
HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER = [
{
product_selector_match_type: :include,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority"],
},
]
HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER = [
{
product_selector_match_type: :exclude,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."],
},
]
# ================================================================
# 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?'
_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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER),
HideRatesForProduct.new(HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER)
]
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
I hope that is helpful,
Matthew
Hi @playwright-matt ,
Thank you so much for your quick reply, much appreciated!
I was able to test your script, and corrected line 29 to replace
_type = selector_type
with
@selector_type = selector_type
It's almost perfect :D.
I tested the (3) scenarios:
- When there is a special order item: I do see the (2) shipping rates available. It works.
- When there isn't a special order item: I do see all other shipping rates but the (2) for Special Order Items. It works.
- When there is both a stocked item and a special order item: I do not see any shipping rate listed. I checked my shipping rates and they all apply to QC. I am wondering how I can tweak your code to make this work.
I don't want to be a pain, but I would love to hear your thoughts on this.
Thank you!
This is an accepted solution.
Good catch. I've modified the script below. It requires an extra loop through the shipping rates, but not too bad.
HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER = [
{
product_selector_match_type: :include,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority"],
},
]
HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER = [
{
product_selector_match_type: :exclude,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."],
},
]
# ================================================================
# 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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
campaign_satisified = false
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.each do |shipping_rate|
if rate_name_selector.match?(shipping_rate)
campaign_satisified = true
end
end
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
return campaign_satisified
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_STANDARD_RATES_FOR_SPECIAL_ORDER),
HideRatesForProduct.new(HIDE_SPECIAL_FREE_RATES_WHEN_NO_SPECIAL_ORDER)
]
CAMPAIGNS.each do |campaign|
break if campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
@playwright-matt , thank you very much!
Just tried it and it works like a charm 🙂
@playwright-matt , I am sorry to ask you this, but I figured I could pick your brain 🙂
Is there a way to add an extra loop somewhere so that if there is only (1) special order item, or multiple special order items in the cart, it shows a different shipping rate?
As of right now, with at least one special order item and at least one stocked item, it works just fine and shows both options:
"Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."
With only stocked items in the cart, it works just fine as well and shows all shipping rates but the (2) listed above:
["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority"]
With 1 or + special order item (and no stocked items), it shows both options:
["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."]
Since the cart only special order items, I'm thinking having only one option showing, which could be a different message showing (i.e: "Free Shipping: special order items usually take 10 to 15 business days" or something similar).
Again, you already helped me a lot here, but if there is any chance you have a solution, it would be more than appreciated.
Thank you!
This is an accepted solution.
Again, check your exact shipping names to make sure they are the same, but I've added a new parameter called product_selector_match_scope that can take "any" or "all" as values:
HIDE_RATES_FOR_ONLY_SPECIAL_ORDER = [
{
product_selector_match_type: :include,
product_selector_match_scope: :all,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority","Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint."],
},
]
HIDE_RATES_FOR_MIXED_ORDER = [
{
product_selector_match_type: :include,
product_selector_match_scope: :any,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping (Regular)","$5.99 Flat Rate","Expedited Parcel","Xpresspost","Priority","Free Shipping: special order items usually take 10 to 15 business days."],
},
]
HIDE_RATES_FOR_STOCK_ORDER = [
{
product_selector_match_type: :exclude,
product_selector_match_scope: :any,
product_selector_type: :tag,
product_selectors: ["status-special-order"],
rate_match_type: :exact,
rate_names: ["Free Shipping: I'm in a rush. Send me stocked item(s) now, and special item(s) when available.","Free Shipping: I'm in no rush. I can wait for all items to be available and help offset carbon footprint.","Free Shipping: special order items usually take 10 to 15 business days."],
},
]
# ================================================================
# 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
end
# ================================================================
# RateNameSelector
# Finds whether the supplied rate names match any of the entered names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@match_type = match_type
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
if @match_type == :all
true
else
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
end
# ================================================================
# HideRatesForProduct
# If the cart contains any matching items, the entered rate(s) are hidden.
# ================================================================
class HideRatesForProduct
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
address = cart.shipping_address
campaign_satisified = false
return if address.nil?
@campaigns.each do |campaign|
product_selector = ProductSelector.new(
campaign[:product_selector_match_type],
campaign[:product_selector_type],
campaign[:product_selectors],
)
if campaign[:product_selector_match_scope] == :all
product_match = cart.line_items.all? { |line_item| product_selector.match?(line_item) }
else
product_match = cart.line_items.any? { |line_item| product_selector.match?(line_item) }
end
next unless product_match
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names],
)
shipping_rates.each do |shipping_rate|
if rate_name_selector.match?(shipping_rate)
campaign_satisified = true
end
end
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate)
end
end
return campaign_satisified
end
end
CAMPAIGNS = [
HideRatesForProduct.new(HIDE_RATES_FOR_ONLY_SPECIAL_ORDER),
HideRatesForProduct.new(HIDE_RATES_FOR_MIXED_ORDER),
HideRatesForProduct.new(HIDE_RATES_FOR_STOCK_ORDER)
]
CAMPAIGNS.each do |campaign|
break if campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
Let me know if that works as expected!
Matthew
User | RANK |
---|---|
2 | |
2 | |
1 | |
1 | |
1 |