spree_core 2.2.2 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +2 -2
  3. data/app/helpers/spree/products_helper.rb +1 -1
  4. data/app/helpers/spree/store_helper.rb +1 -1
  5. data/app/models/spree/adjustment.rb +10 -9
  6. data/app/models/spree/app_configuration.rb +1 -0
  7. data/app/models/spree/credit_card.rb +6 -5
  8. data/app/models/spree/line_item.rb +3 -3
  9. data/app/models/spree/order.rb +4 -8
  10. data/app/models/spree/order/checkout.rb +2 -0
  11. data/app/models/spree/order_contents.rb +3 -0
  12. data/app/models/spree/order_updater.rb +2 -2
  13. data/app/models/spree/payment.rb +10 -9
  14. data/app/models/spree/payment/processing.rb +1 -1
  15. data/app/models/spree/product.rb +18 -1
  16. data/app/models/spree/promotion/actions/create_item_adjustments.rb +5 -3
  17. data/app/models/spree/promotion_action.rb +2 -0
  18. data/app/models/spree/promotion_handler/coupon.rb +13 -4
  19. data/app/models/spree/return_authorization.rb +9 -8
  20. data/app/models/spree/stock/estimator.rb +1 -1
  21. data/app/models/spree/zone.rb +5 -5
  22. data/app/views/spree/order_mailer/confirm_email.text.erb +20 -2
  23. data/app/views/spree/shared/_routes.html.erb +5 -5
  24. data/config/locales/en.yml +1 -0
  25. data/db/migrate/20131118183431_add_line_item_id_to_spree_inventory_units.rb +2 -2
  26. data/db/migrate/20140601011216_set_shipment_total_for_users_upgrading.rb +12 -0
  27. data/db/migrate/20140609201656_add_deleted_at_to_spree_promotion_actions.rb +6 -0
  28. data/db/migrate/20140616202624_remove_uncaptured_amount_from_spree_payments.rb +5 -0
  29. data/lib/spree/core/product_duplicator.rb +6 -2
  30. data/lib/spree/core/version.rb +1 -1
  31. data/lib/spree/testing_support/factories/promotion_factory.rb +31 -1
  32. metadata +14 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a5120849e1aaa18b3747ba821d39be5e0e22c64
4
- data.tar.gz: 472557e5032544f1c53694c452989910466e7fa9
3
+ metadata.gz: f612c6f42ba3ade084e50bdca945ccf34f1ce76f
4
+ data.tar.gz: f84f159adfe58ab3b210da9b0d596a54d3d758c2
5
5
  SHA512:
6
- metadata.gz: 8dec314e53c791de3fa15d96772d7b6b46771873321ff7219fe5a7a8316d61f6dfa82fc50d6b176d1186a3c1944eeb9962488570dea5f14a8fb7a40ac6fba4fe
7
- data.tar.gz: 3423ee941bbce9284bad16a6137a991efe553553a87abca67585cb5bf8dc9e10a4cf4b364b456e8404f37b0649050b154ecd266fa78965a5ec9758866b53896b
6
+ metadata.gz: 39a5a14c31bfeb6eaff2d0f2b99eacd506e01f882fa5c20f6f03efc1d8e74d7f965a37e0d1f5f857ef25e0735056905708c8960b89310a776d2fc506d702b9d3
7
+ data.tar.gz: 7c92311fcbbd4cc550c32c3473352f719e94d40367fde91c05779a7274eff4a34c6d3ed096c69fc9eacbb921ab4f20ad3c3ba722d8060646e4ace2813e2d9dcb
@@ -20,11 +20,11 @@ module Spree
20
20
  text = "#{text}: (#{Spree.t('empty')})"
21
21
  css_class = 'empty'
22
22
  else
23
- text = "#{text}: (#{simple_current_order.item_count}) <span class='amount'>#{simple_current_order.display_total.to_html}</span>".html_safe
23
+ text = "#{text}: (#{simple_current_order.item_count}) <span class='amount'>#{simple_current_order.display_total.to_html}</span>"
24
24
  css_class = 'full'
25
25
  end
26
26
 
27
- link_to text, spree.cart_path, :class => "cart-info #{css_class}"
27
+ link_to text.html_safe, spree.cart_path, :class => "cart-info #{css_class}"
28
28
  end
29
29
 
30
30
  # human readable list of variant options
@@ -55,7 +55,7 @@ module Spree
55
55
  def cache_key_for_products
56
56
  count = @products.count
57
57
  max_updated_at = (@products.maximum(:updated_at) || Date.today).to_s(:number)
58
- "#{current_currency}/spree/products/all-#{params[:page]}-#{max_updated_at}-#{count}"
58
+ "#{I18n.locale}/#{current_currency}/spree/products/all-#{params[:page]}-#{max_updated_at}-#{count}"
59
59
  end
60
60
  end
61
61
  end
@@ -10,7 +10,7 @@ module Spree
10
10
  def cache_key_for_taxons
11
11
  max_updated_at = @taxons.maximum(:updated_at).to_i
12
12
  parts = [@taxon.try(:id), max_updated_at].compact.join("-")
13
- "taxons/#{parts}"
13
+ "#{I18n.locale}/taxons/#{parts}"
14
14
  end
15
15
  end
16
16
  end
@@ -24,7 +24,7 @@ module Spree
24
24
  class Adjustment < ActiveRecord::Base
25
25
  belongs_to :adjustable, polymorphic: true
26
26
  belongs_to :source, polymorphic: true
27
- belongs_to :order, :class_name => "Spree::Order"
27
+ belongs_to :order, class_name: "Spree::Order"
28
28
 
29
29
  validates :label, presence: true
30
30
  validates :amount, numericality: true
@@ -59,6 +59,14 @@ module Spree
59
59
  state == "closed"
60
60
  end
61
61
 
62
+ def currency
63
+ adjustable ? adjustable.currency : Spree::Config[:currency]
64
+ end
65
+
66
+ def display_amount
67
+ Spree::Money.new(amount, { currency: currency })
68
+ end
69
+
62
70
  def promotion?
63
71
  source.class < Spree::PromotionAction
64
72
  end
@@ -88,19 +96,12 @@ module Spree
88
96
  amount
89
97
  end
90
98
 
91
- def currency
92
- adjustable ? adjustable.currency : Spree::Config[:currency]
93
- end
94
-
95
- def display_amount
96
- Spree::Money.new(amount, { currency: currency })
97
- end
98
-
99
99
  private
100
100
 
101
101
  def update_adjustable_adjustment_total
102
102
  # Cause adjustable's total to be recalculated
103
103
  Spree::ItemAdjustments.new(adjustable).update if adjustable
104
104
  end
105
+
105
106
  end
106
107
  end
@@ -57,6 +57,7 @@ module Spree
57
57
  preference :max_level_in_taxons_menu, :integer, default: 1 # maximum nesting level in taxons menu
58
58
  preference :orders_per_page, :integer, default: 15
59
59
  preference :prices_inc_tax, :boolean, default: false
60
+ preference :properties_per_page, :integer, default: 15
60
61
  preference :products_per_page, :integer, default: 12
61
62
  preference :promotions_per_page, :integer, default: 15
62
63
  preference :redirect_https_to_http, :boolean, :default => false
@@ -37,9 +37,10 @@ module Spree
37
37
  elsif match = expiry.match(/(\d{2})(\d{2,4})/) # will match mmyy and mmyyyy
38
38
  [match[1], match[2]]
39
39
  end
40
-
41
- self[:year] = "20" + self[:year] if self[:year].length == 2
42
- self[:year] = self[:year].to_i
40
+ if self[:year]
41
+ self[:year] = "20" + self[:year] if self[:year].length == 2
42
+ self[:year] = self[:year].to_i
43
+ end
43
44
  self[:month] = self[:month].to_i
44
45
  end
45
46
 
@@ -111,8 +112,8 @@ module Spree
111
112
  :month => month,
112
113
  :year => year,
113
114
  :verification_value => verification_value,
114
- :first_name => first_name,
115
- :last_name => last_name
115
+ :first_name => first_name || name.to_s.split(/[[:space:]]/, 2)[0],
116
+ :last_name => last_name || name.to_s.split(/[[:space:]]/, 2)[1]
116
117
  )
117
118
  end
118
119
 
@@ -28,7 +28,7 @@ module Spree
28
28
  after_save :update_inventory
29
29
  after_save :update_adjustments
30
30
 
31
- after_create :create_tax_charge
31
+ after_create :update_tax_charge
32
32
 
33
33
  delegate :name, :description, :should_track_inventory?, to: :variant
34
34
 
@@ -108,6 +108,7 @@ module Spree
108
108
 
109
109
  def update_adjustments
110
110
  if quantity_changed?
111
+ update_tax_charge # Called to ensure pre_tax_amount is updated.
111
112
  recalculate_adjustments
112
113
  end
113
114
  end
@@ -116,7 +117,7 @@ module Spree
116
117
  Spree::ItemAdjustments.new(self).update
117
118
  end
118
119
 
119
- def create_tax_charge
120
+ def update_tax_charge
120
121
  Spree::TaxRate.adjust(order, [self])
121
122
  end
122
123
 
@@ -127,4 +128,3 @@ module Spree
127
128
  end
128
129
  end
129
130
  end
130
-
@@ -121,7 +121,7 @@ module Spree
121
121
 
122
122
  def all_adjustments
123
123
  Adjustment.where("order_id = :order_id OR (adjustable_id = :order_id AND adjustable_type = 'Spree::Order')",
124
- :order_id => self.id)
124
+ order_id: self.id)
125
125
  end
126
126
 
127
127
  # For compatiblity with Calculator::PriceSack
@@ -439,8 +439,9 @@ module Spree
439
439
  def empty!
440
440
  line_items.destroy_all
441
441
  updater.update_item_count
442
-
443
442
  adjustments.destroy_all
443
+ shipments.destroy_all
444
+
444
445
  update_totals
445
446
  persist_totals
446
447
  end
@@ -532,12 +533,7 @@ module Spree
532
533
  end
533
534
 
534
535
  def is_risky?
535
- self.payments.where(%{
536
- (avs_response IS NOT NULL and avs_response != '' and avs_response != 'D' and avs_response != 'M') or
537
- (cvv_response_code IS NOT NULL and cvv_response_code != 'M') or
538
- cvv_response_message IS NOT NULL and cvv_response_message != '' or
539
- state = 'failed'
540
- }.squish!).uniq.count > 0
536
+ self.payments.risky.count > 0
541
537
  end
542
538
 
543
539
  def approved_by(user)
@@ -222,6 +222,8 @@ module Spree
222
222
  raise Core::GatewayError.new Spree.t(:invalid_credit_card)
223
223
  end
224
224
 
225
+ credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
226
+
225
227
  attributes[:payments_attributes].first[:source] = credit_card
226
228
  attributes[:payments_attributes].first[:payment_method_id] = credit_card.payment_method_id
227
229
  attributes[:payments_attributes].first.delete :source_attributes
@@ -49,7 +49,10 @@ module Spree
49
49
  order_updater.update_item_count
50
50
  order_updater.update_item_total
51
51
  order_updater.update_adjustment_total
52
+
53
+ order_updater.update_payment_state if order.completed?
52
54
  order_updater.persist_totals
55
+
53
56
  order.reload
54
57
  end
55
58
 
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class OrderUpdater
3
3
  attr_reader :order
4
- delegate :payments, :line_items, :adjustments, :shipments, :update_hooks, to: :order
4
+ delegate :payments, :line_items, :adjustments, :all_adjustments, :shipments, :update_hooks, to: :order
5
5
 
6
6
  def initialize(order)
7
7
  @order = order
@@ -30,7 +30,7 @@ module Spree
30
30
  end
31
31
 
32
32
  def recalculate_adjustments
33
- adjustments.includes(:source).each { |adjustment| adjustment.update! order }
33
+ all_adjustments.includes(:adjustable).map(&:adjustable).uniq.each { |adjustable| Spree::ItemAdjustments.new(adjustable).update }
34
34
  end
35
35
 
36
36
  # Updates the following Order total values:
@@ -2,7 +2,9 @@ module Spree
2
2
  class Payment < ActiveRecord::Base
3
3
  include Spree::Payment::Processing
4
4
 
5
- IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze
5
+ IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze
6
+ NON_RISKY_AVS_CODES = ['B', 'D', 'H', 'J', 'M', 'Q', 'T', 'V', 'X', 'Y'].freeze
7
+ RISKY_AVS_CODES = ['A', 'C', 'E', 'F', 'G', 'I', 'K', 'L', 'N', 'O', 'P', 'R', 'S', 'U', 'W', 'Z'].freeze
6
8
 
7
9
  belongs_to :order, class_name: 'Spree::Order', touch: true, inverse_of: :payments
8
10
  belongs_to :source, polymorphic: true
@@ -16,7 +18,6 @@ module Spree
16
18
 
17
19
  before_validation :validate_source
18
20
  before_create :set_unique_identifier
19
- before_save :update_uncaptured_amount
20
21
 
21
22
  after_save :create_payment_profile, if: :profiles_supported?
22
23
 
@@ -33,6 +34,7 @@ module Spree
33
34
  scope :completed, -> { with_state('completed') }
34
35
  scope :pending, -> { with_state('pending') }
35
36
  scope :failed, -> { with_state('failed') }
37
+ scope :risky, -> { where("avs_response IN (?) OR (cvv_response_code IS NOT NULL and cvv_response_code != 'M') OR state = 'failed'", RISKY_AVS_CODES) }
36
38
  scope :valid, -> { where.not(state: %w(failed invalid)) }
37
39
 
38
40
  after_rollback :persist_invalid
@@ -94,7 +96,7 @@ module Spree
94
96
  case amount
95
97
  when String
96
98
  separator = I18n.t('number.currency.format.separator')
97
- number = amount.delete("^0-9-#{separator}").tr(separator, '.')
99
+ number = amount.delete("^0-9-#{separator}\.").tr(separator, '.')
98
100
  number.to_d if number.present?
99
101
  end || amount
100
102
  end
@@ -132,8 +134,7 @@ module Spree
132
134
  end
133
135
 
134
136
  def is_avs_risky?
135
- return false if avs_response == "D"
136
- return false if avs_response.blank?
137
+ return false if avs_response.blank? || NON_RISKY_AVS_CODES.include?(avs_response)
137
138
  return true
138
139
  end
139
140
 
@@ -144,6 +145,10 @@ module Spree
144
145
  return true
145
146
  end
146
147
 
148
+ def uncaptured_amount
149
+ amount - capture_events.sum(:amount)
150
+ end
151
+
147
152
  private
148
153
 
149
154
  def validate_source
@@ -193,9 +198,5 @@ module Spree
193
198
  def generate_identifier
194
199
  Array.new(8){ IDENTIFIER_CHARS.sample }.join
195
200
  end
196
-
197
- def update_uncaptured_amount
198
- self.uncaptured_amount = amount - capture_events.sum(:amount)
199
- end
200
201
  end
201
202
  end
@@ -50,7 +50,7 @@ module Spree
50
50
  gateway_options
51
51
  )
52
52
 
53
- money = ::Money.new(amount, Spree::Config[:currency])
53
+ money = ::Money.new(amount, currency)
54
54
  capture_events.create!(amount: money.to_f)
55
55
  handle_response(response, :complete, :failure)
56
56
  end
@@ -21,7 +21,7 @@
21
21
  module Spree
22
22
  class Product < ActiveRecord::Base
23
23
  extend FriendlyId
24
- friendly_id :name, use: :slugged
24
+ friendly_id :slug_candidates, use: :slugged
25
25
 
26
26
  acts_as_paranoid
27
27
  has_many :product_option_types, dependent: :destroy, inverse_of: :product
@@ -77,9 +77,12 @@ module Spree
77
77
  validates :price, presence: true, if: proc { Spree::Config[:require_master_price] }
78
78
  validates :shipping_category_id, presence: true
79
79
  validates :slug, length: { minimum: 3 }
80
+ validates :slug, uniqueness: true
80
81
 
81
82
  before_validation :normalize_slug, on: :update
82
83
 
84
+ after_destroy :punch_slug
85
+
83
86
  attr_accessor :option_values_hash
84
87
 
85
88
  accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
@@ -213,6 +216,7 @@ module Spree
213
216
  end
214
217
 
215
218
  private
219
+
216
220
  def normalize_slug
217
221
  self.slug = normalize_friendly_id(slug)
218
222
  end
@@ -265,6 +269,19 @@ module Spree
265
269
  taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
266
270
  Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
267
271
  end
