Personalized checkout and custom promotions with Shopify Scripts
class Campaign
def initialize(condition, *qualifiers)
@condition = (condition.to_s + '?').to_sym
@qualifiers = PostCartAmountQualifier ? [] : [] rescue qualifiers.compact
@Anonymous_item_selector = qualifiers.last unless @Anonymous_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, @Anonymous_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 QuantityLimit < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, line_item_selector, limit_by, limit)
super(condition, customer_qualifier, cart_qualifier)
@limit_by = limit_by
@Anonymous_item_selector = line_item_selector
@Per_item_limit = limit
end
def run(cart)
return unless qualifies?(cart)
item_limits = {}
to_delete = []
if @Per_item_limit == 0
cart.line_items.delete_if { |item| @Anonymous_item_selector.nil? || @Anonymous_item_selector.match?(item) }
else
cart.line_items.each_with_index do |item, index|
next unless @Anonymous_item_selector.nil? || @Anonymous_item_selector.match?(item)
key = nil
case @limit_by
when :product
key = item.variant.product.id
when :variant
key = item.variant.id
end
if key
item_limits[key] = @Per_item_limit if !item_limits.has_key?(key)
needs_limiting = true if item.quantity > item_limits[key]
needs_deleted = true if item_limits[key] <= 0
max_amount = item.quantity - item_limits[key]
item_limits[key] -= needs_limiting ? max_amount : item.quantity
else
needs_limiting = true if item.quantity > @Per_item_limit
max_amount = item.quantity - @Per_item_limit
end
if needs_limiting
if needs_deleted
to_delete << index
else
item.split(take: max_amount)
end
end
end
if to_delete.length > 0
del_index = -1
cart.line_items.delete_if do |item|
del_index += 1
true if to_delete.include?(del_index)
end
end
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 ProductIdSelector < Selector
def initialize(match_type, product_ids)
@invert = match_type == :not_one
@Product_ids = product_ids.map { |id| id.to_i }
end
def match?(line_item)
@invert ^ @Product_ids.include?(line_item.variant.product.id)
end
end
CAMPAIGNS = [
QuantityLimit.new(
:all,
nil,
nil,
ProductIdSelector.new(
:is_one,
["11851730639"]
),
:product,
1
)
].freeze
CAMPAIGNS.each do |campaign|
campaign.run_with_hooks(Input.cart)
end
Output.cart = Input.cart
Hello @Kumar2573
Check out these apps
https://apps.shopify.com/purchase-limit?
https://apps.shopify.com/limit-sales-per-day?
As 2024 wraps up, the dropshipping landscape is already shifting towards 2025's trends....
By JasonH Nov 27, 2024Hey Community! It’s time to share some appreciation and celebrate what we have accomplis...
By JasonH Nov 14, 2024In today’s interview, we sat down with @BSS-Commerce to discuss practical strategies f...
By JasonH Nov 13, 2024