Hey all, my goal here is to display an error message and not apply a coupon if this script has been activated.
Instead what is happening is when a coupon is entered it's cancelling the script and applying the coupon and reverting the line item prices back to their original prices?
Anyone know what I need to change here?
case Input.cart.discount_code
when CartDiscount::Percentage
if Line_items.quantity > 1
Input.cart.discount_code.reject(message: "Coupons can not be combined with BOGO promotion")
end
end
class BogoCampaign
# Initializes the campaign.
#
# Arguments
# ---------
#
# * selector
# The selector finds eligible items for this campaign.
#
# * discount
# The discount changes the prices of the items returned by the partitioner.
#
# * partitioner
# The partitioner takes all applicable items, and returns only those that
# are to be discounted. In a "Buy two items, get the third for free"
# campaign, the partitioner would skip two items and return the third item.
#
def initialize(selector, discount, partitioner)
@selector = selector
@discount = discount
@partitioner = partitioner
end
# Runs the campaign on the given cart.
#
# Arguments
# ---------
#
# * cart
# The cart to which the campaign is applied.
#
# Example
# -------
# To run the campaign on the input cart:
#
# campaign.run(Input.cart)
#
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
# TagSelector
# ============
#
# The `TagSelector` selects items by tag.
#
# Example
# -------
# * Items where the variant has "sale" tag
#
class TagSelector
# Initializes the selector.
#
# Arguments
# ---------
#
# * tag
# The tag that the selector will look for in the item.
def initialize(tag)
@tag = tag
end
# Returns whether a line item matches this selector or not.
#
# Arguments
# ---------
#
# * line_item
# The item to check for matching.
#
# Example
# -------
# Given `TagSelector.new("sale")` and
# a line_item with a variant with tags = ["sale", "boat", "hat"]
#
# selector.match?(line_item) # returns true
#
def match?(line_item)
line_item.variant.product.tags.include?(@tag)
end
end
# PercentageDiscount
# ==================
#
# The `PercentageDiscount` gives percentage discounts to item prices.
#
# Example
# -------
# * 15% off
#
class PercentageDiscount
# Initializes the discount.
#
# Arguments
# ---------
#
# * percent
# The percentage by which the item will be discounted.
#
# * message
# The message to show for the discount.
#
def initialize(percent, message)
# Calculate the percentage, while ensuring that Decimal values are used in
# order to maintain precision.
@percent = Decimal.new(percent) / 100.0
@message = message
end
# Applies the discount on a line item.
#
# Arguments
# ---------
#
# * line_item
# The item on which the discount will be applied.
#
# Example
# -------
# Given `PercentageDiscount.new(10, "Great discount")` and the following line item:
#
# * Quantity = 2, Price = 10
#
# The discount will give $1 off per quantity, for a total of $2 off.
#
def apply(line_item)
# Calculate the discount for this line item
line_discount = line_item.line_price * @percent
# Calculated the discounted line price
new_line_price = line_item.line_price - line_discount
# Apply the new line price to this line item with a given message
# describing the discount, which may be displayed in cart pages and
# confirmation emails to describe the applied discount.
line_item.change_line_price(new_line_price, message: @message)
# Print a debugging line to the console
puts "Discounted line item with variant #{line_item.variant.id} by #{line_discount}."
end
end
# LowToHighPartitioner
# ====================
#
# The `LowToHighPartitioner` is used by campaigns for which not all items
# are discounted, such as `BogoCampaign`. It tries to discount items so that
# the cheaper items are prioritized for discounting.
#
# Example
# -------
# Given `LowToHighPartitioner.new(2,1)` and a cart containing the following
# line items:
#
# * (A) Quantity = 2, Price = 5
# * (B) Quantity = 3, Price = 10
#
# The partitioner will:
#
# * Sort them by ascending price (A, B)
# * Count the total items to be discounted (1)
# * Take 1 of A to be discounted
#
# The items to be discounted will be (before discount):
#
# * (A) Quantity = 1, Price = 5
#
class LowToHighPartitioner
# Initializes the partitioner.
#
# Arguments
# ---------
#
# * paid_item_count
# The number of items to skip before selecting items to discount.
#
# * discounted_item_count
# The number of items to return for discounting.
#
# Example
# -------
# To create a campaign such as "Buy two, the 3rd item is discounted"
#
# LowToHighPartitioner.new(2,1)
#
def initialize(paid_item_count, discounted_item_count)
@paid_item_count = paid_item_count
@discounted_item_count = discounted_item_count
end
# Partitions the items and returns the items that are to be discounted.
#
# Arguments
# ---------
#
# * cart
# The cart to which split items will be added (typically Input.cart).
#
# * line_items
# The selected items that are applicable for the campaign.
#
# Example
# -------
#
# To create a campaign such that for all items under $5, the 3rd one is discounted:
#
# selected_items = Input.cart.line_items.select{|item| item.variant.price < Money.new(cents: 5_00)}
# partitioner = LowToHighPartitioner.new(2,1)
# items_to_discount = partitioner.partition(Input.cart, selected_items)
#
# After this, the campaign has to apply discounts to `items_to_discount`.
#
def partition(cart, applicable_line_items)
# Sort the items by price from low to high
sorted_items = applicable_line_items.sort_by{|line_item| line_item.variant.price}
# Find the total quantity of items
total_applicable_quantity = sorted_items.map(&:quantity).reduce(0, :+)
# Find the quantity of items that must be discounted
discounted_items_remaining = Integer(total_applicable_quantity / (@paid_item_count + @discounted_item_count) * @discounted_item_count)
# Create an array of items to return
discounted_items = []
# Loop over all the items and find those to be discounted
sorted_items.each do |line_item|
# Exit the loop if all discounted items have been found
break if discounted_items_remaining == 0
# The item will be discounted
discounted_item = line_item
if line_item.quantity > discounted_items_remaining
# If the item has more quantity than what must be discounted, split it
discounted_item = line_item.split(take: discounted_items_remaining)
# Insert the newly-created item in the cart, right after the original item
position = cart.line_items.find_index(line_item)
cart.line_items.insert(position + 1, discounted_item)
end
# Decrement the items left to be discounted
discounted_items_remaining -= discounted_item.quantity
# Add the item to be returned
discounted_items.push(discounted_item)
end
# Return the items to be discounted
discounted_items
end
end
# Use an array to keep track of the discount campaigns desired.
CAMPAIGNS = [
# Give every 3rd item with the tag "letter" for free
BogoCampaign.new(
TagSelector.new("On-Sale"),
PercentageDiscount.new(50, "Half off!"),
LowToHighPartitioner.new(1,1),
)
]
# Iterate through each of the discount campaigns.
CAMPAIGNS.each do |campaign|
# Apply the campaign onto the cart.
campaign.run(Input.cart)
end
# In order to have the changes to the line items be reflected, the output of
# the script needs to be specified.
Output.cart = Input.cart
Im trying to get something similar done. I just want my script to void any discount codes. I asked our account manager and they said it would have to be paid to sent to a developer. Someone needs to really be more active on these forums and help people out. This seems like it should be a no brainer that they would know the fix for.
User | Count |
---|---|
2 | |
2 | |
2 | |
1 | |
1 |