Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # GENERATED BY THE SHOPIFY SCRIPT CREATOR APP
- 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 TieredDiscount < Campaign
- def initialize(condition, customer_qualifier, cart_qualifier, line_item_selector, discount_type, tier_type, discount_tiers)
- super(condition, customer_qualifier, cart_qualifier)
- @line_item_selector = line_item_selector
- @discount_type = discount_type
- @tier_type = tier_type
- @discount_tiers = discount_tiers.sort_by {|tier| tier[:discount].to_f }
- end
- def init_discount(amount, message)
- case @discount_type
- when :fixed
- return FixedTotalDiscount.new(amount, message, :split)
- when :percent
- return PercentageDiscount.new(amount, message)
- when :per_item
- return FixedItemDiscount.new(amount, message)
- end
- end
- def run(cart)
- return unless qualifies?(cart)
- applicable_items = cart.line_items.select { |item| @line_item_selector.nil? || @line_item_selector.match?(item) }
- case @tier_type
- when :customer_tag
- return if cart.customer.nil?
- customer_tags = cart.customer.tags.map(&:downcase)
- qualified_tiers = @discount_tiers.select { |tier| customer_tags.include?(tier[:tier].downcase) }
- when :cart_subtotal
- cart_total = cart.subtotal_price
- qualified_tiers = @discount_tiers.select { |tier| cart_total >= Money.new(cents: tier[:tier].to_i * 100) }
- when :discountable_total
- discountable_total = applicable_items.reduce(Money.zero) { |total, item| total + item.line_price }
- qualified_tiers = @discount_tiers.select { |tier| discountable_total >= Money.new(cents: tier[:tier].to_i * 100) }
- when :discountable_total_items
- discountable_quantity = applicable_items.reduce(0) { |total, item| total + item.quantity }
- qualified_tiers = @discount_tiers.select { |tier| discountable_quantity >= tier[:tier].to_i }
- when :cart_items
- cart_quantity = cart.line_items.reduce(0) { |total, item| total + item.quantity }
- qualified_tiers = @discount_tiers.select { |tier| cart_quantity >= tier[:tier].to_i }
- end
- if @tier_type == :line_quantity
- applicable_items.each do |item|
- qualified_tiers = @discount_tiers.select { |tier| item.quantity >= tier[:tier].to_i }
- next if qualified_tiers.empty?
- discount_amount = qualified_tiers.last[:discount].to_f
- discount_message = qualified_tiers.last[:message]
- discount = init_discount(discount_amount, discount_message)
- discount.apply(item)
- discount.apply_final_discount if discount.respond_to?(:apply_final_discount)
- end
- else
- return if qualified_tiers.empty?
- discount_amount = qualified_tiers.last[:discount].to_f
- discount_message = qualified_tiers.last[:message]
- @discount = init_discount(discount_amount, discount_message)
- applicable_items.each { |item| @discount.apply(item) }
- end
- 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
- class FixedTotalDiscount
- def initialize(amount, message, behaviour = :to_zero)
- @amount = Money.new(cents: amount * 100)
- @message = message
- @discount_applied = Money.zero
- @all_items = []
- @is_split = behaviour == :split
- end
- def apply(line_item)
- if @is_split
- @all_items << line_item
- else
- return unless @discount_applied < @amount
- discount_to_apply = [(@amount - @discount_applied), line_item.line_price].min
- line_item.change_line_price(line_item.line_price - discount_to_apply, {message: @message})
- @discount_applied += discount_to_apply
- end
- end
- def apply_final_discount
- return if @all_items.length == 0
- total_items = @all_items.length
- total_quantity = 0
- total_cost = Money.zero
- @all_items.each do |item|
- total_quantity += item.quantity
- total_cost += item.line_price
- end
- @all_items.each_with_index do |item, index|
- discount_percent = item.line_price.cents / total_cost.cents
- if total_items == index + 1
- discount_to_apply = Money.new(cents: @amount.cents - @discount_applied.cents.floor)
- else
- discount_to_apply = Money.new(cents: @amount.cents * discount_percent)
- end
- item.change_line_price(item.line_price - discount_to_apply, {message: @message})
- @discount_applied += discount_to_apply
- end
- end
- end
- class FixedItemDiscount
- def initialize(amount, message)
- @amount = Money.new(cents: amount * 100)
- @message = message
- end
- def apply(line_item)
- per_item_price = line_item.variant.price
- per_item_discount = [(@amount - per_item_price), @amount].max
- discount_to_apply = [(per_item_discount * line_item.quantity), line_item.line_price].min
- line_item.change_line_price(line_item.line_price - discount_to_apply, {message: @message})
- 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 CustomerTagQualifier < Qualifier
- def initialize(match_type, match_condition, tags)
- @match_condition = match_condition
- @invert = match_type == :does_not
- @tags = tags.map(&:downcase)
- end
- def match?(cart, selector = nil)
- return true if cart.customer.nil? && @invert
- return false if cart.customer.nil?
- customer_tags = cart.customer.tags.to_a.map(&:downcase)
- case @match_condition
- when :match
- return @invert ^ ((@tags & customer_tags).length > 0)
- else
- return @invert ^ partial_match(@match_condition, customer_tags, @tags)
- 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 ProductTypeSelector < Selector
- def initialize(match_type, product_types)
- @invert = match_type == :not_one
- @product_types = product_types.map(&:downcase)
- end
- def match?(line_item)
- @invert ^ @product_types.include?(line_item.variant.product.product_type.downcase)
- end
- end
- CAMPAIGNS = [
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 400
- ),
- ProductTypeSelector.new(
- :is_one,
- ["ratcat"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "ratcat", :discount => "29", :message => "$400 column pricing -RatCAT"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 400
- ),
- ProductTypeSelector.new(
- :is_one,
- ["cabletester"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "cabletesters", :discount => "29", :message => "$400 column pricing - Testers"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 400
- ),
- ProductTypeSelector.new(
- :is_one,
- ["cable"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "cable", :discount => "15", :message => "$400 column pricing - cable"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 400
- ),
- ProductTypeSelector.new(
- :is_one,
- ["essentials"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "essentials", :discount => "25", :message => "$400 column pricing - essentials"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 2500
- ),
- ProductTypeSelector.new(
- :is_one,
- ["ratcat"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "ratcat", :discount => "39", :message => "$2500 column pricing -RatCAT"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 2500
- ),
- ProductTypeSelector.new(
- :is_one,
- ["cabletester"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "cabletesters", :discount => "39", :message => "$2500 column pricing - Testers"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 2500
- ),
- ProductTypeSelector.new(
- :is_one,
- ["cable"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "cable", :discount => "25", :message => "$2500 column pricing - cable"}]
- ),
- TieredDiscount.new(
- :all,
- CustomerTagQualifier.new(
- :does,
- :match,
- ["flexdealer"]
- ),
- CartAmountQualifier.new(
- :cart,
- :greater_than_or_equal,
- 2500
- ),
- ProductTypeSelector.new(
- :is_one,
- ["essentials"]
- ),
- :percent,
- :cart_subtotal,
- [{:tier => "essentials", :discount => "25", :message => "$2500 column pricing - essentials"}]
- )
- ].freeze
- CAMPAIGNS.each do |campaign|
- campaign.run_with_hooks(Input.cart)
- end
- Output.cart = Input.cart
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement