spree_core 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/products_helper.rb +3 -3
  3. data/app/models/concerns/spree/user_reporting.rb +2 -2
  4. data/app/models/spree/address.rb +7 -7
  5. data/app/models/spree/credit_card.rb +11 -5
  6. data/app/models/spree/gateway.rb +4 -1
  7. data/app/models/spree/item_adjustments.rb +17 -7
  8. data/app/models/spree/line_item.rb +2 -2
  9. data/app/models/spree/order.rb +35 -19
  10. data/app/models/spree/order/checkout.rb +3 -1
  11. data/app/models/spree/order_updater.rb +8 -2
  12. data/app/models/spree/payment.rb +2 -2
  13. data/app/models/spree/payment/processing.rb +9 -0
  14. data/app/models/spree/payment_method.rb +6 -0
  15. data/app/models/spree/price.rb +2 -2
  16. data/app/models/spree/product.rb +7 -2
  17. data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -0
  18. data/app/models/spree/promotion/rules/product.rb +4 -2
  19. data/app/models/spree/promotion/rules/user.rb +2 -2
  20. data/app/models/spree/promotion_handler/coupon.rb +6 -1
  21. data/app/models/spree/shipment.rb +0 -1
  22. data/app/models/spree/shipping_rate.rb +11 -9
  23. data/app/models/spree/stock/availability_validator.rb +1 -1
  24. data/app/models/spree/stock/quantifier.rb +1 -9
  25. data/app/models/spree/stock_item.rb +4 -0
  26. data/app/models/spree/tax_rate.rb +9 -8
  27. data/app/models/spree/taxon.rb +3 -0
  28. data/app/models/spree/variant.rb +1 -5
  29. data/config/locales/en.yml +1 -0
  30. data/db/migrate/20130830001159_migrate_old_shipping_calculators.rb +1 -1
  31. data/db/migrate/20140415041315_add_user_id_created_by_id_index_to_order.rb +5 -0
  32. data/lib/generators/spree/dummy/dummy_generator.rb +7 -2
  33. data/lib/spree/core.rb +2 -0
  34. data/lib/spree/core/engine.rb +1 -1
  35. data/lib/spree/core/importer/order.rb +13 -2
  36. data/lib/spree/core/version.rb +1 -1
  37. data/lib/spree/migrations.rb +10 -1
  38. data/lib/spree/money.rb +1 -1
  39. data/lib/spree/testing_support/capybara_ext.rb +1 -1
  40. data/lib/spree/testing_support/factories/address_factory.rb +1 -1
  41. metadata +34 -11
  42. data/vendor/assets/fonts/FontAwesome.otf +0 -0
  43. data/vendor/assets/fonts/fontawesome-webfont.eot +0 -0
  44. data/vendor/assets/fonts/fontawesome-webfont.svg +0 -399
  45. data/vendor/assets/fonts/fontawesome-webfont.ttf +0 -0
  46. data/vendor/assets/fonts/fontawesome-webfont.woff +0 -0
  47. data/vendor/assets/stylesheets/font-awesome.scss +0 -1475
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6877ed94eb40aa392d3e75311ae1c46f07d16c4
4
- data.tar.gz: 86f962251bf0d966fce2dc5562a4e537b05db77c
3
+ metadata.gz: 2a5120849e1aaa18b3747ba821d39be5e0e22c64
4
+ data.tar.gz: 472557e5032544f1c53694c452989910466e7fa9
5
5
  SHA512:
6
- metadata.gz: b9f99321e59660959d319148d1c7deed17c10caedb97e6d29d95dd15c195b2dac43bcfb35d5117c915bc456a1d8c0fb8f2d319971a7bd681f842f77a91ba25b6
7
- data.tar.gz: 154ee0e0f7d1bd5fa2ce9bce96008951200122a3c687dfe88b6e75284987bef2c12d464c6bba83a2a97747ccd2e9dae7537b2fddc3a4fb9e9cc924c5c11c8491
6
+ metadata.gz: 8dec314e53c791de3fa15d96772d7b6b46771873321ff7219fe5a7a8316d61f6dfa82fc50d6b176d1186a3c1944eeb9962488570dea5f14a8fb7a40ac6fba4fe
7
+ data.tar.gz: 3423ee941bbce9284bad16a6137a991efe553553a87abca67585cb5bf8dc9e10a4cf4b364b456e8404f37b0649050b154ecd266fa78965a5ec9758866b53896b
@@ -9,7 +9,6 @@ module Spree
9
9
  end
