Beispiele für Einzelartikel-Skripte
Einzelartikel-Skripte wirken sich auf Artikel in einem Warenkorb aus und können ihre Eigenschaften und Preise ändern. Diese Skripte werden jedes Mal ausgeführt, wenn sich ein Warenkorbattribut ändert, z. B. wenn ein Artikel entfernt, die Lieferadresse geändert oder ein Rabattcode hinzugefügt wird.
Plananforderung
Shopify Scripts und die Script Editor-App sind nur für Shops mit dem Shopify Plus-Plan verfügbar. Die Script Editor-App steht im Shopify App Store nicht mehr zum Download zur Verfügung.
Am 28. August 2025 wird Shopify Scripts entfernt und funktioniert dann nicht mehr. Migriere deine vorhandenen Scripts vor diesem Datum zu Shopify Functions .
Erstelle ein neues Skript mit einer leeren Vorlage, um die Vorlage auf dieser Seite zu verwenden.
Schritte:
Gehen Sie im Shopify-Adminbereich zu Apps > Script Editor .
Klicken Sie auf Skript erstellen .
Klicke auf Einzelartikel .
Wählen Sie Leere Vorlage aus und klicken Sie anschließend auf Skript erstellen .
Löschen Sie im Abschnitt Ruby-Quellcode die standardmäßige Codezeile: Output.cart = Input.cart
Kopiere ein Skript von dieser Seite und füge es in den Abschnitt Ruby-Quellcode ein.
Bearbeite den Abschnitt Anpassbare Einstellungen des Skriptes, damit es in deinem Shop funktioniert.
Teste dein Skript. Weitere Informationen findest du unter Shopify Scripts testen und Fehler beheben .
Nach dem Testen:
Klicken Sie auf Entwurf speichern , um einen unveröffentlichten Entwurf des Skriptes zu speichern, oder
klicke auf Speichern und veröffentlichen , um das Skript zu erstellen und zu veröffentlichen.
Gestaffelter Warenkorb-Rabatt nach Ausgaben Verwende dieses Skript, um einen Dollarbetrag-Rabatt anzubieten, der mit dem Gesamtwert der Artikel im Warenkorb steigt. Dieser Rabatt wird so gleichmäßig wie möglich über die einzelnen Artikel im Warenkorb verteilt.
Biete Kunden z. B. einen Rabatt von 25 USD auf ihren Gesamtbetrag an, wenn sie mehr als 150 USD ausgeben, einen Rabatt von 50 USD, wenn sie mehr als 300 USD ausgeben, oder einen Rabatt von 75 USD, wenn sie mehr als 400 USD ausgeben.
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Cart Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to the cart. The
# discount will be spread, as evenly as possible, across all items.
#
# - 'threshold' is the spend amount needed to qualify
# - 'discount_amount' is the dollar discount to apply to the
# cart
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
SPENDING_THRESHOLDS = [
{
threshold: 150 ,
discount_amount: 25 ,
discount_message: 'Spend $150 and get $25 off!' ,
},
{
threshold: 300 ,
discount_amount: 50 ,
discount_message: 'Spend $300 and get $50 off!' ,
},
{
threshold: 400 ,
discount_amount: 75 ,
discount_message: 'Spend $400 and get $75 off!' ,
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# DollarDiscountApplicator
#
# Applies the entered discount to the supplied line item.
# ================================================================
class DollarDiscountApplicator
def initialize ( discount_message )
@discount_message = discount_message
end
def apply ( line_item , discount_amount )
new_line_price = line_item . line_price - discount_amount
line_item . change_line_price ( new_line_price , message: @discount_message )
end
end
# ================================================================
# TieredCartDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to the cart. The
# discount will be spread, as evenly as possible, across all items.
# ================================================================
class TieredCartDiscountBySpendCampaign
def initialize ( tiers )
@tiers = tiers . sort_by { | tier | tier [ :threshold ] }. reverse
end
def run ( cart )
applicable_tier = @tiers . find { | tier | cart . subtotal_price >= ( Money . new ( cents: 100 ) * tier [ :threshold ]) }
return if applicable_tier . nil?
discount_applicator = DollarDiscountApplicator . new ( applicable_tier [ :discount_message ])
discount_amount = applicable_tier [ :discount_amount ]
items = cart . line_items . sort_by { | line_item | line_item . variant . price }
self . loop_items ( cart , items , discount_amount , discount_applicator )
end
def loop_items ( cart , line_items , discount_amount , discount_applicator )
avg_discount = ( discount_amount . to_f * ( 1 / line_items . map ( & :quantity ). reduce ( 0 , : + ))). round ( 2 )
avg_discount = Money . new ( cents: 100 ) * avg_discount
discount_amount = Money . new ( cents: 100 ) * discount_amount
line_items . each_with_index do | line_item , index |
break if discount_amount <= Money . zero
line_discount = avg_discount * line_item . quantity
if discount_amount < line_discount || index == ( line_items . size - 1 )
discount_update = line_item . line_price > discount_amount ? discount_amount : line_item . line_price
else
discount_update = line_item . line_price > line_discount ? line_discount : line_item . line_price
end
discount_amount -= discount_update
discount_applicator . apply ( line_item , discount_update )
end
end
end
CAMPAIGNS = [
TieredCartDiscountBySpendCampaign . new ( SPENDING_THRESHOLDS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Gestaffelter Rabatte nach Ausgaben Verwende dieses Skript, um einen prozentualen Rabatt anzubieten, der mit dem Gesamtwert der Artikel im Warenkorb steigt.
Biete Kunden z. B. einen Rabatt von 10 % an, wenn sie 30 USD oder mehr ausgeben, 15 %, wenn sie 50 USD oder mehr ausgeben, oder von 20 %, wenn sie 100 USD oder mehr ausgeben.
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
# - 'threshold' is the spend amount needed to qualify
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
SPENDING_THRESHOLDS = [
{
threshold: 30 ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: 'Spend $30 and get 10% off!' ,
},
{
threshold: 50 ,
discount_type: :percent ,
discount_amount: 15 ,
discount_message: 'Spend $50 and get 15% off!' ,
},
{
threshold: 100 ,
discount_type: :percent ,
discount_amount: 20 ,
discount_message: 'Spend $100 and get 20% off!' ,
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# 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
# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
def initialize ( tiers )
@tiers = tiers . sort_by { | tier | tier [ :threshold ] }. reverse
end
def run ( cart )
applicable_tier = @tiers . find { | tier | cart . subtotal_price >= ( Money . new ( cents: 100 ) * tier [ :threshold ]) }
return if applicable_tier . nil?
discount_applicator = DiscountApplicator . new (
applicable_tier [ :discount_type ],
applicable_tier [ :discount_amount ],
applicable_tier [ :discount_message ]
)
cart . line_items . each do | line_item |
next if line_item . variant . product . gift_card?
discount_applicator . apply ( line_item )
end
end
end
CAMPAIGNS = [
TieredDiscountBySpendCampaign . new ( SPENDING_THRESHOLDS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Nach Anzahl gestaffelter Produktrabatt Verwende dieses Skript, um einen Mengenrabatt für ein bestimmtes Produkt anzubieten, mit einem prozentualen Rabatt, der entsprechend der Anzahl dieser Produkte im Warenkorb steigt.
Biete Kunden z. B. 10 % Rabatt auf jeden Hut an, wenn sie zwei oder mehr Hüte kaufen, oder 15 %, wenn sie fünf oder mehr Hüte kaufen.
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Product Discount by Quantity
#
# If the total quantity of matching items is greater than (or
# equal to) an entered threshold, the associated discount is
# applied to each matching item.
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above) for
# qualifying products. Product/Variant ID lists should only
# contain numbers (ie. no quotes). If ':all' is used, this
# can also be 'nil'.
# - 'tiers' is a list of tiers where:
# - 'quantity' is the minimum quantity you need to buy to
# qualify
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNT_TIERS = [
{
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "your_tag" ],
tiers: [
{
quantity: 2 ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: '10% off for 2+' ,
},
{
quantity: 5 ,
discount_type: :percent ,
discount_amount: 15 ,
discount_message: '15% off for 5+' ,
},
],
},
]
# ================================ 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
# ================================================================
# TieredProductDiscountByQuantityCampaign
#
# If the total quantity of matching items is greater than (or
# equal to) an entered threshold, the associated discount is
# applied to each matching item.
# ================================================================
class TieredProductDiscountByQuantityCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
applicable_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if applicable_items . nil?
total_applicable_quantity = applicable_items . map ( & :quantity ). reduce ( 0 , : + )
tiers = campaign [ :tiers ]. sort_by { | tier | tier [ :quantity ] }. reverse
applicable_tier = tiers . find { | tier | tier [ :quantity ] <= total_applicable_quantity }
next if applicable_tier . nil?
discount_applicator = DiscountApplicator . new (
applicable_tier [ :discount_type ],
applicable_tier [ :discount_amount ],
applicable_tier [ :discount_message ]
)
applicable_items . each do | line_item |
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
TieredProductDiscountByQuantityCampaign . new ( PRODUCT_DISCOUNT_TIERS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Nach Produktausgaben gestaffelter Produktrabatt Verwenden Sie dieses Skript, um einen prozentualen Rabatt anzubieten, der mit dem Gesamtwert bestimmter Artikel im Warenkorb steigt.
Biete Kunden z. B. einen Rabatt von 10 % an, wenn sie 30 USD oder mehr ausgeben, 15 %, wenn sie 50 USD oder mehr ausgeben, oder von 20 %, wenn sie 100 USD oder mehr ausgeben – jedoch nur für Artikel, die mit einem bestimmten Tag übereinstimmen.
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Product Discount by Product Spend Threhsold
#
# If the total amount spent on matching items is greather than (or
# equal to) an entered threshold, the associated discount is
# applied to each matching item.
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'tiers' is a list of tiers where:
# - 'threshold' is the minimum dollar amount needed to
# qualify
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNT_TIERS = [
{
product_selector_match_type: :exclude ,
product_selector_type: :tag ,
product_selectors: [ "your_tag" , "another_tag" ],
tiers: [
{
threshold: 100 ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: 'Spend $100 or more, and get 10% off!' ,
},
],
},
]
# ================================ 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
# ================================================================
# TieredProductDiscountByProductSpendCampaign
#
# If the total amount spent on matching items is greather than (or
# equal to) an entered threshold, the associated discount is
# applied to each matching item.
# ================================================================
class TieredProductDiscountByProductSpendCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
if campaign [ :product_selector_type ] == :all
total_applicable_cost = cart . subtotal_price
applicable_items = cart . line_items
else
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
applicable_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if applicable_items . nil?
total_applicable_cost = applicable_items . map ( & :line_price ). reduce ( Money . zero , : + )
end
tiers = campaign [ :tiers ]. sort_by { | tier | tier [ :threshold ] }. reverse
applicable_tier = tiers . find { | tier | total_applicable_cost >= ( Money . new ( cents: 100 ) * tier [ :threshold ]) }
next if applicable_tier . nil?
discount_applicator = DiscountApplicator . new (
applicable_tier [ :discount_type ],
applicable_tier [ :discount_amount ],
applicable_tier [ :discount_message ]
)
applicable_items . each do | line_item |
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
TieredProductDiscountByProductSpendCampaign . new ( PRODUCT_DISCOUNT_TIERS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktrabatt Verwende dieses Skript, um einen Rabatt auf bestimmte Artikel anzubieten.
Biete Kunden z. B. 10 % Rabatt auf Artikel an, die als discounted
getaggt sind.
# ================================ Customizable Settings ================================
# ================================================================
# Discount by Product
#
# Any matching item will be discounted by the entered amount.
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNTS = [
{
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "your_tag" ],
discount_type: :percent ,
discount_amount: 10 ,
discount_message: '10% off tagged products!'
}
]
# ================================ 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
# ================================================================
# ProductDiscountCampaign
#
# Any matching item will be discounted by the entered amount.
# ================================================================
class ProductDiscountCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
ProductDiscountCampaign . new ( PRODUCT_DISCOUNTS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktrabatt nach Rabattcode Verwende dieses Skript, um einen Rabatt für bestimmte Artikel anzubieten, wenn ein bestimmter Rabattcode verwendet wird.
Biete Kunden z. B. 10 % Rabatt auf Artikel an, die als discounted
getaggt sind, wenn die Kunden den Rabattcode DISCOUNT_10
verwenden.
# ================================ Customizable Settings ================================
# ================================================================
# Product Discount by Discount Code
#
# If any matching discount codes are used, any matching items
# will be discounted by the entered amount.
#
# - 'discount_code_match_type' determines whether the below
# strings should be an exact or partial match. Can be:
# - ':exact' for an exact match
# - ':partial' for a partial match
# - 'discount_codes' is a list of strings to identify discount
# codes
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNTS_BY_DISCOUNT_CODE = [
{
discount_code_match_type: :exact ,
discount_codes: [ "TESTCODE1" , "TESTCODE2" ],
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "your_tag" ],
discount_type: :percent ,
discount_amount: 10 ,
discount_message: '10% off tagged products!'
}
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# DiscountCodeSelector
#
# Finds whether the supplied discount code matches any of the
# entered codes.
# ================================================================
class DiscountCodeSelector
def initialize ( match_type , discount_codes )
@comparator = match_type == :exact ? '==' : 'include?'
@discount_codes = discount_codes . map { | discount_code | discount_code . upcase . strip }
end
def match? ( discount_code )
@discount_codes . any? { | code | discount_code . code . upcase . send ( @comparator , code ) }
end
end
# ================================================================
# 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
# ================================================================
# ProductDiscountByCodeCampaign
#
# If any matching discount codes are used, any matching items
# will be discounted by the entered amount.
# ================================================================
class ProductDiscountByCodeCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
return if cart . discount_code . nil?
@campaigns . each do | campaign |
discount_code_selector = DiscountCodeSelector . new (
campaign [ :discount_code_match_type ],
campaign [ :discount_codes ]
)
next unless discount_code_selector . match? ( cart . discount_code )
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
ProductDiscountByCodeCampaign . new ( PRODUCT_DISCOUNTS_BY_DISCOUNT_CODE ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Eine bestimmte Menge eines Produkts kaufen, eine zweite Menge mit einem Rabatt erhalten Verwende dieses Skript, um einen Rabatt für einen bestimmten Artikel anzubieten, wenn mehr als eine bestimmte Menge gekauft wird.
Biete Kunden z. B. an, drei Artikel zu kaufen, die ein discount
-Tag haben, und auf einen vierten Artikel mit dem Tag discount
50 % Rabatt zu erhalten.
Hinweis
Dieses Skript fügt nicht die Artikel, die mit 'get' ("kaufe") gemeint sind, zum Warenkorb hinzu. Es kann nur einen Rabatt auf Artikel anwenden, die bereits im Warenkorb sind.
# ================================ Customizable Settings ================================
# ================================================================
# Buy X, Get Y For Z Discount
#
# Buy a certain number of matching items, get a certain number
# of the same matching items with the entered discount applied. For
# example:
#
# "Buy 2 products tagged with 'tag', get another product
# tagged with 'tag' for 10% off"
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above) for
# qualifying products. Product/Variant ID lists should only
# contain numbers (ie. no quotes). If ':all' is used, this
# can also be 'nil'.
# - 'quantity_to_buy' is the number of products needed to
# qualify
# - 'quantity_to_discount' is the number of products to discount
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
#
# Something to note for the case of running multiple offers is
# that there shouldn't be any overlap between product selection
# as this can lead to extra discounting. For example, you should
# NOT offer "Buy 1 Product X, get 1 50% off", as well as "Buy 2
# Product X, get 1 free"
# ================================================================
BUY_X_GET_Y_FOR_Z = [
{
product_selector_match_type: :include ,
product_selector_type: :all ,
product_selectors: nil ,
quantity_to_buy: 1 ,
quantity_to_discount: 1 ,
discount_type: :percent ,
discount_amount: 50 ,
discount_message: 'Buy one item, get the second 50% off!' ,
},
]
# ================================ 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
# ================================================================
# BuyXGetYForZCampaign
#
# Buy a certain number of matching items, get a certain number
# of the same matching items with the entered discount applied.
# ================================================================
class BuyXGetYForZCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
eligible_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if eligible_items . nil?
eligible_items = eligible_items . sort_by { | line_item | - line_item . variant . price }
quantity_to_buy = campaign [ :quantity_to_buy ]
quantity_to_discount = campaign [ :quantity_to_discount ]
bundle_size = quantity_to_buy + quantity_to_discount
number_of_bundles = ( eligible_items . map ( & :quantity ). reduce ( 0 , : + ) / bundle_size ). floor
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 ]
)
self . loop_items (
discount_applicator , cart , eligible_items , number_of_discountable_items , quantity_to_buy , quantity_to_discount
)
end
end
def loop_items ( discount_applicator , cart , line_items , num_to_discount , quantity_to_buy , quantity_to_discount )
surplus = 0
bundle_size = quantity_to_buy + quantity_to_discount
line_items . each do | line_item |
line_quantity = line_item . quantity + surplus
if line_quantity > quantity_to_buy
bundles_per_line = ( line_quantity / bundle_size ). floor
take_quantity = bundles_per_line * quantity_to_discount
surplus += ( line_quantity - ( bundle_size * bundles_per_line ))
if line_item . quantity > take_quantity
discount_item = line_item . split ( take: take_quantity )
discount_applicator . apply ( discount_item )
position = cart . line_items . find_index ( line_item )
cart . line_items . insert ( position + 1 , discount_item )
num_to_discount -= take_quantity
else
discount_applicator . apply ( line_item )
num_to_discount -= line_item . quantity
end
else
surplus += line_quantity
end
break if num_to_discount <= 0
end
end
end
CAMPAIGNS = [
BuyXGetYForZCampaign . new ( BUY_X_GET_Y_FOR_Z ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Ein Bundle kaufen, ein zusätzliches Produkt mit einem Rabatt erhalten Verwende dieses Skript, um einen Rabatt für einen bestimmten Artikel anzubieten, wenn der Kunde eine Reihe anderer Artikel gekauft hat.
Biete Kunden z. B. an, dass sie ein kostenloses Paar Socken erhalten, wenn sie auch einen Hut, ein T-Shirt und eine Sonnenbrille kaufen.
Hinweis
Dieses Skript fügt nicht den oder die Artikel, die mit 'get' ("kaufe") gemeint sind, zum Warenkorb hinzu. Es kann nur einen Rabatt auf Artikel anwenden, die bereits im Warenkorb sind.
# ================================ Customizable Settings ================================
# ================================================================
# Buy Products VWX, get Product Y for Z Discount
#
# Buy a specific bundle of items, get another item at a discount.
# For example:
#
# "Buy a t-shirt, a hat, and sunglasses, get a free pair of socks"
#
# - 'bundle_items' is a list of the items that comprise the
# bundle, where:
# - 'product_id' is the ID of the product
# - 'quantity_needed' is the quantity necessary to complete
# the bundle
# - 'quantity_to_buy' is the number of bundles needed to qualify
# for a discount product
# - 'discount_product_selector_match_type' determines whether we
# look for products that do or don't match the entered
# selectors. Can be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'discount_product_selector_type' determines how qualifying
# products will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'discount_product_selectors' is a list of identifiers (from
# above) for qualifying products. Product/Variant ID lists
# should only contain numbers (ie. no quotes). If ':all' is
# used, this can also be 'nil'.
# - 'quantity_to_discount' is the number of items to discount
# per offer
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
BUNDLE_DISCOUNTS = [
{
bundle_items: [
{
product_id: 1234567890987 ,
quantity_needed: 1
},
{
product_id: 1234567890986 ,
quantity_needed: 1
},
],
quantity_to_buy: 1 ,
discount_product_selector_match_type: :include ,
discount_product_selector_type: :product_id ,
discount_product_selectors: [ 1234567890123 ],
quantity_to_discount: 1 ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: "Buy Product VWX, get Product Y for 10% off" ,
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# BundleSelector
#
# Finds any items that are part of the entered bundle and saves
# them.
# ================================================================
class BundleSelector
def initialize ( bundle_items )
@bundle_items = bundle_items . reduce ({}) do | acc , bundle_item |
acc [ bundle_item [ :product_id ]] = {
cart_items: [],
quantity_needed: bundle_item [ :quantity_needed ],
total_quantity: 0 ,
}
acc
end
end
def build ( cart )
cart . line_items . each do | line_item |
next unless @bundle_items [ line_item . variant . product . id ]
@bundle_items [ line_item . variant . product . id ][ :cart_items ]. push ( line_item )
@bundle_items [ line_item . variant . product . id ][ :total_quantity ] += line_item . quantity
end
@bundle_items
end
end
# ================================================================
# 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_with_index 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
# ================================================================
# BundleDiscountCampaign
#
# If the entered bundle is present, the entered discount is
# applied to the entered product.
# ================================================================
class BundleDiscountCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
bundle_selector = BundleSelector . new ( campaign [ :bundle_items ])
bundle_items = bundle_selector . build ( cart )
next if bundle_items . any? do | product_id , product_info |
product_info [ :total_quantity ] < product_info [ :quantity_needed ]
end
num_bundles = bundle_items . map do | product_id , product_info |
( product_info [ :total_quantity ] / product_info [ :quantity_needed ])
end
num_bundles = num_bundles . min . floor
product_selector = ProductSelector . new (
campaign [ :discount_product_selector_match_type ],
campaign [ :discount_product_selector_type ],
campaign [ :discount_product_selectors ],
)
discount_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if discount_items . nil?
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
discount_loop = DiscountLoop . new ( discount_applicator )
discount_loop . loop_items ( cart , discount_items , ( campaign [ :quantity_to_discount ] * num_bundles ))
end
end
end
CAMPAIGNS = [
BundleDiscountCampaign . new ( BUNDLE_DISCOUNTS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Bundle-Rabatt Verwende dieses Skript, um einen Rabatt anzubieten, wenn ein bestimmtes Produktset zum Warenkorb hinzugefügt wird.
Biete Kunden z. B. einen Rabatt von 20 % auf den Kauf eines T-Shirts, eines Hutes und einer Sonnenbrille an.
# ================================ Customizable Settings ================================
# ================================================================
# Buy Products WXY, get Z Discount
#
# Buy a specific bundle of products, get that bundle at a
# discount. For example:
#
# "Buy a t-shirt, a hat, and sunglasses, get 20% off each"
#
# - 'bundle_items' is a list of the items that comprise the
# bundle, where:
# - 'product_id' is the ID of the product
# - 'quantity_needed' is the quantity necessary to complete
# the bundle
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
BUNDLE_DISCOUNTS = [
{
bundle_items: [
{
product_id: 1234567890987 ,
quantity_needed: 1
},
{
product_id: 1234567890986 ,
quantity_needed: 1
},
],
discount_type: :percent ,
discount_amount: 10 ,
discount_message: "Buy Product X and Product Y, get 10% off!" ,
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# BundleSelector
#
# Finds any items that are part of the entered bundle and saves
# them.
# ================================================================
class BundleSelector
def initialize ( bundle_items )
@bundle_items = bundle_items . reduce ({}) do | acc , bundle_item |
acc [ bundle_item [ :product_id ]] = {
cart_items: [],
quantity_needed: bundle_item [ :quantity_needed ],
total_quantity: 0 ,
}
acc
end
end
def build ( cart )
cart . line_items . each do | line_item |
next if line_item . line_price_changed?
next unless @bundle_items [ line_item . variant . product . id ]
@bundle_items [ line_item . variant . product . id ][ :cart_items ]. push ( line_item )
@bundle_items [ line_item . variant . product . id ][ :total_quantity ] += line_item . quantity
end
@bundle_items
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_with_index 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
# ================================================================
# BundleDiscountCampaign
#
# If the entered bundle is present, the entered discount is
# applied to each item in the bundle.
# ================================================================
class BundleDiscountCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
bundle_selector = BundleSelector . new ( campaign [ :bundle_items ])
bundle_items = bundle_selector . build ( cart )
next if bundle_items . any? do | product_id , product_info |
product_info [ :total_quantity ] < product_info [ :quantity_needed ]
end
num_bundles = bundle_items . map do | product_id , product_info |
( product_info [ :total_quantity ] / product_info [ :quantity_needed ])
end
num_bundles = num_bundles . min . floor
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
discount_loop = DiscountLoop . new ( discount_applicator )
bundle_items . each do | product_id , product_info |
discount_loop . loop_items (
cart ,
product_info [ :cart_items ],
( product_info [ :quantity_needed ] * num_bundles ),
)
end
end
end
end
CAMPAIGNS = [
BundleDiscountCampaign . new ( BUNDLE_DISCOUNTS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
BOGO-Rabatt (Buy one get one) Verwende dieses Skript, um einen prozentualen Rabatt auf einen Artikel anzubieten, wenn ein Kunde eine festgelegte Anzahl eines anderen Produkts kauft.
Biete Kunden z. B. 10 % Rabatt auf einen Hut an, wenn sie zwei T-Shirts kaufen.
Hinweis
Dieses Skript fügt nicht den oder die Artikel, die mit 'get' ("kaufe") gemeint sind, zum Warenkorb hinzu. Es kann nur einen Rabatt auf Artikel anwenden, die bereits im Warenkorb sind.
# ================================ Customizable Settings ================================
# ================================================================
# Buy V of Product W, Get X of Product Y for Z Discount
#
# Buy a certain number of matching items, get a certain number of
# a different set of matching items with the entered discount
# applied. For example:
#
# "Buy 2 t-shirts, get 1 hat for 10% off"
#
# - 'buy_product_selector_match_type' determines whether we look
# for products that do or don't match the entered selectors.
# Can be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'buy_product_selector_type' determines how eligible products
# will be identified. Can be:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'buy_product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should only
# contain numbers (ie. no quotes). If ':all' is used, this
# can also be 'nil'.
# - 'quantity_to_buy' is the number of products needed to
# qualify
# - 'get_selector_match_type' is the same idea as the "Buy"
# version above
# - 'get_product_selector_type' is the same idea as the "Buy"
# version above
# - 'get_product_selectors' is the same idea as the "Buy"
# version above
# - 'quantity_to_discount' is the number of products to discount
# - 'allow_incomplete_bundle' determines whether a portion of
# the items to discount can be discounted, or all items
# need to be present. Can be:
# - 'true'
# - 'false'
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
BUYVOFW_GETXOFY_FORZ = [
{
buy_product_selector_match_type: :include ,
buy_product_selector_type: :tag ,
buy_product_selectors: [ "your_tag" , "another_tag" ],
quantity_to_buy: 1 ,
get_product_selector_match_type: :include ,
get_product_selector_type: :tag ,
get_product_selectors: [ "your_other_tag" , "a_different_tag" ],
quantity_to_discount: 1 ,
allow_incomplete_bundle: false ,
discount_type: :percent ,
discount_amount: 100 ,
discount_message: 'Buy a Product X, get a Product Y free!' ,
},
{
buy_product_selector_match_type: :include ,
buy_product_selector_type: :product_id ,
buy_product_selectors: [ 1234567890987 , 1234567890986 ],
quantity_to_buy: 1 ,
get_product_selector_match_type: :include ,
get_product_selector_type: :product_id ,
get_product_selectors: [ 1234567890985 , 1234567890984 ],
quantity_to_discount: 1 ,
allow_incomplete_bundle: false ,
discount_type: :dollar ,
discount_amount: 10 ,
discount_message: 'Buy a Product X, get $10 off a Product Y!' ,
},
]
# ================================ 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 ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Eine bestimmte Menge eines Produkts für einen bestimmten Betrag kaufen Verwende dieses Skript, um eine Anzahl von Produkten für einen ausgewählten Preis anzubieten.
Biete Kunden z. B. zwei T-Shirts für 20 USD an.
# ================================ Customizable Settings ================================
# ================================================================
# Buy X of Product Y for $Z
#
# Buy a certain number of matching items for a specific price.
# For example:
#
# "Buy 2 t-shirts for $20"
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'quantity_to_buy' is the number of products needed to
# qualify
# - 'final_price` is the amount to charge for all products that
# are part of the offer
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
BUY_X_GET_Y_FOR_Z = [
{
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "your_tag" ],
quantity_to_buy: 2 ,
final_price: 100 ,
discount_message: 'Buy 2 for $20' ,
},
]
# ================================ 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
# ================================================================
# DollarDiscountApplicator
#
# Applies the entered discount to the supplied line item.
# ================================================================
class DollarDiscountApplicator
def initialize ( discount_message )
@discount_message = discount_message
end
def apply ( line_item , discount_amount )
new_line_price = line_item . line_price - discount_amount
line_item . change_line_price ( new_line_price , message: @discount_message )
end
end
# ================================================================
# BuyXOfYForZCampaign
#
# Buy a certain number of matching items for a specific price.
# ================================================================
class BuyXOfYForZCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
eligible_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if eligible_items . nil?
eligible_item_count = eligible_items . map ( & :quantity ). reduce ( 0 , : + )
quantity_to_buy = campaign [ :quantity_to_buy ]
number_of_offers = ( eligible_item_count / quantity_to_buy ). floor
next unless number_of_offers > 0
number_of_discountable_items = number_of_offers * quantity_to_buy
total_offer_price = Money . new ( cents: 100 ) * ( number_of_offers * campaign [ :final_price ])
discount_applicator = DollarDiscountApplicator . new ( campaign [ :discount_message ])
self . loop_items ( cart , eligible_items , number_of_discountable_items , total_offer_price , discount_applicator )
end
end
def loop_items ( cart , line_items , num_to_discount , total_price , discount_applicator )
current_price = Money . zero
avg_price = total_price * ( 1 / num_to_discount )
line_items = line_items . sort_by { | line_item | line_item . variant . price }
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_amount = split_line_item . line_price - ( total_price - current_price )
discount_applicator . apply ( split_line_item , discount_amount )
position = cart . line_items . find_index ( line_item )
cart . line_items . insert ( position + 1 , split_line_item )
break
elsif line_item . quantity == num_to_discount
discount_amount = line_item . line_price - ( total_price - current_price )
discount_applicator . apply ( line_item , discount_amount )
break
else
if line_item . variant . price <= avg_price
current_price += line_item . line_price
else
discount_amount = ( line_item . variant . price - avg_price ) * line_item . quantity
current_price += ( line_item . line_price - discount_amount )
discount_applicator . apply ( line_item , discount_amount )
end
num_to_discount -= line_item . quantity
end
end
end
end
CAMPAIGNS = [
BuyXOfYForZCampaign . new ( BUY_X_GET_Y_FOR_Z ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Gratis Geschenk beim Kauf Verwende dieses Skript, um einen Rabatt für ein bestimmtes Produkt anzubieten, wenn die Gesamtsumme des Warenkorbs größer als ein bestimmter Betrag ist.
Biete Kunden z. B. ein kostenloses Geschenk an, wenn sie mehr als 75 USD ausgeben.
Hinweis
Dieses Skript fügt nicht den oder die Artikel, die mit 'get' ("kaufe") gemeint sind, zum Warenkorb hinzu. Es kann nur einen Rabatt auf Artikel anwenden, die bereits im Warenkorb sind.
# ================================ Customizable Settings ================================
# ================================================================
# Spend $X, get Product Y for Z Discount
#
# If the cart total is greater than (or equal to) the entered
# threshold (less the discounted amount), the entered number of
# matching items is discounted by the entered amount.
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'threshold' is the dollar amount needed to spend to qualify
# - 'quantity_to_discount' is the number of items to discount
# if qualified
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
SPENDX_GETY_FORZ = [
{
product_selector_match_type: :include ,
product_selector_type: :product_id ,
product_selectors: [ 1234567890123 ],
threshold: 75 ,
quantity_to_discount: 1 ,
discount_type: :percent ,
discount_amount: 100 ,
discount_message: 'Spend $75 or more and get a free Product X!' ,
},
]
# ================================ 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
# ================================================================
# SpendXGetYForZCampaign
#
# If the cart total is greater than (or equal to) the entered
# threshold (less the discounted amount), the entered number of
# matching items is discounted by the entered amount.
# ================================================================
class SpendXGetYForZCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
@campaigns . each do | campaign |
threshold = Money . new ( cents: 100 ) * campaign [ :threshold ]
next if cart . subtotal_price < threshold
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
eligible_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if eligible_items . nil?
eligible_items = eligible_items . sort_by { | line_item | line_item . variant . price }
num_to_discount = campaign [ :quantity_to_discount ]
cart_total = cart . subtotal_price
eligible_items . each do | line_item |
break if num_to_discount <= 0
if line_item . quantity > num_to_discount
cart_total -= line_item . variant . price * num_to_discount
break
else
cart_total -= line_item . line_price
num_to_discount -= line_item . quantity
end
end
next if cart_total < threshold
discount_applicator = discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
discount_loop = DiscountLoop . new ( discount_applicator )
discount_loop . loop_items ( cart , eligible_items , campaign [ :quantity_to_discount ])
end
end
end
CAMPAIGNS = [
SpendXGetYForZCampaign . new ( SPENDX_GETY_FORZ ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktrabatt nach Kunden-Tag Verwende dieses Skript, um Kunden mit bestimmten Tags einen Rabatt auf bestimmte Produkte zu gewähren.
Biete z. B. einen Rabatt in Höhe von 20 % an, wenn der Kunde ein VIP
-Tag hat.
# ================================ Customizable Settings ================================
# ================================================================
# Product Discounts by Customer Tag
#
# If we have a matching customer (by tag), the entered discount
# will be applied to any matching items.
#
# - 'customer_tag_match_type' determines whether we look for the customer
# to be tagged with any of the entered tags or not. Can be:
# - ':include' to check if the customer is tagged
# - ':exclude' to make sure the customer isn't tagged
# - 'customer_tags' is a list of tags to identify qualified
# customers
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
DISCOUNTS_FOR_CUSTOMER_TAG = [
{
customer_tag_match_type: :include ,
customer_tags: [ "VIP" ],
product_selector_match_type: :include ,
product_selector_type: :all ,
product_selectors: nil ,
discount_type: :percent ,
discount_amount: 20 ,
discount_message: "Discount for VIP customers!" ,
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# CustomerTagSelector
#
# Finds whether the supplied customer has any of the entered tags.
# ================================================================
class CustomerTagSelector
def initialize ( match_type , tags )
@comparator = match_type == :include ? 'any?' : 'none?'
@tags = tags . map { | tag | tag . downcase . strip }
end
def match? ( customer )
customer_tags = customer . tags . map { | tag | tag . downcase . strip }
( @tags & customer_tags ). send ( @comparator )
end
end
# ================================================================
# 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
# ================================================================
# DiscountForCustomerTagCampaign
#
# If we have a matching customer (by tag), the entered discount
# is applied to any matching items.
# ================================================================
class DiscountForCustomerTagCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
return unless cart . customer & . tags
@campaigns . each do | campaign |
customer_tag_selector = CustomerTagSelector . new ( campaign [ :customer_tag_match_type ], campaign [ :customer_tags ])
next unless customer_tag_selector . match? ( cart . customer )
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ]
)
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
DiscountForCustomerTagCampaign . new ( DISCOUNTS_FOR_CUSTOMER_TAG ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktrabatt bei Zustimmung zum Erhalt von Marketingmitteilungen Verwende dieses Skript, um Kunden, die dem Erhalt von Marketingmitteilungen zustimmen, einen Rabatt auf bestimmte Produkte zu gewähren.
Biete z. B. Kunden, die Marketing akzeptieren, einen Rabatt von 10 % auf alle Produkte an.
# ================================ Customizable Settings ================================
# ================================================================
# Product Discount by Customer Marketing
#
# If the customer accepts marketing, any matching items are
# discounted by the entered amount.
#
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNTS_BY_CUSTOMER_MARKETING = [
{
product_selector_match_type: :include ,
product_selector_type: :all ,
product_selectors: nil ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: '10% off for subscribed customers!'
}
]
# ================================ 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
# ================================================================
# ProductDiscountByCustomerMarketingCampaign
#
# If the customer accepts marketing, any matching items are
# discounted by the entered amount.
# ================================================================
class ProductDiscountByCustomerMarketingCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
return if cart . customer . nil?
@campaigns . each do | campaign |
next unless cart . customer . accepts_marketing?
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ]
)
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
ProductDiscountByCustomerMarketingCampaign . new ( PRODUCT_DISCOUNTS_BY_CUSTOMER_MARKETING ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktrabatt nach Anzahl der Bestellungen eines Kunden Verwende dieses Skript, um Kunden mit einer bestimmten Anzahl an Bestellungen einen Rabatt auf bestimmte Produkte zu gewähren.
Biete z. B. Kunden, die noch keine Bestellungen aufgegeben haben, einen Rabatt von 10 % an.
# ================================ Customizable Settings ================================
# ================================================================
# Product Discount by Order Count
#
# If the customer has made a matching number of orders, any
# matching items are discounted by the entered amount.
#
# - 'order_count_match_type' determines how we compare the
# customer's order count to the entered limit. Can be:
# - ':greater_than' to ensure that the customer's order count
# is greater than the entered limit
# - ':greater_than_equal' to ensure that the customer's order
# count is greater than, or equal to, the entered limit
# - ':less_than' to ensure that the customer's order count is
# less than the entered limit
# - ':less_than_equal' to ensure that the customer's order
# count is less than, or equal to, the entered limit
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
PRODUCT_DISCOUNTS_BY_ORDER_COUNT = [
{
order_count_match_type: :less_than ,
order_count_limit: 1 ,
product_selector_match_type: :include ,
product_selector_type: :all ,
product_selectors: nil ,
discount_type: :percent ,
discount_amount: 10 ,
discount_message: '10% off for first time customers!'
}
]
# ================================ Script Code (do not edit) ===============================
# ================================================================
# OrderCountSelector
#
# Finds whether the customer has made a certain number of orders
# ================================================================
class OrderCountSelector
def initialize ( match_type , limit )
@match_type = match_type
@limit = limit
end
def match? ( customer )
if self . respond_to? ( @match_type )
self . send ( @match_type , customer , @limit )
else
raise RuntimeError . new ( 'Invalid order count match type' )
end
end
def greater_than ( customer , limit )
customer . orders_count > limit
end
def greater_than_equal ( customer , limit )
customer . orders_count >= limit
end
def less_than ( customer , limit )
customer . orders_count < limit
end
def less_than_equal ( customer , limit )
customer . orders_count <= limit
end
end
# ================================================================
# 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
# ================================================================
# ProductDiscountByOrderCountCampaign
#
# If the customer has made a matching number of orders, any
# matching items are discounted by the entered amount.
# ================================================================
class ProductDiscountByOrderCountCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
return if cart . customer . nil?
@campaigns . each do | campaign |
order_count_selector = OrderCountSelector . new (
campaign [ :order_count_match_type ],
campaign [ :order_count_limit ]
)
next unless order_count_selector . match? ( cart . customer )
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ]
)
discount_applicator = DiscountApplicator . new (
campaign [ :discount_type ],
campaign [ :discount_amount ],
campaign [ :discount_message ]
)
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
discount_applicator . apply ( line_item )
end
end
end
end
CAMPAIGNS = [
ProductDiscountByOrderCountCampaign . new ( PRODUCT_DISCOUNTS_BY_ORDER_COUNT ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Rabattcodes deaktivieren Verwende dieses Skript, um die Verwendung von Rabattcodes im Checkout-Prozess zu deaktivieren.
Verhindere z. B., dass Kunden Rabattcodes anwenden, wenn dein Shop einen Sale anbietet.
# ================================ Customizable Settings ================================
# ================================================================
# Disable Discount Code Use
#
# Any discount codes will be rejected with the entered message.
#
# - 'REJECTION_MESSAGE' is the message to show when a discount
# code is rejected
# ================================================================
REJECTION_MESSAGE = 'Discount codes cannot be used during this sale'
# ================================ Script Code (do not edit) ================================
# ================================================================
# DisableDiscountCodesCampaign
#
# Any discount codes will be rejected with the entered message.
# ================================================================
class DisableDiscountCodesCampaign
def initialize ( rejection_message )
@rejection_message = rejection_message
end
def run ( cart )
return if cart . discount_code . nil?
cart . discount_code . reject ( message: @rejection_message )
end
end
CAMPAIGNS = [
DisableDiscountCodesCampaign . new ( REJECTION_MESSAGE ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Rabattcodes für Produkte deaktivieren Verwende dieses Skript, um die Anwendung von Rabattcodes im Checkout-Prozess zu deaktivieren, wenn sich bestimmte Produkte im Warenkorb befinden.
Verhindere z. B., dass Kunden Rabattcodes anwenden, wenn sich ein Produkt mit einem discounted
-Tag im Warenkorb befindet.
# ================================ Customizable Settings ================================
# ================================================================
# Disable Discount Code(s) For Products
#
# If any matching discount codes are used, and any matching items
# are in the cart, the discount code is rejected with the entered
# message.
#
# - 'discount_code_match_type' determines whether the below
# strings should be an exact or partial match. Can be:
# - ':exact' for an exact match
# - ':partial' for a partial match
# - 'discount_codes' is a list of strings to identify discount
# codes
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'rejection_message' is the message to show when a discount
# code is rejected
# ================================================================
REJECT_DISCOUNT_CODE_FOR_PRODUCTS = [
{
discount_code_match_type: :exact ,
discount_codes: [ "TESTCODE1" , "TESTCODE2" ],
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "discounted" ],
rejection_message: "Discount codes can't be used with 'discounted' products"
}
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# DiscountCodeSelector
#
# Finds whether the supplied discount code matches any of the
# entered codes.
# ================================================================
class DiscountCodeSelector
def initialize ( match_type , discount_codes )
@comparator = match_type == :exact ? '==' : 'include?'
@discount_codes = discount_codes . map { | discount_code | discount_code . upcase . strip }
end
def match? ( discount_code )
@discount_codes . any? { | code | discount_code . code . upcase . send ( @comparator , code ) }
end
end
# ================================================================
# 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
# ================================================================
# DisableDiscountCodesForProductsCampaign
#
# If any matching discount codes are used, and any matching items
# are in the cart, the discount code is rejected with the entered
# message.
# ================================================================
class DisableDiscountCodesForProductsCampaign
def initialize ( campaigns )
@campaigns = campaigns
end
def run ( cart )
return if cart . discount_code . nil?
@campaigns . each do | campaign |
discount_code_selector = DiscountCodeSelector . new (
campaign [ :discount_code_match_type ],
campaign [ :discount_codes ]
)
next unless discount_code_selector . match? ( cart . discount_code )
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ],
)
next unless cart . line_items . any? { | line_item | product_selector . match? ( line_item ) }
cart . discount_code . reject ( message: campaign [ :rejection_message ])
end
end
end
CAMPAIGNS = [
DisableDiscountCodesForProductsCampaign . new ( REJECT_DISCOUNT_CODE_FOR_PRODUCTS ),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart
Produktmengen beschränken Verwende dieses Skript, um Mengenbeschränkungen für bestimmte Produkte anzuwenden.
Verhindere z. B., dass Kunden in einer Bestellung mehr als ein "Produkt X" kaufen.
Hinweis
Dieses Skript verhindert nicht, dass die Artikel zunächst hinzugefügt werden. Es entfernt nur überzählige Artikel im Nachhinein. Kunden sehen keinen Hinweis darauf, dass diese Artikel aus dem Warenkorb entfernt wurden.
# ================================ Customizable Settings ================================
# ================================================================
# Product Quantity Limits
#
# If the quantity of any matching items is greater than the
# entered threshold, the excess items are removed from the cart.
# It should be noted that there will be no notice to the customer
# when this happens.
#
# - 'enable' determines whether the campaign will run. Can be:
# - 'true' to run
# - 'false' to not run
# - 'product_selector_match_type' determines whether we look for
# products that do or don't match the entered selectors. Can
# be:
# - ':include' to check if the product does match
# - ':exclude' to make sure the product doesn't match
# - 'product_selector_type' determines how eligible products
# will be identified. Can be either:
# - ':tag' to find products by tag
# - ':type' to find products by type
# - ':vendor' to find products by vendor
# - ':product_id' to find products by ID
# - ':variant_id' to find products by variant ID
# - ':subscription' to find subscription products
# - ':all' for all products
# - 'product_selectors' is a list of identifiers (from above)
# for qualifying products. Product/Variant ID lists should
# only contain numbers (ie. no quotes). If ':all' is used,
# this can also be 'nil'.
# - 'variant_level_limit' determines whether the below limit
# is applied on a variant, or a total quantity, level. For
# example, can I have X number of individual matching items,
# or can I only have X number total of matching items?
# Can be:
# - 'true' to limit at a variant level
# - 'false' to limit total quantity
# - 'quantity_allowed' is the number of products allowed
# ================================================================
QUANTITY_LIMITS = {
enable: true ,
campaigns: [
{
product_selector_match_type: :include ,
product_selector_type: :tag ,
product_selectors: [ "limited" ],
variant_level_limit: true ,
quantity_allowed: 2 ,
},
]
}
# ================================ 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
# ================================================================
# ProductQuantityLimitCampaign
#
# If the quantity of any matching items is greater than the
# entered threshold, the excess items are removed from the cart.
# ================================================================
class ProductQuantityLimitCampaign
def initialize ( enable , campaigns )
@enable = enable
@campaigns = campaigns
end
def run ( cart )
return unless @enable
@campaigns . each do | campaign |
product_selector = ProductSelector . new (
campaign [ :product_selector_match_type ],
campaign [ :product_selector_type ],
campaign [ :product_selectors ]
)
if campaign [ :variant_level_limit ]
applicable_items = {}
cart . line_items . each do | line_item |
next unless product_selector . match? ( line_item )
id = line_item . variant . id
if applicable_items [ id ]. nil?
applicable_items [ id ] = {
items: [],
total_quantity: 0
}
end
applicable_items [ id ][ :items ]. push ( line_item )
applicable_items [ id ][ :total_quantity ] += line_item . quantity
end
next if applicable_items . nil?
applicable_items . each do | id , info |
next unless info [ :total_quantity ] > campaign [ :quantity_allowed ]
num_to_remove = info [ :total_quantity ] - campaign [ :quantity_allowed ]
self . loop_items ( cart , info [ :items ], num_to_remove )
end
else
applicable_items = cart . line_items . select { | line_item | product_selector . match? ( line_item ) }
next if applicable_items . nil?
total_quantity = applicable_items . map ( & :quantity ). reduce ( 0 , : + )
next unless total_quantity > campaign [ :quantity_allowed ]
num_to_remove = total_quantity - campaign [ :quantity_allowed ]
self . loop_items ( cart , applicable_items , num_to_remove )
end
end
end
def loop_items ( cart , line_items , num_to_remove )
line_items . each do | line_item |
if line_item . quantity > num_to_remove
split_line_item = line_item . split ( take: num_to_remove )
break
else
index = cart . line_items . find_index ( line_item )
cart . line_items . delete_at ( index )
num_to_remove -= line_item . quantity
end
break if num_to_remove <= 0
end
end
end
CAMPAIGNS = [
ProductQuantityLimitCampaign . new (
QUANTITY_LIMITS [ :enable ],
QUANTITY_LIMITS [ :campaigns ],
),
]
CAMPAIGNS . each do | campaign |
campaign . run ( Input . cart )
end
Output . cart = Input . cart