272
+
273
+ # Try building a slug based on the following fields in increasing order of specificity.
274
+ def slug_candidates
275
+ [
276
+ :name,
277
+ [:name, :sku]
278
+ ]
279
+ end
280
+
281
+ def punch_slug
282
+ update(slug: "#{Time.now.to_i}_#{slug}") # punch slug with date prefix to allow reuse of original
283
+ end
284
+
268
285
  end
269
286
  end
270
287
 
@@ -41,8 +41,9 @@ module Spree
41
41
  # Ensure a negative amount which does not exceed the sum of the order's
42
42
  # item_total and ship_total
43
43
  def compute_amount(adjustable)
44
- amount = self.calculator.compute(adjustable).to_f.abs
45
- [adjustable.total, amount].min * -1
44
+ promotion_amount = self.calculator.compute(adjustable).to_f.abs
45
+
46
+ [adjustable.amount, promotion_amount].min * -1
46
47
  end
47
48
 
48
49
  private
@@ -62,7 +63,8 @@ module Spree
62
63
  end
63
64
 
64
65
  def deals_with_adjustments
65
- adjustment_scope = Adjustment.includes(:order).references(:spree_orders)
66
+ adjustment_scope = self.adjustments.includes(:order).references(:spree_orders)
67
+
66
68
  # For incomplete orders, remove the adjustment completely.
67
69
  adjustment_scope.where("spree_orders.completed_at IS NULL").each do |adjustment|
68
70
  adjustment.destroy
@@ -2,6 +2,8 @@
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
+ acts_as_paranoid
6
+
5
7
  belongs_to :promotion, class_name: 'Spree::Promotion'
6
8
 
7
9
  scope :of_type, ->(t) { where(type: t) }
@@ -36,15 +36,16 @@ module Spree
36
36
 
37
37
  def handle_present_promotion(promotion)
38
38
  return promotion_usage_limit_exceeded if promotion.usage_limit_exceeded?(order)
39
+ return promotion_applied if promotion_exists_on_order?(order, promotion)
39
40
  return ineligible_for_this_order unless promotion.eligible?(order)
40
41
 
41
42
  # If any of the actions for the promotion return `true`,
42
43
  # then result here will also be `true`.
43
44
  result = promotion.activate(:order => order)
44
45
  if result
45
- determine_promotion_application_result(result)
46
+ determine_promotion_application_result
46
47
  else
47
- self.error = Spree.t(:coupon_code_already_applied)
48
+ self.error = Spree.t(:coupon_code_unknown_error)
48
49
  end
49
50
  end
50
51
 
@@ -56,7 +57,15 @@ module Spree
56
57
  self.error = Spree.t(:coupon_code_not_eligible)
57
58
  end
58
59
 
