spree_promo 1.1.1 → 1.1.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -40,19 +40,15 @@ var initProductActions = function(){
40
40
 
41
41
  // Remove line item
42
42
  var setupRemoveLineItems = function(){
43
- $(".promotion_action.create_line_items table img").unbind('click').click(function(){
44
- var $container = $(this).parents('.promotion_action');
45
- var $hiddenField = $container.find("input[type='hidden']");
46
- var $row = $(this).parents('tr');
47
- var index = $row.parents('table').find('tr').index($row.get(0));
48
- // Remove variant_id quantity pair from the string
49
- var items = _($hiddenField.val().split(',')).compact();
50
- items.splice(index - 1, 1);
51
- $hiddenField.val(items.join(','));
43
+ $(".remove_promotion_line_item").click(function(){
44
+ line_items_el = $($('.line_items_string')[0])
45
+ finder = RegExp($(this).data("variant-id") + "x\\d+")
46
+ line_items_el.val(line_items_el.val().replace(finder, ""))
52
47
  $(this).parents('tr').remove();
53
48
  hideOrShowItemTables();
54
49
  });
55
50
  };
51
+
56
52
  setupRemoveLineItems();
57
53
  // Add line item to list
58
54
  $(".promotion_action.create_line_items button.add").unbind('click').click(function(e){
@@ -18,7 +18,12 @@ Spree::Order.class_eval do
18
18
  update_adjustments_without_promotion_limiting
19
19
  return if adjustments.promotion.eligible.none?
20
20
  most_valuable_adjustment = adjustments.promotion.eligible.max{|a,b| a.amount.abs <=> b.amount.abs}
21
- ( adjustments.promotion.eligible - [most_valuable_adjustment] ).each{|adjustment| adjustment.update_attribute_without_callbacks(:eligible, false)}
21
+ current_adjustments = (adjustments.promotion.eligible - [most_valuable_adjustment])
22
+ current_adjustments.each do |adjustment|
23
+ if adjustment.originator.calculator.is_a?(Spree::Calculator::PerItem)
24
+ adjustment.update_attribute_without_callbacks(:eligible, false)
25
+ end
26
+ end
22
27
  end
23
28
  alias_method_chain :update_adjustments, :promotion_limiting
24
29
  end
@@ -1,43 +1,48 @@
1
1
  module Spree
2
- class Promotion::Actions::CreateAdjustment < PromotionAction
3
- calculated_adjustments
2
+ class Promotion
3
+ module Actions
4
+ class CreateAdjustment < PromotionAction
5
+ calculated_adjustments
4
6
 
5
- delegate :eligible?, :to => :promotion
7
+ delegate :eligible?, :to => :promotion
6
8
 
7
- before_validation :ensure_action_has_calculator
9
+ before_validation :ensure_action_has_calculator
8
10
 
9
- def perform(options = {})
10
- return unless order = options[:order]
11
- # Nothing to do if the promotion is already associated with the order
12
- return if order.promotion_credit_exists?(promotion)
11
+ def perform(options = {})
12
+ return unless order = options[:order]
13
+ # Nothing to do if the promotion is already associated with the order
14
+ return if order.promotion_credit_exists?(promotion)
13
15
 
14
- order.adjustments.promotion.reload.clear
15
- order.update!
16
- create_adjustment("#{I18n.t(:promotion)} (#{promotion.name})", order, order)
17
- end
16
+ order.adjustments.promotion.reload.clear
17
+ order.update!
18
+ create_adjustment("#{I18n.t(:promotion)} (#{promotion.name})", order, order)
19
+ order.update!
20
+ end
18
21
 
19
- # override of CalculatedAdjustments#create_adjustment so promotional
20
- # adjustments are added all the time. They will get their eligability
21
- # set to false if the amount is 0
22
- def create_adjustment(label, target, calculable, mandatory=false)
23
- amount = compute_amount(calculable)
24
- params = { :amount => amount,
25
- :source => calculable,
26
- :originator => self,
27
- :label => label,
28
- :mandatory => mandatory }
29
- target.adjustments.create(params, :without_protection => true)
30
- end
22
+ # override of CalculatedAdjustments#create_adjustment so promotional
23
+ # adjustments are added all the time. They will get their eligability
24
+ # set to false if the amount is 0
25
+ def create_adjustment(label, target, calculable, mandatory=false)
26
+ amount = compute_amount(calculable)
27
+ params = { :amount => amount,
28
+ :source => calculable,
29
+ :originator => self,
30
+ :label => label,
31
+ :mandatory => mandatory }
32
+ target.adjustments.create(params, :without_protection => true)
33
+ end
31
34
 
32
- # Ensure a negative amount which does not exceed the sum of the order's item_total and ship_total
33
- def compute_amount(calculable)
34
- [(calculable.item_total + calculable.ship_total), super.to_f.abs].min * -1
35
- end
35
+ # Ensure a negative amount which does not exceed the sum of the order's item_total and ship_total
36
+ def compute_amount(calculable)
37
+ [(calculable.item_total + calculable.ship_total), super.to_f.abs].min * -1
38
+ end
36
39
 
37
- private
38
- def ensure_action_has_calculator
39
- return if self.calculator
40
- self.calculator = Calculator::FlatPercentItemTotal.new
40
+ private
41
+ def ensure_action_has_calculator
42
+ return if self.calculator
43
+ self.calculator = Calculator::FlatPercentItemTotal.new
44
+ end
45
+ end
41
46
  end
42
47
  end
43
- end
48
+ end
@@ -1,31 +1,36 @@
1
1
  module Spree
2
- class Promotion::Actions::CreateLineItems < PromotionAction
3
- has_many :promotion_action_line_items, :foreign_key => 'promotion_action_id'
2
+ class Promotion
3
+ module Actions
4
+ class CreateLineItems < PromotionAction
5
+ has_many :promotion_action_line_items, :foreign_key => 'promotion_action_id'
4
6
 
5
- attr_accessor :line_items_string
7
+ attr_accessor :line_items_string
6
8
 
7
- def perform(options = {})
8
- return unless order = options[:order]
9
- promotion_action_line_items.each do |item|
10
- current_quantity = order.quantity_of(item.variant)
11
- if current_quantity < item.quantity
12
- order.add_variant(item.variant, item.quantity - current_quantity)
9
+ def perform(options = {})
10
+ return unless order = options[:order]
11
+ promotion_action_line_items.each do |item|
12
+ current_quantity = order.quantity_of(item.variant)
13
+ if current_quantity < item.quantity
14
+ order.add_variant(item.variant, item.quantity - current_quantity)
15
+ order.update!
16
+ end
17
+ end
13
18
  end
14
- end
15
- end
16
19
 
17
- def line_items_string
18
- promotion_action_line_items.map { |li| "#{li.variant_id}x#{li.quantity}" }.join(',')
19
- end
20
+ def line_items_string
21
+ promotion_action_line_items.map { |li| "#{li.variant_id}x#{li.quantity}" }.join(',')
22
+ end
20
23
 
21
- def line_items_string=(value)
22
- promotion_action_line_items.destroy_all
23
- value.to_s.split(',').each do |str|
24
- variant_id, quantity = str.split('x')
25
- if variant_id && quantity && variant = Variant.find_by_id(variant_id)
26
- promotion_action_line_items.create({:variant => variant, :quantity => quantity.to_i}, :without_protection => true)
24
+ def line_items_string=(value)
25
+ promotion_action_line_items.destroy_all
26
+ value.to_s.split(',').each do |str|
27
+ variant_id, quantity = str.split('x')
28
+ if variant_id && quantity && variant = Variant.find_by_id(variant_id)
29
+ promotion_action_line_items.create({:variant => variant, :quantity => quantity.to_i}, :without_protection => true)
30
+ end
31
+ end
27
32
  end
28
33
  end
29
34
  end
30
35
  end
31
- end
36
+ end
@@ -1,8 +1,12 @@
1
1
  module Spree
2
- class Promotion::Rules::FirstOrder < PromotionRule
3
- def eligible?(order, options = {})
4
- user = order.try(:user) || options[:user]
5
- !!(user && user.orders.complete.count == 0)
2
+ class Promotion
3
+ module Rules
4
+ class FirstOrder < PromotionRule
5
+ def eligible?(order, options = {})
6
+ user = order.try(:user) || options[:user]
7
+ !!(user && user.orders.complete.count == 0)
8
+ end
9
+ end
6
10
  end
7
11
  end
8
12
  end
@@ -1,16 +1,20 @@
1
1
  # A rule to limit a promotion to a specific user.
2
2
  module Spree
3
- class Promotion::Rules::ItemTotal < PromotionRule
4
- preference :amount, :decimal, :default => 100.00
5
- preference :operator, :string, :default => '>'
3
+ class Promotion
4
+ module Rules
5
+ class ItemTotal < PromotionRule
6
+ preference :amount, :decimal, :default => 100.00
7
+ preference :operator, :string, :default => '>'
6
8
 
7
- attr_accessible :preferred_amount, :preferred_operator
9
+ attr_accessible :preferred_amount, :preferred_operator
8
10
 
9
- OPERATORS = ['gt', 'gte']
11
+ OPERATORS = ['gt', 'gte']
10
12
 
11
- def eligible?(order, options = {})
12
- item_total = order.line_items.map(&:amount).sum
13
- item_total.send(preferred_operator == 'gte' ? :>= : :>, BigDecimal.new(preferred_amount.to_s))
13
+ def eligible?(order, options = {})
14
+ item_total = order.line_items.map(&:amount).sum
15
+ item_total.send(preferred_operator == 'gte' ? :>= : :>, BigDecimal.new(preferred_amount.to_s))
16
+ end
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -2,32 +2,45 @@
2
2
  # Can require all or any of the products to be present.
3
3
  # Valid products either come from assigned product group or are assingned directly to the rule.
4
4
  module Spree
5
- class Promotion::Rules::Product < PromotionRule
6
- has_and_belongs_to_many :products, :class_name => '::Spree::Product', :join_table => 'spree_products_promotion_rules', :foreign_key => 'promotion_rule_id'
5
+ class Promotion
6
+ module Rules
7
+ class Product < PromotionRule
8
+ has_and_belongs_to_many :products, :class_name => '::Spree::Product', :join_table => 'spree_products_promotion_rules', :foreign_key => 'promotion_rule_id'
9
+ validate :only_one_promotion_per_product
7
10
 
8
- MATCH_POLICIES = %w(any all)
9
- preference :match_policy, :string, :default => MATCH_POLICIES.first
11
+ MATCH_POLICIES = %w(any all)
12
+ preference :match_policy, :string, :default => MATCH_POLICIES.first
10
13
 
11
- # scope/association that is used to test eligibility
12
- def eligible_products
13
- products
14
- end
14
+ # scope/association that is used to test eligibility
15
+ def eligible_products
16
+ products
17
+ end
15
18
 
16
- def eligible?(order, options = {})
17
- return true if eligible_products.empty?
18
- if preferred_match_policy == 'all'
19
- eligible_products.all? {|p| order.products.include?(p) }
20
- else
21
- order.products.any? {|p| eligible_products.include?(p) }
22
- end
23
- end
19
+ def eligible?(order, options = {})
20
+ return true if eligible_products.empty?
21
+ if preferred_match_policy == 'all'
22
+ eligible_products.all? {|p| order.products.include?(p) }
23
+ else
24
+ order.products.any? {|p| eligible_products.include?(p) }
25
+ end
26
+ end
24
27
 
25
- def product_ids_string
26
- product_ids.join(',')
27
- end
28
+ def product_ids_string
29
+ product_ids.join(',')
30
+ end
28
31
 
29
- def product_ids_string=(s)
30
- self.product_ids = s.to_s.split(',').map(&:strip)
32
+ def product_ids_string=(s)
33
+ self.product_ids = s.to_s.split(',').map(&:strip)
34
+ end
35
+
36
+ private
37
+
38
+ def only_one_promotion_per_product
39
+ if Spree::Promotion::Rules::Product.all.map(&:products).flatten.uniq!
40
+ errors[:base] << "You can't create two promotions for the same product"
41
+ end
42
+ end
43
+ end
31
44
  end
32
45
  end
33
46
  end
@@ -1,18 +1,24 @@
1
1
  module Spree
2
- class Promotion::Rules::User < PromotionRule
3
- belongs_to :user
4
- has_and_belongs_to_many :users, :class_name => '::Spree::User', :join_table => 'spree_promotion_rules_users', :foreign_key => 'promotion_rule_id'
2
+ class Promotion
3
+ module Rules
4
+ class User < PromotionRule
5
+ attr_accessible :user_ids_string
5
6
 
6
- def eligible?(order, options = {})
7
- users.none? or users.include?(order.user)
8
- end
7
+ belongs_to :user, :class_name => "Spree::User"
8
+ has_and_belongs_to_many :users, :class_name => '::Spree::User', :join_table => 'spree_promotion_rules_users', :foreign_key => 'promotion_rule_id'
9
9
 
10
- def user_ids_string
11
- user_ids.join(',')
12
- end
10
+ def eligible?(order, options = {})
11
+ users.none? or users.include?(order.user)
12
+ end
13
+
14
+ def user_ids_string
15
+ user_ids.join(',')
16
+ end
13
17
 
14
- def user_ids_string=(s)
15
- self.user_ids = s.to_s.split(',').map(&:strip)
18
+ def user_ids_string=(s)
19
+ self.user_ids = s.to_s.split(',').map(&:strip)
20
+ end
21
+ end
16
22
  end
17
23
  end
18
24
  end
@@ -1,15 +1,20 @@
1
1
  module Spree
2
- class Promotion::Rules::UserLoggedIn < PromotionRule
3
- def eligible?(order, options = {})
2
+ class Promotion
3
+ module Rules
4
+ class UserLoggedIn < PromotionRule
4
5
 
5
- # this is tricky. We couldn't use any of the devise methods since we aren't in the controller.
6
- # we need to rely on the controller already having done this for us.
6
+ def eligible?(order, options = {})
7
+ # this is tricky. We couldn't use any of the devise methods since we aren't in the controller.
8
+ # we need to rely on the controller already having done this for us.
7
9
 
8
- # The thinking is that the controller should have some sense of what state
9
- # we should be in before firing events,
10
- # so the controller will have to set this field.
10
+ # The thinking is that the controller should have some sense of what state
11
+ # we should be in before firing events,
12
+ # so the controller will have to set this field.
11
13
 
12
- return options && options[:user_signed_in]
14
+ return options && options[:user_signed_in]
15
+ end
16
+
17
+ end
13
18
  end
14
19
  end
15
20
  end
@@ -14,6 +14,8 @@ module Spree
14
14
  alias_method :actions, :promotion_actions
15
15
  accepts_nested_attributes_for :promotion_actions
16
16
 
17
+ validates_associated :rules
18
+
17
19
  attr_accessible :name, :event_name, :code, :match_policy,
18
20
  :path, :advertise, :description, :usage_limit,
19
21
  :starts_at, :expires_at, :promotion_rules_attributes,
@@ -2,10 +2,12 @@
2
2
  # PromotionActions perform the necessary tasks when a promotion is activated by an event and determined to be eligible.
3
3
  module Spree
4
4
  class PromotionAction < ActiveRecord::Base
5
- belongs_to :promotion, :foreign_key => 'activator_id'
5
+ belongs_to :promotion, :foreign_key => 'activator_id', :class_name => "Spree::Promotion"
6
6
 
7
7
  scope :of_type, lambda {|t| {:conditions => {:type => t}}}
8
8
 
9
+ attr_accessible :line_items_string
10
+
9
11
  # This method should be overriden in subclass
10
12
  # Updates the state of the order or performs some other action depending on the subclass
11
13
  # options will contain the payload from the event that activated the promotion. This will include
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class PromotionActionLineItem < ActiveRecord::Base
3
3
  belongs_to :promotion_action, :class_name => 'Spree::Promotion::Actions::CreateLineItems'
4
- belongs_to :variant
4
+ belongs_to :variant, :class_name => "Spree::Variant"
5
5
  end
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # Base class for all promotion rules
2
2
  module Spree
3
3
  class PromotionRule < ActiveRecord::Base
4
- belongs_to :promotion, :foreign_key => 'activator_id'
4
+ belongs_to :promotion, :foreign_key => 'activator_id', :class_name => "Spree::Promotion"
5
5
 
6
6
  scope :of_type, lambda {|t| {:conditions => {:type => t}}}
7
7
 
@@ -13,7 +13,7 @@
13
13
  <%= item.quantity %>
14
14
  </td>
15
15
  <td>
16
- <%= image_tag 'admin/icons/cross.png' %>
16
+ <%= image_tag 'admin/icons/cross.png', :class => "remove_promotion_line_item", :data => { :variant_id => item.variant_id } %>
17
17
  </td>
18
18
  </tr>
19
19
  <% end %>
metadata CHANGED
@@ -1,38 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_promo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
5
- prerelease:
4
+ version: 1.1.2.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - David North
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-16 00:00:00.000000000 Z
12
+ date: 2012-06-25 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: spree_core
16
- requirement: &70340061938220 !ruby/object:Gem::Requirement
16
+ requirement: &70249530014760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
20
20
  - !ruby/object:Gem::Version
21
- version: 1.1.1
21
+ version: 1.1.2.rc1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70340061938220
24
+ version_requirements: *70249530014760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: spree_auth
27
- requirement: &70340061937140 !ruby/object:Gem::Requirement
27
+ requirement: &70249530003060 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - =
31
31
  - !ruby/object:Gem::Version
32
- version: 1.1.1
32
+ version: 1.1.2.rc1
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70340061937140
35
+ version_requirements: *70249530003060
36
36
  description: Required dependency for Spree
37
37
  email: david@spreecommerce.com
38
38
  executables: []
@@ -127,12 +127,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
127
  required_rubygems_version: !ruby/object:Gem::Requirement
128
128
  none: false
129
129
  requirements:
130
- - - ! '>='
130
+ - - ! '>'
131
131
  - !ruby/object:Gem::Version
132
- version: '0'
133
- segments:
134
- - 0
135
- hash: -2121439115021991443
132
+ version: 1.3.1
136
133
  requirements:
137
134
  - none
138
135
  rubyforge_project: