Created
May 25, 2022 21:29
-
-
Save CrowderSoup/1c302af65beed3c302c7d591e3d3636f to your computer and use it in GitHub Desktop.
Disable discount codes for orders containing gift cards
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ConditionalDiscountCodeRejection < Campaign | |
def initialize(condition, customer_qualifier, cart_qualifier, li_match_type, line_item_qualifier, message) | |
super(condition, customer_qualifier, cart_qualifier, line_item_qualifier) | |
@li_match_type = (li_match_type.to_s + '?').to_sym | |
@message = message == "" ? "This discount code cannot be used at this time" : message | |
end | |
def run(cart) | |
return unless cart.discount_code | |
cart.discount_code.reject({message: @message}) if qualifies?(cart) | |
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 CartHasItemQualifier < Qualifier | |
def initialize(quantity_or_subtotal, comparison_type, amount, item_selector) | |
@quantity_or_subtotal = quantity_or_subtotal | |
@comparison_type = comparison_type | |
@amount = quantity_or_subtotal == :subtotal ? Money.new(cents: amount * 100) : amount | |
@item_selector = item_selector | |
end | |
def match?(cart, selector = nil) | |
raise "Must supply an item selector for the #{self.class}" if @item_selector.nil? | |
case @quantity_or_subtotal | |
when :quantity | |
total = cart.line_items.reduce(0) do |total, item| | |
total + (@item_selector&.match?(item) ? item.quantity : 0) | |
end | |
when :subtotal | |
total = cart.line_items.reduce(Money.zero) do |total, item| | |
total + (@item_selector&.match?(item) ? item.line_price : Money.zero) | |
end | |
end | |
compare_amounts(total, @comparison_type, @amount) | |
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 ProductTagSelector < Selector | |
def initialize(match_type, match_condition, tags) | |
@match_condition = match_condition | |
@invert = match_type == :does_not | |
@tags = tags.map(&:downcase) | |
end | |
def match?(line_item) | |
product_tags = line_item.variant.product.tags.to_a.map(&:downcase) | |
case @match_condition | |
when :match | |
return @invert ^ ((@tags & product_tags).length > 0) | |
else | |
return @invert ^ partial_match(@match_condition, product_tags, @tags) | |
end | |
end | |
end | |
CAMPAIGNS = [ | |
ConditionalDiscountCodeRejection.new( | |
:all, | |
nil, | |
CartHasItemQualifier.new( | |
:quantity, | |
:greater_than, | |
0, | |
ProductTagSelector.new( | |
:does, | |
:match, | |
["Govalo Gift Card (Do Not Delete)"] | |
) | |
), | |
:any, | |
nil, | |
"Discount codes cannot be used on orders with gift cards." | |
) | |
].freeze | |
CAMPAIGNS.each do |campaign| | |
campaign.run_with_hooks(Input.cart) | |
end | |
Output.cart = Input.cart |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment