Skip to content

Commit

Permalink
Add ability to remove promotions via Promotion#remove_from
Browse files Browse the repository at this point in the history
  • Loading branch information
jordan-brough committed Sep 17, 2016
1 parent f74c9a0 commit 0be285f
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 3 deletions.
14 changes: 14 additions & 0 deletions core/app/models/spree/promotion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,20 @@ def used_by?(user, excluded_orders = [])
end
end

# Removes a promotion and any adjustments or other side effects from an
# order.
# @param order [Spree::Order] the order to remove the promotion from.
# @return [undefined]
def remove_from(order)
actions.each do |action|
action.remove_from(order)
end
# note: this destroys the join table entry, not the promotion itself
order.promotions.destroy(self)
order.order_promotions.reset
order_promotions.reset
end

private

def blacklisted?(promotable)
Expand Down
10 changes: 10 additions & 0 deletions core/app/models/spree/promotion/actions/create_adjustment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ def compute_amount(calculable)
[(calculable.item_total + calculable.ship_total), amount].min * -1
end

# Removes any adjustments generated by this action from the order.
# @param order [Spree::Order] the order to remove the action from.
def remove_from(order)
order.adjustments.each do |adjustment|
if adjustment.source == self
order.adjustments.destroy(adjustment)
end
end
end

private

# Tells us if there if the specified promotion is already associated with the line item
Expand Down
13 changes: 13 additions & 0 deletions core/app/models/spree/promotion/actions/create_item_adjustments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ def compute_amount(adjustable)
[adjustable.amount, promotion_amount].min * -1
end

# Removes any adjustments generated by this action from the order's
# line items.
# @param order [Spree::Order] the order to remove the action from.
def remove_from(order)
order.line_items.each do |line_item|
line_item.adjustments.each do |adjustment|
if adjustment.source == self
line_item.adjustments.destroy(adjustment)
end
end
end
end

private

def create_adjustment(adjustable, order, promotion_code)
Expand Down
13 changes: 13 additions & 0 deletions core/app/models/spree/promotion/actions/free_shipping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ def compute_amount(shipment)
shipment.cost * -1
end

# Removes any adjustments generated by this action from the order's
# shipments.
# @param order [Spree::Order] the order to remove the action from.
def remove_from(order)
order.shipments.each do |shipment|
shipment.adjustments.each do |adjustment|
if adjustment.source == self
shipment.adjustments.destroy(adjustment)
end
end
end
end

private

def promotion_credit_exists?(shipment)
Expand Down
17 changes: 17 additions & 0 deletions core/app/models/spree/promotion_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,22 @@ class PromotionAction < Spree::Base
def perform(_options = {})
raise 'perform should be implemented in a sub-class of PromotionAction'
end

# Removes the action from an order
#
# @note This method should be overriden in subclassses.
#
# @param order [Spree::Order] the order to remove the action from
# @return [undefined]
def remove_from(order)
Spree::Deprecation.warn("#{self.class.name.inspect} does not define #remove_from. The default behavior may be incorrect and will be removed in a future version of Solidus.", caller)
[order, *order.line_items, *order.shipments].each do |item|
item.adjustments.each do |adjustment|
if adjustment.source == self
item.adjustments.destroy(adjustment)
end
end
end
end
end
end
21 changes: 21 additions & 0 deletions core/spec/models/spree/promotion/actions/create_adjustment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,27 @@
end
end

describe '#remove_from' do
let(:action) { promotion.actions.first! }
let(:promotion) { create(:promotion, :with_order_adjustment) }

# this adjustment should not get removed
let!(:other_adjustment) { create(:adjustment, order: order, source: nil) }

before do
action.perform(payload)
@action_adjustment = order.adjustments.where(source: action).first!
end

it 'removes the action adjustment' do
expect(order.adjustments).to match_array([other_adjustment, @action_adjustment])

action.remove_from(order)

expect(order.adjustments).to eq([other_adjustment])
end
end

context "#destroy" do
before(:each) do
action.calculator = Spree::Calculator::FlatRate.new(preferred_amount: 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ module Actions
end
end

describe '#remove_from' do
# this adjustment should not get removed
let!(:other_adjustment) { create(:adjustment, adjustable: line_item, order: order, source: nil) }

before do
action.perform(payload)
@action_adjustment = line_item.adjustments.where(source: action).first!
end

it 'removes the action adjustment' do
expect(line_item.adjustments).to match_array([other_adjustment, @action_adjustment])

action.remove_from(order)

expect(line_item.adjustments).to eq([other_adjustment])
end
end

context "#destroy" do
let!(:action) { promotion.actions.first }
let(:other_action) { other_promotion.actions.first }
Expand Down
25 changes: 22 additions & 3 deletions core/spec/models/spree/promotion/actions/free_shipping_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

describe Spree::Promotion::Actions::FreeShipping, type: :model do
let(:order) { create(:completed_order_with_totals) }
let(:promotion_code) { create(:promotion_code, value: 'somecode') }
let(:promotion) { promotion_code.promotion }
let(:action) { Spree::Promotion::Actions::FreeShipping.create }
let(:shipment) { order.shipments.to_a.first }
let(:promotion) { create(:promotion, code: 'somecode', promotion_actions: [action]) }
let(:action) { Spree::Promotion::Actions::FreeShipping.new }
let(:payload) { { order: order, promotion_code: promotion_code } }
let(:promotion_code) { promotion.codes.first! }

# From promotion spec:
context "#perform" do
Expand Down Expand Up @@ -37,4 +38,22 @@
end
end
end

describe '#remove_from' do
# this adjustment should not get removed
let!(:other_adjustment) { create(:adjustment, adjustable: shipment, order: order, source: nil) }

before do
action.perform(payload)
@action_adjustment = shipment.adjustments.where(source: action).first!
end

it 'removes the action adjustment' do
expect(shipment.adjustments).to match_array([other_adjustment, @action_adjustment])

action.remove_from(order)

expect(shipment.adjustments).to eq([other_adjustment])
end
end
end
38 changes: 38 additions & 0 deletions core/spec/models/spree/promotion_action_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'spec_helper'

describe Spree::PromotionAction, type: :model do
describe '#remove_from' do
class MyPromotionAction < Spree::PromotionAction
def perform(options = {})
order = options[:order]
order.adjustments.create!(amount: 1, order: order, source: self, label: 'foo')
true
end
end

let(:action) { promotion.actions.first! }
let!(:promotion) { create(:promotion, promotion_actions: [MyPromotionAction.new]) }
let(:order) { create(:order) }

# this adjustment should not get removed
let!(:other_adjustment) { create(:adjustment, order: order, source: nil) }

before do
action.perform(order: order)
@action_adjustment = order.adjustments.where(source: action).first!
end

it 'removes the action adjustment' do
expect(order.adjustments).to match_array([other_adjustment, @action_adjustment])

expect(Spree::Deprecation).to(
receive(:warn).
with(/"MyPromotionAction" does not define #remove_from/, anything)
)

action.remove_from(order)

expect(order.adjustments).to eq([other_adjustment])
end
end
end
19 changes: 19 additions & 0 deletions core/spec/models/spree/promotion_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,25 @@
end
end

describe '#remove_from' do
let(:promotion) { create(:promotion, :with_line_item_adjustment) }
let(:order) { create(:order_with_line_items) }

before do
promotion.activate(order: order)
end

it 'removes the promotion' do
expect(order.promotions).to include(promotion)
expect(order.line_items.flat_map(&:adjustments)).to be_present

promotion.remove_from(order)

expect(order.promotions).to be_empty
expect(order.line_items.flat_map(&:adjustments)).to be_empty
end
end

describe "#usage_limit_exceeded?" do
subject { promotion.usage_limit_exceeded? }

Expand Down

0 comments on commit 0be285f

Please sign in to comment.