59
- def determine_promotion_application_result(result)
60
+ def promotion_applied
61
+ self.error = Spree.t(:coupon_code_already_applied)
62
+ end
63
+
64
+ def promotion_exists_on_order?(order, promotion)
65
+ order.promotions.include? promotion
66
+ end
67
+
68
+ def determine_promotion_application_result
60
69
  detector = lambda { |p|
61
70
  if p.source.promotion.code
62
71
  p.source.promotion.code.downcase == order.coupon_code.downcase
@@ -67,7 +76,7 @@ module Spree
67
76
  discount ||= order.shipment_adjustments.promotion.detect(&detector)
68
77
  discount ||= order.adjustments.promotion.detect(&detector)
69
78
 
70
- if result and discount.eligible
79
+ if discount.eligible
71
80
  order.update_totals
72
81
  order.persist_totals
73
82
  self.success = Spree.t(:coupon_code_applied)
@@ -3,7 +3,7 @@ module Spree
3
3
  belongs_to :order, class_name: 'Spree::Order'
4
4
 
5
5
  has_many :inventory_units
6
- has_one :stock_location
6
+ belongs_to :stock_location
7
7
  before_create :generate_number
8
8
  before_save :force_positive_amount
9
9
 
@@ -81,16 +81,17 @@ module Spree
81
81
  end
82
82
 
83
83
  def process_return
84
- inventory_units.each do |iu|
84
+ inventory_units(include: :variant).each do |iu|
85
85
  iu.return!
86
- stock_item = Spree::StockItem.where(variant_id: iu.variant.id, stock_location_id: stock_location_id).first
87
- Spree::StockMovement.create!(stock_item_id: stock_item.id, quantity: 1)
86
+
87
+ if iu.variant.should_track_inventory?
88
+ if stock_item = Spree::StockItem.find_by(variant_id: iu.variant_id, stock_location_id: stock_location_id)
89
+ Spree::StockMovement.create!(stock_item_id: stock_item.id, quantity: 1)
90
+ end
91
+ end
88
92
  end
89
93
 
90
- credit = Adjustment.new(amount: compute_amount, label: Spree.t(:rma_credit))
91
- credit.source = self
92
- credit.adjustable = order
93
- credit.save
94
+ Adjustment.create(adjustable: order, amount: compute_amount, label: Spree.t(:rma_credit), source: self)
94
95
  order.update!
95
96
 
96
97
  order.return if inventory_units.all?(&:returned?)
@@ -52,8 +52,8 @@ module Spree
52
52
  package.shipping_methods.select do |ship_method|
53
53
  calculator = ship_method.calculator
54
54
  begin
55
- calculator.available?(package) &&
56
55
  ship_method.include?(order.ship_address) &&
56
+ calculator.available?(package) &&
57
57
  (calculator.preferences[:currency].nil? ||
58
58
  calculator.preferences[:currency] == currency)
59
59
  rescue Exception => exception
@@ -71,12 +71,12 @@ module Spree
71
71
  # All zoneables belonging to the zone members. Will be a collection of either
72
72
  # countries or states depending on the zone type.
73
73
  def zoneables
74
- members.collect(&:zoneable)
74
+ members.includes(:zoneable).collect(&:zoneable)
75
75
  end
76
76
 
77
77
  def country_ids
78
78
  if kind == 'country'
79
- members.collect(&:zoneable_id)
79
+ members.pluck(:zoneable_id)
80
80
  else
81
81
  []
82
82
  end
@@ -84,7 +84,7 @@ module Spree
84
84
 
85
85
  def state_ids
86
86
  if kind == 'state'
87
- members.collect(&:zoneable_id)
87
+ members.pluck(:zoneable_id)
88
88
  else
89
89
  []
90
90
  end
@@ -117,9 +117,9 @@ module Spree
117
117
  return false if zone_members.empty? || target.zone_members.empty?
118
118
 
119
119
  if kind == target.kind
120
- return false if target.zoneables.any? { |target_zoneable| zoneables.exclude?(target_zoneable) }
120
+ return false if (target.zoneables.collect(&:id) - zoneables.collect(&:id)).present?
121
121
  else
122
- return false if target.zoneables.any? { |target_state| zoneables.exclude?(target_state.country) }
122
+ return false if (target.zoneables.collect(&:country).collect(&:id) - zoneables.collect(&:id)).present?
123
123
  end
124
124
  true
125
125
  end
@@ -10,11 +10,29 @@
10
10
  <% end %>
11
11
  ============================================================
12
12
  <%= Spree.t('order_mailer.confirm_email.subtotal', :subtotal => @order.display_item_total) %>
13
+ <% if @order.line_item_adjustments.exists? %>
14
+ <% if @order.all_adjustments.promotion.eligible.exists? %>
15
+ <% @order.all_adjustments.promotion.eligible.group_by(&:label).each do |label, adjustments| %>
16
+ <%= Spree.t(:promotion) %>: <%= label %> <%= Spree::Money.new(adjustments.sum(&:amount), currency: @order.currency) %>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
13
20
 
14
- <% @order.adjustments.eligible.each do |adjustment| %>
15
- <%= raw(adjustment.label) %> <%= adjustment.display_amount %>
21
+ <% @order.shipments.group_by { |s| s.selected_shipping_rate.try(:name) }.each do |name, shipments| %>
22
+ <%= Spree.t(:shipping) %>: <%= name %> <%= Spree::Money.new(shipments.sum(&:discounted_cost), currency: @order.currency) %>
23
+ <% end %>
24
+
25
+ <% if @order.all_adjustments.eligible.tax.exists? %>
26
+ <% @order.all_adjustments.eligible.tax.group_by(&:label).each do |label, adjustments| %>
27
+ <%= Spree.t(:tax) %>: <%= label %> <%= Spree::Money.new(adjustments.sum(&:amount), currency: @order.currency) %>
28
+ <% end %>
16
29
  <% end %>
17
30
 
31
+ <% @order.adjustments.eligible.each do |adjustment| %>
32
+ <% next if (adjustment.source_type == 'Spree::TaxRate') and (adjustment.amount == 0) %>
33
+ <%= adjustment.label %> <%= adjustment.display_amount %>
34
+ <% end %>
35
+ ============================================================
18
36
  <%= Spree.t('order_mailer.confirm_email.total', :total => @order.display_total) %>
19
37
 
20
38
  <%= Spree.t('order_mailer.confirm_email.thanks') %>
@@ -1,13 +1,13 @@
1
1
  <script>
2
2
  if (Spree === undefined) {
3
- var Spree = {}
3
+ var Spree = {};
4
4
  }
5
5
  if (Spree.routes == undefined) {
6
- Spree.routes = {}
6
+ Spree.routes = {};
7
7
  }
8
- Spree.routes.states_search = "<%= spree.api_states_path(:format => 'json') %>"
8
+ Spree.routes.states_search = "<%= spree.api_states_path(:format => 'json') %>";
9
9
  Spree.routes.apply_coupon_code = function(order_id) {
10
- return "<%= spree.api_orders_path %>/" + order_id + "/apply_coupon_code"
10
+ return "<%= spree.api_orders_path %>/" + order_id + "/apply_coupon_code";
11
11
  }
12
- Spree.routes.root = "<%= spree.root_url if spree.respond_to? :root_url %>"
12
+ Spree.routes.root = "<%= spree.root_url if spree.respond_to? :root_url %>";
13
13
  </script>
@@ -485,6 +485,7 @@ en:
485
485
  coupon_code_max_usage: Coupon code usage limit exceeded
486
486
  coupon_code_not_eligible: This coupon code is not eligible for this order
487
487
  coupon_code_not_found: The coupon code you entered doesn't exist. Please try again.
488
+ coupon_code_unknown_error: This coupon code could not be applied to the cart at this time.
488
489
  create: Create
489
490
  create_a_new_account: Create a new account
490
491
  created_at: Created At
@@ -8,9 +8,9 @@ class AddLineItemIdToSpreeInventoryUnits < ActiveRecord::Migration
8
8
  shipments = Spree::Shipment.includes(:inventory_units, :order)
9
9
 
10
10
  shipments.find_each do |shipment|
11
- shipment.inventory_units.group_by(&:variant).each do |variant, units|
11
+ shipment.inventory_units.group_by(&:variant_id).each do |variant, units|
12
12
 
13
- line_item = shipment.order.find_line_item_by_variant(variant)
13
+ line_item = shipment.order.line_items.find_by(variant_id: variant_id)
14
14
  next unless line_item
15
15
 
16
16
  Spree::InventoryUnit.where(id: units.map(&:id)).update_all(line_item_id: line_item.id)
@@ -0,0 +1,12 @@
1
+ class SetShipmentTotalForUsersUpgrading < ActiveRecord::Migration
2
+ def up
3
+ # NOTE You might not need this at all unless you're upgrading from Spree 2.1.x
4
+ # or below. For those upgrading this should populate the Order#shipment_total
5
+ # for legacy orders
6
+ execute "UPDATE spree_orders
7
+ SET shipment_total = (SELECT SUM(spree_shipments.cost) AS sum_id
8
+ FROM spree_shipments
9
+ WHERE spree_shipments.order_id = spree_orders.id)
10
+ WHERE spree_orders.completed_at IS NOT NULL AND spree_orders.shipment_total = 0"
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ class AddDeletedAtToSpreePromotionActions < ActiveRecord::Migration
2
+ def change
3
+ add_column :spree_promotion_actions, :deleted_at, :datetime
4
+ add_index :spree_promotion_actions, :deleted_at
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveUncapturedAmountFromSpreePayments < ActiveRecord::Migration
2
+ def change
3
+ remove_column :spree_payments, :uncaptured_amount
4
+ end
5
+ end
@@ -2,8 +2,12 @@ module Spree
2
2
  class ProductDuplicator
3
3
  attr_accessor :product
4
4
 
5
- def initialize(product)
5
+ @@clone_images_default = true
6
+ mattr_accessor :clone_images_default
7
+
8
+ def initialize(product, include_images = @@clone_images_default)
6
9
  @product = product
10
+ @include_images = include_images
7
11
  end
8
12
 
9
13
  def duplicate
@@ -38,7 +42,7 @@ module Spree
38
42
  master.dup.tap do |new_master|
39
43
  new_master.sku = "COPY OF #{master.sku}"
40
44
  new_master.deleted_at = nil
41
- new_master.images = master.images.map { |image| duplicate_image image }
45
+ new_master.images = master.images.map { |image| duplicate_image image } if @include_images
42
46
  new_master.price = master.price
43
47
  new_master.currency = master.currency
44
48
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
2
  def self.version
3
- "2.2.2"
3
+ "2.2.3"
4
4
  end
5
5
  end
@@ -2,7 +2,7 @@ FactoryGirl.define do
2
2
  factory :promotion, class: Spree::Promotion do
3
3
  name 'Promo'
4
4
 
5
- factory :promotion_with_item_adjustment do
5
+ trait :with_line_item_adjustment do
6
6
  ignore do
7
7
  adjustment_rate 10
8
8
  end
@@ -15,6 +15,36 @@ FactoryGirl.define do
15
15
  promotion.save
16
16
  end
17
17
  end
18
+ factory :promotion_with_item_adjustment, traits: [:with_line_item_adjustment]
19
+
20
+ trait :with_order_adjustment do
21
+ ignore do
22
+ order_adjustment_amount 10
23
+ end
24
+
25
+ after(:create) do |promotion, evaluator|
26
+ calculator = Spree::Calculator::FlatRate.new
27
+ calculator.preferred_amount = evaluator.order_adjustment_amount
28
+ action = Spree::Promotion::Actions::CreateAdjustment.create!(:calculator => calculator)
29
+ promotion.actions << action
30
+ promotion.save!
31
+ end
32
+ end
33
+
34
+ trait :with_item_total_rule do
35
+ ignore do
36
+ item_total_threshold_amount 10
37
+ end
38
+
39
+ after(:create) do |promotion, evaluator|
40
+ rule = Spree::Promotion::Rules::ItemTotal.create!(
41
+ preferred_operator: 'gte',
42
+ preferred_amount: evaluator.item_total_threshold_amount
43
+ )
44
+ promotion.rules << rule
45
+ promotion.save!
46
+ end
47
+ end
18
48
 
19
49
  end
20
50
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Schofield
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-15 00:00:00.000000000 Z
11
+ date: 2014-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemerchant
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.42.3
19
+ version: 1.43.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.42.3
26
+ version: 1.43.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: acts_as_list
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -112,16 +112,16 @@ dependencies:
112
112
  name: friendly_id
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '='
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 5.0.3
117
+ version: 5.0.4
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '='
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 5.0.3
124
+ version: 5.0.4
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: highline
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -226,14 +226,14 @@ dependencies:
226
226
  requirements:
227
227
  - - "~>"
228
228
  - !ruby/object:Gem::Version
229
- version: 4.0.5
229
+ version: 4.0.6
230
230
  type: :runtime
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
- version: 4.0.5
236
+ version: 4.0.6
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: ransack
239
239
  requirement: !ruby/object:Gem::Requirement
@@ -590,6 +590,9 @@ files:
590
590
  - db/migrate/20140219060952_add_considered_risky_to_orders.rb
591
591
  - db/migrate/20140307235515_add_user_id_to_spree_credit_cards.rb
592
592
  - db/migrate/20140415041315_add_user_id_created_by_id_index_to_order.rb
593
+ - db/migrate/20140601011216_set_shipment_total_for_users_upgrading.rb
594
+ - db/migrate/20140609201656_add_deleted_at_to_spree_promotion_actions.rb
595
+ - db/migrate/20140616202624_remove_uncaptured_amount_from_spree_payments.rb
593
596
  - db/seeds.rb
594
597
  - lib/generators/spree/custom_user/custom_user_generator.rb
595
598
  - lib/generators/spree/custom_user/templates/authentication_helpers.rb.tt
@@ -738,7 +741,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
738
741
  version: '0'
739
742
  requirements: []
740
743
  rubyforge_project:
741
- rubygems_version: 2.2.0
744
+ rubygems_version: 2.2.2
742
745
  signing_key:
743
746
  specification_version: 4
744
747
  summary: The bare bones necessary for Spree.