Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Shopify Script Bogo

Shopify Script Bogo

Fromrachel
Shopify Partner
1 0 0

Hi, 

 

I created a Shopify scripts BOGO

Buy 3 tights get 1 at 40% off

 

what I want : don't want the promo to applies to tights on sale (Even if I add the condition to apply to tag: not_on_sale = it's still applying on sale items.

and don't want to customers can add a discount code above these items. 

But if in their cart they have 3 tights, 2 skirts, the discounts will apply only on skirts.

 

Here the scripts

thanks for you help.


# ================================================================
BUYVOFW_GETXOFY_FORZ = [
{
buy_product_selector_match_type: :include,
buy_product_selector_type: :tag,
buy_product_selectors: ["pdty:TIGHTS","pdty:TIGHTS_FR"],
quantity_to_buy: 3,
get_product_selector_match_type: :include,
get_product_selector_type: :tag,
get_product_selectors: ["pdty:TIGHTS","pdty:TIGHTS_FR"],
quantity_to_discount: 1,
allow_incomplete_bundle: true,
discount_type: :percent,
discount_amount: 40,
discount_message: '3rd tights at 40% / 3eme collant à -40%',
}
]

# ================================ Script Code (do not edit) ================================
# ================================================================
# ProductSelector
#
# Finds matching products by the entered criteria.
# ================================================================
class ProductSelector
def initialize(match_type, selector_type, selectors)
@match_type = match_type
@comparator = match_type == :include ? 'any?' : 'none?'
@Selector_type = selector_type
@selectors = selectors
end

def match?(line_item)
if self.respond_to?(@selector_type)
self.send(@selector_type, line_item)
else
raise RuntimeError.new('Invalid product selector type')
end
end

def tag(line_item)
product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip }
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@selectors & product_tags).send(@comparator)
end

def type(line_item)
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip)
end

def vendor(line_item)
@selectors = @selectors.map { |selector| selector.downcase.strip }
(@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip)
end

def product_id(line_item)
(@match_type == :include) == @selectors.include?(line_item.variant.product.id)
end

def variant_id(line_item)
(@match_type == :include) == @selectors.include?(line_item.variant.id)
end

def subscription(line_item)
!line_item.selling_plan_id.nil?
end

def all(line_item)
true
end
end

# ================================================================
# DiscountApplicator
#
# Applies the entered discount to the supplied line item.
# ================================================================
class DiscountApplicator
def initialize(discount_type, discount_amount, discount_message)
@discount_type = discount_type
@discount_message = discount_message

@discount_amount = if discount_type == :percent
1 - (discount_amount * 0.01)
else
Money.new(cents: 100) * discount_amount
end
end

def apply(line_item)
new_line_price = if @discount_type == :percent
line_item.line_price * @discount_amount
else
[line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max
end

line_item.change_line_price(new_line_price, message: @discount_message)
end
end

# ================================================================
# DiscountLoop
#
# Loops through the supplied line items and discounts the supplied
# number of items by the supplied discount.
# ================================================================
class DiscountLoop
def initialize(discount_applicator)
@discount_applicator = discount_applicator
end

def loop_items(cart, line_items, num_to_discount)
line_items.each do |line_item|
break if num_to_discount <= 0

if line_item.quantity > num_to_discount
split_line_item = line_item.split(take: num_to_discount)
@discount_applicator.apply(split_line_item)
position = cart.line_items.find_index(line_item)
cart.line_items.insert(position + 1, split_line_item)
break
else
@discount_applicator.apply(line_item)
num_to_discount -= line_item.quantity
end
end
end
end

# ================================================================
# BuyVofWGetXofYForZCampaign
#
# Buy a certain number of matching items, get a certain number of
# a different set of matching items with the entered discount
# applied.
# ================================================================
class BuyVofWGetXofYForZCampaign
def initialize(campaigns)
@campaigns = campaigns
end

def run(cart)
@campaigns.each do |campaign|
buy_product_selector = ProductSelector.new(
campaign[:buy_product_selector_match_type],
campaign[:buy_product_selector_type],
campaign[:buy_product_selectors],
)

get_product_selector = ProductSelector.new(
campaign[:get_product_selector_match_type],
campaign[:get_product_selector_type],
campaign[:get_product_selectors],
)

buy_items = []
get_items = []

cart.line_items.each do |line_item|
buy_items.push(line_item) if buy_product_selector.match?(line_item)
get_items.push(line_item) if get_product_selector.match?(line_item)
end

next if buy_items.empty? || get_items.empty?

get_items = get_items.sort_by { |line_item| line_item.variant.price }
quantity_to_buy = campaign[:quantity_to_buy]
quantity_to_discount = campaign[:quantity_to_discount]
buy_offers = (buy_items.map(&:quantity).reduce(0, :+) / quantity_to_buy).floor

if campaign[:allow_incomplete_bundle]
number_of_bundles = buy_offers
else
get_offers = (get_items.map(&:quantity).reduce(0, :+) / quantity_to_discount).floor
number_of_bundles = [buy_offers, get_offers].min
end

number_of_discountable_items = number_of_bundles * quantity_to_discount

next unless number_of_discountable_items > 0

discount_applicator = DiscountApplicator.new(
campaign[:discount_type],
campaign[:discount_amount],
campaign[:discount_message]
)

discount_loop = DiscountLoop.new(discount_applicator)
discount_loop.loop_items(cart, get_items, number_of_discountable_items)
end
end
end

CAMPAIGNS = [
BuyVofWGetXofYForZCampaign.new(BUYVOFW_GETXOFY_FORZ),
]
campaign.run(Input.cart)
end

Output.cart = Input.cart

Replies 0 (0)