10
10
  end
11
11
 
12
-
13
12
  # returns the formatted price for the specified variant as a difference from product price
14
13
  def variant_price_diff(variant)
15
14
  diff = variant.amount_in(current_currency) - variant.product.amount_in(current_currency)
@@ -54,8 +53,9 @@ module Spree
54
53
  end
55
54
 
56
55
  def cache_key_for_products
57
- max_updated_at = @products.maximum(:updated_at).to_s(:number)
58
- "#{current_currency}/spree/products/all-#{params[:page]}-#{max_updated_at}"
56
+ count = @products.count
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}"
59
59
  end
60
60
  end
61
61
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  module UserReporting
3
3
  def lifetime_value
4
- orders.complete.pluck(:total).sum
4
+ spree_orders.complete.pluck(:total).sum
5
5
  end
6
6
 
7
7
  def display_lifetime_value
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def order_count
12
- BigDecimal(orders.complete.count)
12
+ BigDecimal(spree_orders.complete.count)
13
13
  end
14
14
 
15
15
  def average_order_value
@@ -82,15 +82,15 @@ module Spree
82
82
  }
83
83
  end
84
84
 
85
- private
86
- def require_phone?
87
- true
88
- end
85
+ def require_phone?
86
+ true
87
+ end
89
88
 
90
- def require_zipcode?
91
- true
92
- end
89
+ def require_zipcode?
90
+ true
91
+ end
93
92
 
93
+ private
94
94
  def state_validate
95
95
  # Skip state validation without country (also required)
96
96
  # or when disabled by preference
@@ -29,12 +29,18 @@ module Spree
29
29
  }
30
30
 
31
31
  def expiry=(expiry)
32
- if expiry.present?
33
- self[:month], self[:year] = expiry.delete(' ').split('/')
34
- self[:year] = "20" + self[:year] if self[:year].length == 2
35
- self[:year] = self[:year].to_i
36
- self[:month] = self[:month].to_i
32
+ return unless expiry.present?
33
+
34
+ self[:month], self[:year] =
35
+ if expiry.match(/\d\s?\/\s?\d/) # will match mm/yy and mm / yyyy
36
+ expiry.delete(' ').split('/')
37
+ elsif match = expiry.match(/(\d{2})(\d{2,4})/) # will match mmyy and mmyyyy
38
+ [match[1], match[2]]
37
39
  end
40
+
41
+ self[:year] = "20" + self[:year] if self[:year].length == 2
42
+ self[:year] = self[:year].to_i
43
+ self[:month] = self[:month].to_i
38
44
  end
39
45
 
40
46
  def number=(num)
@@ -64,7 +64,7 @@ module Spree
64
64
  payment_source_class.where(id: source_ids).with_payment_profile
65
65
  end
66
66
 
67
- def sources_with_profile(order)
67
+ def reusable_sources(order)
68
68
  if order.completed?
69
69
  sources_by_order order
70
70
  else
@@ -75,5 +75,8 @@ module Spree
75
75
  end
76
76
  end
77
77
  end
78
+
79
+ # for backwards compatibility
80
+ alias_method :source_with_profiles, :reusable_sources
78
81
  end
79
82
  end
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  # Manage (recalculate) item (LineItem or Shipment) adjustments
3
3
  class ItemAdjustments
4
+ include ActiveSupport::Callbacks
5
+ define_callbacks :promo_adjustments, :tax_adjustments
4
6
  attr_reader :item
5
7
 
6
8
  delegate :adjustments, :order, to: :item
@@ -32,14 +34,22 @@ module Spree
32
34
  # Included tax adjustments are those which are included in the price.
33
35
  # These ones should not effect the eventual total price.
34
36
  #
