Class: SolidusPromotions::Calculators::TieredPercent

Inherits:
Spree::Calculator
  • Object
show all
Includes:
PromotionCalculator
Defined in:
app/models/solidus_promotions/calculators/tiered_percent.rb

Overview

A calculator that applies tiered percentage-based discounts based on order item total thresholds.

This calculator allows defining multiple discount tiers where each tier specifies a minimum order item total threshold and the corresponding percentage discount to apply to the individual item. The calculator selects the highest tier that the order qualifies for based on its item total.

Unlike TieredFlatRate which applies a fixed amount, this calculator applies a percentage of the item’s amount. The tier thresholds are evaluated against the entire order’s item total, but the percentage discount is applied to the individual item (line item or shipment).

If the order doesn’t meet any tier threshold, the base percentage is used. The discount is only applied if the currency matches the preferred currency.

Examples:

Use case: Volume-based percentage discounts

# Higher discounts for larger orders
calculator = TieredPercent.new(
  preferred_base_percent: 5,
  preferred_tiers: {
    100 => 10,  # 10% off when order total >= $100
    250 => 15,  # 15% off when order total >= $250
    500 => 20   # 20% off when order total >= $500
  },
  preferred_currency: 'USD'
)

Use case: Wholesale tier pricing

# Different percentage discounts for different order sizes
calculator = TieredPercent.new(
  preferred_base_percent: 0,
  preferred_tiers: {
    200 => 5,    # 5% wholesale discount at $200
    500 => 10,   # 10% wholesale discount at $500
    1000 => 15   # 15% wholesale discount at $1000
  },
  preferred_currency: 'USD'
)

Instance Method Summary collapse

Methods included from PromotionCalculator

#description

Instance Method Details

#compute_item(object) ⇒ BigDecimal Also known as: compute_shipment, compute_line_item

Computes the tiered percentage discount for an item based on the order’s item total.

Evaluates the order’s item total against all defined tiers and selects the highest tier threshold that the order meets or exceeds. Returns a percentage of the item’s amount based on the matching tier, or the base percentage if no tier threshold is met. Returns 0 if the currency doesn’t match.

Examples:

Computing discount with tier matching

calculator = TieredPercent.new(
  preferred_base_percent: 5,
  preferred_tiers: { 100 => 10, 250 => 15 }
)
order.item_total # => 150.00
line_item.amount # => 50.00
calculator.compute_item(line_item) # => 5.00 (10% of $50, matches $100 tier)

Computing discount below all tiers

calculator = TieredPercent.new(
  preferred_base_percent: 5,
  preferred_tiers: { 100 => 10, 250 => 15 }
)
order.item_total # => 75.00
line_item.amount # => 30.00
calculator.compute_item(line_item) # => 1.50 (5% base percent of $30)

Computing discount with currency mismatch

calculator = TieredPercent.new(
  preferred_currency: 'USD',
  preferred_tiers: { 100 => 10 }
)
order.currency # => 'EUR'
calculator.compute_item(line_item) # => 0

Parameters:

  • object (Object)

    The object to calculate the discount for (e.g., LineItem, Shipment)

Returns:

  • (BigDecimal)

    The percentage-based discount amount, rounded to currency precision



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/models/solidus_promotions/calculators/tiered_percent.rb', line 94

def compute_item(object)
  order = object.order

  _base, percent = preferred_tiers.sort.reverse.detect do |value, _|
    order.item_total >= value
  end

  if preferred_currency.casecmp(order.currency).zero?
    round_to_currency(object.amount * (percent || preferred_base_percent) / 100, preferred_currency)
  else
    Spree::ZERO
  end
end