Class: Spree::Promotion::Actions::CreateLineItems

Inherits:
Spree::PromotionAction show all
Defined in:
app/models/spree/promotion/actions/create_line_items.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Spree::PromotionAction

#free_shipping?, human_description, #human_description, human_name, #human_name, #key

Class Method Details

.additional_permitted_attributesObject



11
12
13
# File 'app/models/spree/promotion/actions/create_line_items.rb', line 11

def self.additional_permitted_attributes
  [line_items: [:variant_id, :quantity]]
end

Instance Method Details

#item_available?(item) ⇒ Boolean

Checks that there’s enough stock to add the line item to the order

Returns:



92
93
94
95
# File 'app/models/spree/promotion/actions/create_line_items.rb', line 92

def item_available?(item)
  quantifier = Spree::Stock::Quantifier.new(item.variant)
  quantifier.can_supply? item.quantity
end

#line_items=(rows) ⇒ Object

API v3 flat alias for ‘promotion_action_line_items_attributes`. Accepts an array of `{ variant_id:, quantity: }` rows; the list is the desired set, so anything missing on save is removed.



18
19
20
# File 'app/models/spree/promotion/actions/create_line_items.rb', line 18

def line_items=(rows)
  self.promotion_action_line_items_attributes = rows
end

#perform(options = {}) ⇒ Object

Adds a line item to the Order if the promotion is eligible

This doesn’t play right with Add to Cart events because at the moment the item was added to cart the promo may not be eligible. However it might become eligible as the order gets updated.

e.g.

- A promo adds a line item to cart if order total greater then $30
- Customer add 1 item of $10 to cart
- This action shouldn't perform because the order is not eligible
- Customer increases item quantity to 5 (order total goes to $50)
- Now the order is eligible for the promo and the action should perform

Another complication is when the same line item created by the promo is also added to cart on a separate action.

e.g.

- Promo adds 1 item A to cart if order total greater then $30
- Customer add 2 items B to cart, current order total is $40
- This action performs adding item A to cart since order is eligible
- Customer changes his mind and updates item B quantity to 1
- At this point order is no longer eligible and one might expect
  that item A should be removed

It doesn’t remove items from the order here because there’s no way it can know whether that item was added via this promo action or if it was manually populated somewhere else. In that case the item needs to be manually removed from the order by the customer



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/models/spree/promotion/actions/create_line_items.rb', line 52

def perform(options = {})
  order = options[:order]
  return unless eligible? order

  action_taken = false
  promotion_action_line_items.each do |item|
    current_quantity = order.quantity_of(item.variant)
    next unless current_quantity < item.quantity && item_available?(item)

    line_item = Spree.cart_add_item_service.call(order: order,
                                                 variant: item.variant,
                                                 quantity: item.quantity - current_quantity).value
    action_taken = true if line_item.try(:valid?)
  end
  action_taken
end

#revert(options = {}) ⇒ Object

Called by promotion handler when a promotion is removed This will find any line item matching the ones defined in the PromotionAction and remove the same quantity as was added by the PromotionAction. Should help to prevent some of cases listed above the #perform method



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/models/spree/promotion/actions/create_line_items.rb', line 73

def revert(options = {})
  order = options[:order]
  return if eligible?(order)

  action_taken = false
  promotion_action_line_items.each do |item|
    line_item = order.find_line_item_by_variant(item.variant)
    next unless line_item.present?

    Spree.cart_remove_item_service.call(order: order,
                                        variant: item.variant,
                                        quantity: (item.quantity || 1))
    action_taken = true
  end

  action_taken
end