35
- # Additional tax adjustments are the opposite; effecting the final total.
36
- promotion_total = adjustments.promotion.reload.map(&:update!).compact.sum
37
- unless promotion_total == 0
38
- choose_best_promotion_adjustment
37
+ # Additional tax adjustments are the opposite; effecting the final total.
38
+ promo_total = 0
39
+ run_callbacks :promo_adjustments do
40
+ promotion_total = adjustments.promotion.reload.map(&:update!).compact.sum
41
+ unless promotion_total == 0
42
+ choose_best_promotion_adjustment
43
+ end
44
+ promo_total = best_promotion_adjustment.try(:amount).to_f
45
+ end
46
+
47
+ included_tax_total = 0
48
+ additional_tax_total = 0
49
+ run_callbacks :tax_adjustments do
50
+ included_tax_total = adjustments.tax.included.reload.map(&:update!).compact.sum
51
+ additional_tax_total = adjustments.tax.additional.reload.map(&:update!).compact.sum
39
52
  end
40
- promo_total = best_promotion_adjustment.try(:amount).to_f
41
- included_tax_total = adjustments.tax.included.reload.map(&:update!).compact.sum
42
- additional_tax_total = adjustments.tax.additional.reload.map(&:update!).compact.sum
43
53
 
44
54
  item.update_columns(
45
55
  :promo_total => promo_total,
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class LineItem < ActiveRecord::Base
3
3
  before_validation :adjust_quantity
4
- belongs_to :order, class_name: "Spree::Order", inverse_of: :line_items
4
+ belongs_to :order, class_name: "Spree::Order", inverse_of: :line_items, touch: true
5
5
  belongs_to :variant, class_name: "Spree::Variant", inverse_of: :line_items
6
6
  belongs_to :tax_category, class_name: "Spree::TaxCategory"
7
7
 
@@ -78,7 +78,7 @@ module Spree
78
78
  end
79
79
 
80
80
  def sufficient_stock?
81
- Stock::Quantifier.new(variant_id).can_supply? quantity
81
+ Stock::Quantifier.new(variant).can_supply? quantity
82
82
  end
83
83
 
84
84
  def insufficient_stock?
@@ -48,6 +48,8 @@ module Spree
48
48
  has_many :line_item_adjustments, through: :line_items, source: :adjustments
49
49
  has_many :shipment_adjustments, through: :shipments, source: :adjustments
50
50
  has_many :inventory_units, inverse_of: :order
51
+ has_many :products, through: :variants
52
+ has_many :variants, through: :line_items
51
53
 
52
54
  has_and_belongs_to_many :promotions, join_table: 'spree_orders_promotions'
53
55
 
@@ -87,8 +89,12 @@ module Spree
87
89
  where(number: number)
88
90
  end
89
91
 
92
+ scope :created_between, ->(start_date, end_date) { where(created_at: start_date..end_date) }
93
+ scope :completed_between, ->(start_date, end_date) { where(completed_at: start_date..end_date) }
94
+
90
95
  def self.between(start_date, end_date)
91
- where(created_at: start_date..end_date)
96
+ ActiveSupport::Deprecation.warn("Order#between will be deprecated in Spree 2.3, please use either Order#created_between or Order#completed_between instead.")
97
+ self.created_between(start_date, end_date)
92
98
  end
93
99
 
94
100
  def self.by_customer(customer)
@@ -114,7 +120,8 @@ module Spree
114
120
  end
115
121
 
116
122
  def all_adjustments
117
- Adjustment.where("order_id = :order_id OR adjustable_id = :order_id", :order_id => self.id)
123
+ Adjustment.where("order_id = :order_id OR (adjustable_id = :order_id AND adjustable_type = 'Spree::Order')",
124
+ :order_id => self.id)
118
125
  end
119
126
 
120
127
  # For compatiblity with Calculator::PriceSack
@@ -146,6 +153,10 @@ module Spree
146
153
  Spree::Money.new(additional_tax_total, { currency: currency })
147
154
  end
148
155
 
156
+ def display_tax_total
157
+ Spree::Money.new(included_tax_total + additional_tax_total, { currency: currency })
158
+ end
159
+
149
160
  def display_shipment_total
150
161
  Spree::Money.new(shipment_total, { currency: currency })
151
162
  end
@@ -197,7 +208,7 @@ module Spree
197
208
  # Returns the relevant zone (if any) to be used for taxation purposes.
198
209
  # Uses default tax zone unless there is a specific match
199
210
  def tax_zone
200
- Zone.match(tax_address) || Zone.default_tax
211
+ @tax_zone ||= Zone.match(tax_address) || Zone.default_tax
201
212
  end
202
213
 
203
214
  # Indicates whether tax should be backed out of the price calcualtions in
@@ -205,7 +216,7 @@ module Spree
205
216
  # taxes in that case.
206
217
  def exclude_tax?
207
218
  return false unless Spree::Config[:prices_inc_tax]
208
- return tax_zone != Zone.default_tax
219
+ tax_zone != Zone.default_tax
209
220
  end
210
221
 
211
222
  # Returns the address for taxation based on configuration
@@ -244,14 +255,16 @@ module Spree
244
255
  end
245
256
 
246
257
  # Associates the specified user with the order.
247
- def associate_user!(user)
258
+ def associate_user!(user, override_email = true)
248
259
  self.user = user
249
- self.email = user.email
250
- self.created_by = user if self.created_by.blank?
260
+ attrs_to_set = { user_id: user.id }
261
+ attrs_to_set[:email] = user.email if override_email
262
+ attrs_to_set[:created_by_id] = user.id if self.created_by.blank?
263
+ assign_attributes(attrs_to_set)
251
264
 
252
265
  if persisted?
253
266
  # immediately persist the changes we just made, but don't use save since we might have an invalid address associated
254
- self.class.unscoped.where(id: id).update_all(email: user.email, user_id: user.id, created_by_id: self.created_by_id)
267
+ self.class.unscoped.where(id: id).update_all(attrs_to_set)
255
268
  end
256
269
  end
257
270
 
@@ -395,16 +408,8 @@ module Spree
395
408
  bill_address.try(:lastname)
396
409
  end
397
410
 
398
- def products
399
- line_items.map(&:product)
400
- end
401
-
402
- def variants
403
- line_items.map(&:variant)
404
- end
405
-
406
411
  def insufficient_stock_lines
407
- @insufficient_stock_lines ||= line_items.select(&:insufficient_stock?)
412
+ line_items.select(&:insufficient_stock?)
408
413
  end
409
414
 
410
415
  def merge!(order, user = nil)
@@ -422,6 +427,10 @@ module Spree
422
427
 
423
428
  self.associate_user!(user) if !self.user && !user.blank?
424
429
 
430
+ updater.update_item_count
431
+ updater.update_item_total
432
+ updater.persist_totals
433
+
425
434
  # So that the destroy doesn't take out line items which may have been re-assigned
426
435
  order.line_items.reload
427
436
  order.destroy
@@ -429,6 +438,8 @@ module Spree
429
438
 
430
439
  def empty!
431
440
  line_items.destroy_all
441
+ updater.update_item_count
442
+
432
443
  adjustments.destroy_all
433
444
  update_totals
434
445
  persist_totals
@@ -575,6 +586,11 @@ module Spree
575
586
  self.ensure_updated_shipments
576
587
  end
577
588
 
589
+ def reload
590
+ remove_instance_variable(:@tax_zone) if defined?(@tax_zone)
591
+ super
592
+ end
593
+
578
594
  private
579
595
 
580
596
  def link_by_email
@@ -583,7 +599,7 @@ module Spree
583
599
 
584
600
  # Determine if email is required (we don't want validation errors before we hit the checkout)
585
601
  def require_email
586
- return true unless new_record? or ['cart', 'address'].include?(state)
602
+ true unless new_record? or ['cart', 'address'].include?(state)
587
603
  end
588
604
 
589
605
  def ensure_line_items_present
@@ -607,7 +623,7 @@ module Spree
607
623
 
608
624
  def after_cancel
609
625
  shipments.each { |shipment| shipment.cancel! }
610
- payments.completed.each { |payment| payment.credit! }
626
+ payments.completed.each { |payment| payment.cancel! }
611
627
 
612
628
  send_cancel_email
613
629
  self.update_column(:payment_state, 'credit_owed') unless shipped?
@@ -38,7 +38,7 @@ module Spree
38
38
  # To avoid multiple occurrences of the same transition being defined
39
39
  # On first definition, state_machines will not be defined
40
40
  state_machines.clear if respond_to?(:state_machines)
41
- state_machine :state, :initial => :cart do
41
+ state_machine :state, :initial => :cart, :use_transactions => false, :action => :save_state do
42
42
  klass.next_event_transitions.each { |t| transition(t.merge(:on => :next)) }
43
43
 
44
44
  # Persist the state on the order
@@ -101,6 +101,8 @@ module Spree
101
101
  order.persist_totals
102
102
  end
103
103
  end
104
+
105
+ alias_method :save_state, :save
104
106
  end
105
107
 
106
108
  def self.go_to_state(name, options={})
@@ -149,9 +149,15 @@ module Spree
149
149
  elsif payments.last.state == 'checkout'
150
150
  order.payment_state = 'pending'
151
151
  elsif payments.last.state == 'completed'
152
- order.payment_state = 'credit_owed'
153
- else
152
+ if line_items.empty?
153
+ order.payment_state = 'credit_owed'
154
+ else
155
+ order.payment_state = 'balance_due'
156
+ end
157
+ elsif payments.last.state == 'pending'
154
158
  order.payment_state = 'balance_due'
159
+ else
160
+ order.payment_state = 'credit_owed'
155
161
  end
156
162
  else
157
163
  order.payment_state = 'balance_due'
@@ -113,8 +113,8 @@ module Spree
113
113
 
114
114
  # see https://github.com/spree/spree/issues/981
115
115
  def build_source
116
- return if source_attributes.nil?
117
- if payment_method and payment_method.payment_source_class
116
+ return unless new_record?
117
+ if source_attributes.present? && source.blank? && payment_method.try(:payment_source_class)
118
118
  self.source = payment_method.payment_source_class.new(source_attributes)
119
119
  self.source.payment_method_id = payment_method.id
120
120
  self.source.user_id = self.order.user_id if self.order
@@ -111,6 +111,14 @@ module Spree
111
111
  end
112
112
  end
113
113
 
114
+ def cancel!
115
+ if payment_method.respond_to?(:cancel)
116
+ payment_method.cancel(response_code)
117
+ else
118
+ credit!
119
+ end
120
+ end
121
+
114
122
  def partial_credit(amount)
115
123
  return if amount > credit_allowed
116
124
  started_processing!
@@ -118,6 +126,7 @@ module Spree
118
126
  end
119
127
 
120
128
  def gateway_options
129
+ order.reload
121
130
  options = { :email => order.email,
122
131
  :customer => order.email,
123
132
  :customer_id => order.user_id,
@@ -54,6 +54,12 @@ module Spree
54
54
  true
55
55
  end
56
56
 
57
+ # Custom gateways should redefine this method. See Gateway implementation
58
+ # as an example
59
+ def reusable_sources(order)
60
+ []
61
+ end
62
+
57
63
  def auto_capture?
58
64
  self.auto_capture.nil? ? Spree::Config[:auto_capture] : self.auto_capture
59
65
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class Price < ActiveRecord::Base
3
3
  acts_as_paranoid
4
- belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices
4
+ belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
5
5
 
6
6
  validate :check_price
7
7
  validates :amount, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
@@ -29,6 +29,7 @@ module Spree
29
29
  end
30
30
 
31
31
  private
32
+
32
33
  def check_price
33
34
  raise "Price must belong to a variant" if variant.nil?
34
35
 
@@ -51,4 +52,3 @@ module Spree
51
52
 
52
53
  end
53
54
  end
54
-
@@ -201,7 +201,7 @@ module Spree
201
201
  if self.variants_including_master.any? { |v| !v.should_track_inventory? }
202
202
  Float::INFINITY
203
203
  else
204
- self.stock_items.sum(&:count_on_hand)
204
+ self.stock_items.to_a.sum(&:count_on_hand)
205
205
  end
206
206
  end
207
207
 
@@ -257,8 +257,13 @@ module Spree
257
257
  self.master ||= Variant.new
258
258
  end
259
259
 
260
+ # Iterate through this products taxons and taxonomies and touch their timestamps in a batch
260
261
  def touch_taxons
261
- self.taxons.each(&:touch)
262
+ taxons_to_touch = taxons.map(&:self_and_ancestors).flatten.uniq
263
+ Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
264
+
265
+ taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
266
+ Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
262
267
  end
263
268
  end
264
269
  end