Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save shopifypartners/46cbf42bd0c0b25ec69111fadf698457 to your computer and use it in GitHub Desktop.
Save shopifypartners/46cbf42bd0c0b25ec69111fadf698457 to your computer and use it in GitHub Desktop.
################################################################################
# Buy set, get X% off discount script.
#
# This script allows the running of a campaign to give customers X% off a "set"
# of items, if and only if they purchase at least one of each item in the set.
#
# The discount is applied only to all items in the set in the cart.
#
# Written by Gavin Ballard (gavin@discolabs.com)
################################################################################
################################################################################
# START CUSTOMISATION SECTION
#
# You can customise the variables here at the top of the script to adjust the
# products the campaign applies and the message customers will see in their cart
# and at checkout.
################################################################################
# Defines a list of the products that are in the set. Customers will need to
# purchase at least one of each product with this tag to be eligible for the
# discount. Setting this as an empty list (`[]`) will effectively turn off this
# campaign.
PRODUCTS_IN_SET = []
# Set the percentage discount that should be applied if the customer has all
# products in the set in their cart. Will *only* apply to the products in the
# set themselves - other items in the cart won't be affected.
DISCOUNT_PERCENT = 10
# Set the message that will be displayed to customers in their cart and at
# checkout to let them know their discount has been applied.
DISCOUNT_MESSAGE = "#{DISCOUNT_PERCENT}% off for purchasing the set!"
################################################################################
# END CUSTOMISATION SECTION
#
# You shouldn't need to edit anything below this line, unless you're a developer
# and know what you're doing :).
################################################################################
# The campaign class.
class BuySetGetXOffCampaign
def initialize(selector, discount, partitioner)
@selector = selector
@discount = discount
@partitioner = partitioner
end
def run(cart)
applicable_items = cart.line_items.select do |line_item|
@selector.match?(line_item)
end
discounted_items = @partitioner.partition(cart, applicable_items)
discounted_items.each do |line_item|
@discount.apply(line_item)
end
end
end
# Select line items by product id.
class ProductsSelector
def initialize(product_ids)
@product_ids = Array(product_ids)
end
def match?(line_item)
@product_ids.include?(line_item.variant.product.id)
end
end
# Apply a percentage discount to a line item.
class PercentageDiscount
def initialize(percent, message)
@percent = Decimal.new(percent) / 100.0
@message = message
end
def apply(line_item)
line_discount = line_item.line_price * @percent
new_line_price = line_item.line_price - line_discount
line_item.change_line_price(new_line_price, message: @message)
puts "Discounted line item with variant #{line_item.variant.id} by #{line_discount}."
end
end
class ProductSetPartitioner
def initialize(set_product_ids)
@set_product_ids = set_product_ids
end
def partition(cart, applicable_line_items)
# If all items in the product set are in the cart, then all applicable line
# items are eligible for the discount. Otherwise, none of them are.
cart_product_ids = cart.line_items.map { |line_item| line_item.variant.product.id }.uniq
if (@set_product_ids - cart_product_ids).empty?
applicable_line_items
else
[]
end
end
end
# List of campaigns.
CAMPAIGNS = [
BuySetGetXOffCampaign.new(
ProductsSelector.new(PRODUCTS_IN_SET),
PercentageDiscount.new(DISCOUNT_PERCENT, DISCOUNT_MESSAGE),
ProductSetPartitioner.new(PRODUCTS_IN_SET)
)
]
# Apply all defined campaiagns to the cart.
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart)
end
# Export changes.
Output.cart = Input.cart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment