Personalized checkout and custom promotions with Shopify Scripts
Hi there,
I am using the Bundle Discount on the Script Editor where there are two products within a bundle and if the user picks both, they get 20% off each. The discount should only work if you have the same quantity of each product. The problem is that if I pick e.g. 3 x leggings and 1 x sports bra, the script puts a discount on all 3 leggings. It should only apply to 1 x leggings because the sports bra is also 1. If there is 3 x leggings and 3 x sports bra - then that's fine.
The users should still be able to add as many products as they want, but without getting a discount on it.
I have looked into other posts in the community but I couldn't find anyone posting about the same issue as mine. I would REALLY appreciate any help, thanks!
This is the code generated from the Script Editor:
class Campaign def initialize(condition, *qualifiers) @condition = (condition.to_s + '?').to_sym @qualifiers = PostCartAmountQualifier ? [] : [] rescue qualifiers.compact @line_item_selector = qualifiers.last unless @line_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) { |item| qualifier.match?(item) } else qualifier.match?(cart, @line_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 BundleDiscount < Campaign def initialize(condition, customer_qualifier, cart_qualifier, discount, full_bundles_only, bundle_products) super(condition, customer_qualifier, cart_qualifier, nil) @bundle_products = bundle_products @discount = discount @full_bundles_only = full_bundles_only @split_items = [] @bundle_items = [] end def check_bundles(cart) bundled_items = @bundle_products.map do |bitem| quantity_required = bitem[:quantity].to_i qualifiers = bitem[:qualifiers] type = bitem[:type].to_sym case type when :ptype items = cart.line_items.select { |item| qualifiers.include?(item.variant.product.product_type) && !item.discounted? } when :ptag items = cart.line_items.select { |item| (qualifiers & item.variant.product.tags).length > 0 && !item.discounted? } when :pid qualifiers.map!(&:to_i) items = cart.line_items.select { |item| qualifiers.include?(item.variant.product.id) && !item.discounted? } when :vid qualifiers.map!(&:to_i) items = cart.line_items.select { |item| qualifiers.include?(item.variant.id) && !item.discounted? } when :vsku items = cart.line_items.select { |item| (qualifiers & item.variant.skus).length > 0 && !item.discounted? } end total_quantity = items.reduce(0) { |total, item| total + item.quantity } { has_all: total_quantity >= quantity_required, total_quantity: total_quantity, quantity_required: quantity_required, total_possible: (total_quantity / quantity_required).to_i, items: items } end max_bundle_count = bundled_items.map{ |bundle| bundle[:total_possible] }.min if @full_bundles_only if bundled_items.all? { |item| item[:has_all] } if @full_bundles_only bundled_items.each do |bundle| bundle_quantity = bundle[:quantity_required] * max_bundle_count split_out_extra_quantity(cart, bundle[:items], bundle[:total_quantity], bundle_quantity) end else bundled_items.each do |bundle| bundle[:items].each do |item| @bundle_items << item cart.line_items.delete(item) end end end return true end false end def split_out_extra_quantity(cart, items, total_quantity, quantity_required) items_to_split = quantity_required items.each do |item| break if items_to_split == 0 if item.quantity > items_to_split @bundle_items << item.split({take: items_to_split}) @split_items << item items_to_split = 0 else @bundle_items << item split_quantity = item.quantity items_to_split -= split_quantity end cart.line_items.delete(item) end cart.line_items.concat(@split_items) @split_items.clear end def run(cart) raise "Campaign requires a discount" unless @discount return unless qualifies?(cart) if check_bundles(cart) @bundle_items.each { |item| @discount.apply(item) } end @bundle_items.reverse.each { |item| cart.line_items.prepend(item) } end end class PercentageDiscount def initialize(percent, message) @discount = (100 - percent) / 100.0 @message = message end def apply(line_item) line_item.change_line_price(line_item.line_price * @discount, message: @message) end end CAMPAIGNS = [ BundleDiscount.new( :all, nil, nil, PercentageDiscount.new( 20, "Discount applied!" ), false, [{:type => "pid", :qualifiers => ["2631121043556","2631126679652"], :quantity => "1"}, {:type => "pid", :qualifiers => ["2631125827684","2631125860452"], :quantity => "1"}] ) ].freeze CAMPAIGNS.each do |campaign| campaign.run_with_hooks(Input.cart) end Output.cart = Input.cart
Hey Community! As we jump into 2025, we want to give a big shout-out to all of you wh...
By JasonH Jan 7, 2025Hey Community! As the holiday season unfolds, we want to extend heartfelt thanks to a...
By JasonH Dec 6, 2024Dropshipping, a high-growth, $226 billion-dollar industry, remains a highly dynamic bus...
By JasonH Nov 27, 2024