Class: SolidusPromotions::Calculators::FlexiRate

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

Overview

A calculator that applies different discount amounts for the first item and additional items.

This calculator allows setting a discount for the first item in a line item and a different discount for each additional item. Optionally, a maximum number of items can be specified to limit the discount calculation.

Examples:

# $5 off first item, $2 off each additional item, max 5 items
calculator = FlexiRate.new(
  preferred_first_item: 5,
  preferred_additional_item: 2,
  preferred_max_items: 5
)
# Line item with quantity 3: $5 + ($2 × 2) = $9 discount
# Line item with quantity 10: $5 + ($2 × 4) = $13 discount (limited to 5 items)

Instance Method Summary collapse

Methods included from PromotionCalculator

#description

Instance Method Details

#compute_line_item(line_item) ⇒ BigDecimal

Computes the discount amount for a line item based on its quantity.

Calculates the total discount by applying the first_item rate to the first unit and the additional_item rate to remaining units. If max_items is set (non-zero), the calculation is limited to that number of items.

Examples:

Computing discount for a line item with 3 items

calculator = FlexiRate.new(preferred_first_item: 10, preferred_additional_item: 5)
line_item.quantity # => 3
calculator.compute_line_item(line_item) # => 20.0 (10 + 5 + 5)

Computing discount with max_items limit

calculator = FlexiRate.new(
  preferred_first_item: 10,
  preferred_additional_item: 5,
  preferred_max_items: 2
)
line_item.quantity # => 5
calculator.compute_line_item(line_item) # => 15.0 (10 + 5, limited to 2 items)

Parameters:

  • line_item (Spree::LineItem)

    The line item to calculate the discount for

Returns:

  • (BigDecimal)

    The total discount amount based on quantity and preferences



53
54
55
# File 'app/models/solidus_promotions/calculators/flexi_rate.rb', line 53

def compute_line_item(line_item)
  compute_for_quantity(line_item.quantity)
end

#compute_price(price, options = {}) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'app/models/solidus_promotions/calculators/flexi_rate.rb', line 57

def compute_price(price, options = {})
  order = options[:order]
  desired_quantity = options[:quantity] || 0
  return Spree::ZERO if desired_quantity.zero?

  already_ordered_quantity = if order
    order.line_items.detect do |line_item|
      line_item.variant == price.variant
    end&.quantity || 0
  else
    0
  end
  possible_discount = compute_for_quantity(already_ordered_quantity + desired_quantity)
  existing_discount = compute_for_quantity(already_ordered_quantity)
  round_to_currency(
    (possible_discount - existing_discount) / desired_quantity,
    price.currency
  )
end