spree_core 2.0.7 → 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +5 -2
  3. data/app/models/spree/adjustment.rb +2 -2
  4. data/app/models/spree/gateway.rb +1 -1
  5. data/app/models/spree/inventory_unit.rb +5 -4
  6. data/app/models/spree/line_item.rb +2 -3
  7. data/app/models/spree/option_value.rb +1 -1
  8. data/app/models/spree/order/checkout.rb +4 -0
  9. data/app/models/spree/order.rb +22 -17
  10. data/app/models/spree/order_inventory.rb +1 -1
  11. data/app/models/spree/payment.rb +2 -2
  12. data/app/models/spree/price.rb +5 -0
  13. data/app/models/spree/product/scopes.rb +1 -1
  14. data/app/models/spree/product.rb +3 -3
  15. data/app/models/spree/promotion.rb +1 -8
  16. data/app/models/spree/shipment.rb +9 -14
  17. data/app/models/spree/shipping_method.rb +2 -1
  18. data/app/models/spree/shipping_rate.rb +4 -0
  19. data/app/models/spree/stock/estimator.rb +20 -6
  20. data/app/models/spree/stock/packer.rb +1 -1
  21. data/app/models/spree/stock/quantifier.rb +11 -2
  22. data/app/models/spree/stock_item.rb +1 -1
  23. data/app/models/spree/stock_location.rb +5 -0
  24. data/app/models/spree/stock_movement.rb +3 -1
  25. data/app/models/spree/variant.rb +15 -2
  26. data/app/models/spree/zone.rb +1 -1
  27. data/config/locales/en.yml +4 -0
  28. data/db/migrate/20130417120034_add_index_to_source_columns_on_adjustments.rb +5 -0
  29. data/db/migrate/20131026154747_add_track_inventory_to_variant.rb +5 -0
  30. data/db/migrate/20140120160805_add_index_to_variant_id_and_currency_on_prices.rb +5 -0
  31. data/lib/generators/spree/dummy/dummy_generator.rb +8 -3
  32. data/lib/generators/spree/dummy/templates/rails/database.yml +10 -0
  33. data/lib/spree/core/delegate_belongs_to.rb +2 -0
  34. data/lib/spree/core/engine.rb +5 -1
  35. data/lib/spree/core/permalinks.rb +5 -1
  36. data/lib/spree/core/version.rb +1 -1
  37. data/lib/spree/i18n.rb +1 -0
  38. data/lib/spree/money.rb +171 -1
  39. data/lib/spree/testing_support/capybara_ext.rb +6 -5
  40. data/lib/spree/testing_support/factories/product_factory.rb +4 -0
  41. data/lib/spree/testing_support/factories/variant_factory.rb +15 -0
  42. metadata +147 -158
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c0e00c7f8d48f1f8f6a553128e0f324baf1b80b
4
- data.tar.gz: 13ad6252099846dd0af9cb82e417d804199ecfa5
3
+ metadata.gz: 14ac66f9e7ddcb8372dfead29fd08ba8153910c2
4
+ data.tar.gz: 08206ae70c25c4689dddd12fbab62c82e360fbd0
5
5
  SHA512:
6
- metadata.gz: c87d7b7176aa8f6447eba1897834beb1889741ab3b2a8fe6d0090d25559a96d2f104447a89ced51264099b4ed43e8cc8a9504e8c986bcb868bec309a73d5c71b
7
- data.tar.gz: 884eef22bc8e8e9b6caf813c24b453582089d2966aab9cc924c62fcda7c8fefe0608513b464ed761c157f46047ec3b208b44c1d6e4fa3570e2ffdccdfe204ac9
6
+ metadata.gz: 6aa9dadaa97ec4cd19384d095b92f3bad8e6b0378906c1fa2de65dc3423837a066c09bc602aafe532e0ba11a9cfae36ef8d8887f44f1ebede67d5f922c77fa34
7
+ data.tar.gz: 4d405953434dafed6a819848cc601c2b718d971cb89ff3e9e4413a7692b1f99902f4502a9d56ee870020fa6f61328ac41980d3087f8f793fc67467137d9119a4
@@ -34,7 +34,7 @@ module Spree
34
34
  v.options_text
35
35
  end
36
36
 
37
- def meta_data_tags
37
+ def meta_data
38
38
  object = instance_variable_get('@'+controller_name.singularize)
39
39
  meta = {}
40
40
 
@@ -51,8 +51,11 @@ module Spree
51
51
  keywords: Spree::Config[:default_meta_keywords],
52
52
  description: Spree::Config[:default_meta_description]
53
53
  })
54
+ meta
55
+ end
54
56
 
55
- meta.map do |name, content|
57
+ def meta_data_tags
58
+ meta_data.map do |name, content|
56
59
  tag('meta', name: name, content: content)
57
60
  end.join("\n")
58
61
  end
@@ -55,8 +55,8 @@ module Spree
55
55
  scope :shipping, -> { where(originator_type: 'Spree::ShippingMethod') }
56
56
  scope :optional, -> { where(mandatory: false) }
57
57
  scope :eligible, -> { where(eligible: true) }
58
- scope :charge, -> { where('amount >= 0') }
59
- scope :credit, -> { where('amount < 0') }
58
+ scope :charge, -> { where("#{quoted_table_name}.amount >= 0") }
59
+ scope :credit, -> { where("#{quoted_table_name}.amount < 0") }
60
60
  scope :promotion, -> { where(originator_type: 'Spree::PromotionAction') }
61
61
  scope :return_authorization, -> { where(source_type: "Spree::ReturnAuthorization") }
62
62
 
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Gateway < PaymentMethod
3
- delegate_belongs_to :provider, :authorize, :purchase, :capture, :void, :credit
3
+ delegate :authorize, :purchase, :capture, :void, :credit, to: :provider
4
4
 
5
5
  validates :name, :type, presence: true
6
6
 
@@ -2,16 +2,17 @@ module Spree
2
2
  class InventoryUnit < ActiveRecord::Base
3
3
  belongs_to :variant, class_name: "Spree::Variant"
4
4
  belongs_to :order, class_name: "Spree::Order"
5
- belongs_to :shipment, class_name: "Spree::Shipment"
5
+ belongs_to :shipment, class_name: "Spree::Shipment", touch: true
6
6
  belongs_to :return_authorization, class_name: "Spree::ReturnAuthorization"
7
7
 
8
8
  scope :backordered, -> { where state: 'backordered' }
9
9
  scope :shipped, -> { where state: 'shipped' }
10
10
  scope :backordered_per_variant, ->(stock_item) do
11
- includes(:shipment)
11
+ includes(:shipment, :order)
12
12
  .where("spree_shipments.state != 'canceled'")
13
13
  .where(variant_id: stock_item.variant_id)
14
- .backordered.order("#{self.table_name}.created_at ASC")
14
+ .where('spree_orders.completed_at is not null')
15
+ .backordered.order("spree_orders.completed_at ASC")
15
16
  end
16
17
 
17
18
  attr_accessible :shipment, :variant_id
@@ -36,7 +37,7 @@ module Spree
36
37
  # lead to issues once users tried to modify the objects returned. That's due
37
38
  # to ActiveRecord `joins(shipment: :stock_location)` only return readonly
38
39
  # objects
39
- #
40
+ #
40
41
  # Returns an array of backordered inventory units as per a given stock item
41
42
  def self.backordered_for_stock_item(stock_item)
42
43
  backordered_per_variant(stock_item).select do |unit|
@@ -22,12 +22,11 @@ module Spree
22
22
 
23
23
  attr_accessible :quantity, :variant_id
24
24
 
25
- before_save :update_inventory
26
-
25
+ after_save :update_inventory
27
26
  after_save :update_order
28
27
  after_destroy :update_order
29
28
 
30
- delegate :name, :description, to: :variant
29
+ delegate :name, :description, :should_track_inventory?, to: :variant
31
30
 
32
31
  attr_accessor :target_shipment
33
32
 
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class OptionValue < ActiveRecord::Base
3
- belongs_to :option_type
3
+ belongs_to :option_type, :class_name => 'Spree::OptionType', :touch => true
4
4
  acts_as_list scope: :option_type
5
5
  has_and_belongs_to_many :variants, join_table: 'spree_option_values_variants', class_name: "Spree::Variant"
6
6
 
@@ -145,6 +145,10 @@ module Spree
145
145
  @checkout_steps ||= {}
146
146
  end
147
147
 
148
+ def self.checkout_step_names
149
+ self.checkout_steps.keys
150
+ end
151
+
148
152
  def self.add_transition(options)
149
153
  self.next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
150
154
  end
@@ -28,7 +28,7 @@ module Spree
28
28
 
29
29
  attr_accessible :line_items, :bill_address_attributes, :ship_address_attributes,
30
30
  :payments_attributes, :ship_address, :bill_address, :currency,
31
- :line_items_attributes, :number, :email, :use_billing,
31
+ :line_items_attributes, :number, :email, :use_billing,
32
32
  :special_instructions, :shipments_attributes, :coupon_code
33
33
 
34
34
  attr_reader :coupon_code
@@ -103,7 +103,7 @@ module Spree
103
103
  end
104
104
 
105
105
  def self.complete
106
- where('completed_at IS NOT NULL')
106
+ where("#{quoted_table_name}.completed_at IS NOT NULL")
107
107
  end
108
108
 
109
109
  def self.incomplete
@@ -172,11 +172,12 @@ module Spree
172
172
 
173
173
  # If true, causes the confirmation step to happen during the checkout process
174
174
  def confirmation_required?
175
- if payments.empty? and Spree::Config[:always_include_confirm_step]
176
- true
177
- else
178
- payments.map(&:payment_method).compact.any?(&:payment_profiles_supported?)
179
- end
175
+ Spree::Config[:always_include_confirm_step] ||
176
+ payments.valid.map(&:payment_method).compact.any?(&:payment_profiles_supported?) ||
177
+ # Little hacky fix for #4117
178
+ # If this wasn't here, order would transition to address state on confirm failure
179
+ # because there would be no valid payments any more.
180
+ state == 'confirm'
180
181
  end
181
182
 
182
183
  # Indicates the number of items in the order
@@ -401,7 +402,7 @@ module Spree
401
402
  end
402
403
 
403
404
  def available_payment_methods
404
- @available_payment_methods ||= PaymentMethod.available(:front_end)
405
+ @available_payment_methods ||= (PaymentMethod.available(:front_end) + PaymentMethod.available(:both)).uniq
405
406
  end
406
407
 
407
408
  def pending_payments
@@ -498,12 +499,15 @@ module Spree
498
499
  state = "#{name}_state"
499
500
  if persisted?
500
501
  old_state = self.send("#{state}_was")
501
- self.state_changes.create({
502
- previous_state: old_state,
503
- next_state: self.send(state),
504
- name: name,
505
- user_id: self.user_id
506
- }, without_protection: true)
502
+ new_state = self.send(state)
503
+ unless old_state == new_state
504
+ self.state_changes.create({
505
+ previous_state: old_state,
506
+ next_state: new_state,
507
+ name: name,
508
+ user_id: self.user_id
509
+ }, :without_protection => true)
510
+ end
507
511
  end
508
512
  end
509
513
 
@@ -545,7 +549,7 @@ module Spree
545
549
  #
546
550
  # At some point the might need to force the order to transition from address
547
551
  # to delivery again so that proper updated shipments are created.
548
- # e.g. customer goes back from payment step and changes order items
552
+ # e.g. customer goes back from payment step and changes order items
549
553
  def ensure_updated_shipments
550
554
  if shipments.any?
551
555
  self.shipments.destroy_all
@@ -565,7 +569,7 @@ module Spree
565
569
 
566
570
  # Determine if email is required (we don't want validation errors before we hit the checkout)
567
571
  def require_email
568
- return true unless new_record? or state == 'cart'
572
+ return true unless new_record? or ['cart', 'address'].include?(state)
569
573
  end
570
574
 
571
575
  def ensure_line_items_present
@@ -594,9 +598,10 @@ module Spree
594
598
 
595
599
  def after_cancel
596
600
  shipments.each { |shipment| shipment.cancel! }
601
+ payments.completed.each { |payment| payment.credit! }
597
602
 
598
603
  send_cancel_email
599
- self.payment_state = 'credit_owed' unless shipped?
604
+ self.update_column(:payment_state, 'credit_owed') unless shipped?
600
605
  end
601
606
 
602
607
  def send_cancel_email
@@ -65,7 +65,7 @@ module Spree
65
65
  end
66
66
 
67
67
  def add_to_shipment(shipment, variant, quantity)
68
- if Config.track_inventory_levels
68
+ if variant.should_track_inventory?
69
69
  on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
70
70
 
71
71
  on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze
6
6
 
7
- belongs_to :order, class_name: 'Spree::Order'
7
+ belongs_to :order, class_name: 'Spree::Order', touch: true
8
8
  belongs_to :source, polymorphic: true
9
9
  belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
10
10
 
@@ -31,7 +31,7 @@ module Spree
31
31
  scope :completed, with_state('completed')
32
32
  scope :pending, with_state('pending')
33
33
  scope :failed, with_state('failed')
34
- scope :valid, where('state NOT IN (?)', %w(failed invalid))
34
+ scope :valid, where("#{quoted_table_name}.state NOT IN (?)", %w(failed invalid))
35
35
 
36
36
  after_rollback :persist_invalid
37
37
 
@@ -24,6 +24,11 @@ module Spree
24
24
  self[:amount] = parse_price(price)
25
25
  end
26
26
 
27
+ # Remove variant default_scope `deleted_at: nil`
28
+ def variant
29
+ Spree::Variant.unscoped { super }
30
+ end
31
+
27
32
  private
28
33
  def check_price
29
34
  raise "Price must belong to a variant" if variant.nil?
@@ -24,7 +24,7 @@ module Spree
24
24
  next if name.to_s.include?("master_price")
25
25
  parts = name.to_s.match(/(.*)_by_(.*)/)
26
26
  order_text = "#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? "ASC" : "DESC"}"
27
- self.scope(name.to_s, relation.order(order_text))
27
+ self.scope(name.to_s, order(order_text))
28
28
  end
29
29
  end
30
30
 
@@ -220,10 +220,10 @@ module Spree
220
220
  end
221
221
 
222
222
  def total_on_hand
223
- if Spree::Config.track_inventory_levels
224
- self.stock_items.sum(&:count_on_hand)
225
- else
223
+ if self.variants_including_master.any? { |v| !v.should_track_inventory? }
226
224
  Float::INFINITY
225
+ else
226
+ self.stock_items.sum(&:count_on_hand)
227
227
  end
228
228
  end
229
229
 
@@ -26,13 +26,6 @@ module Spree
26
26
  validates :path, presence: true, if: lambda{|r| r.event_name == 'spree.content.visited' }
27
27
  validates :usage_limit, numericality: { greater_than: 0, allow_nil: true }
28
28
 
29
- # TODO: This shouldn't be necessary with :autosave option but nested attribute updating of actions is broken without it
30
- after_save :save_rules_and_actions
31
-
32
- def save_rules_and_actions
33
- (rules + actions).each &:save
34
- end
35
-
36
29
  def self.advertised
37
30
  where(advertise: true)
38
31
  end
@@ -96,7 +89,7 @@ module Spree
96
89
  end
97
90
 
98
91
  def credits
99
- Adjustment.promotion.where(originator_id: actions.map(&:id))
92
+ Adjustment.eligible.promotion.where(originator_id: actions.map(&:id))
100
93
  end
101
94
 
102
95
  def credits_count
@@ -2,7 +2,7 @@ require 'ostruct'
2
2
 
3
3
  module Spree
4
4
  class Shipment < ActiveRecord::Base
5
- belongs_to :order, class_name: 'Spree::Order'
5
+ belongs_to :order, class_name: 'Spree::Order', touch: true
6
6
  belongs_to :address, class_name: 'Spree::Address'
7
7
  belongs_to :stock_location, class_name: 'Spree::StockLocation'
8
8
 
@@ -12,7 +12,6 @@ module Spree
12
12
  has_many :inventory_units, dependent: :delete_all
13
13
  has_one :adjustment, as: :source, dependent: :destroy
14
14
 
15
- before_create :generate_shipment_number
16
15
  after_save :ensure_correct_adjustment, :update_order
17
16
 
18
17
  attr_accessor :special_instructions
@@ -22,7 +21,7 @@ module Spree
22
21
  accepts_nested_attributes_for :address
23
22
  accepts_nested_attributes_for :inventory_units
24
23
 
25
- make_permalink field: :number
24
+ make_permalink field: :number, length: 11, prefix: 'H'
26
25
 
27
26
  scope :shipped, -> { with_state('shipped') }
28
27
  scope :ready, -> { with_state('ready') }
@@ -166,8 +165,8 @@ module Spree
166
165
  end
167
166
 
168
167
  def line_items
169
- if order.complete? and Spree::Config[:track_inventory_levels]
170
- order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) }
168
+ if order.complete? and Spree::Config.track_inventory_levels
169
+ order.line_items.select { |li| !li.should_track_inventory? || inventory_units.pluck(:variant_id).include?(li.variant_id) }
171
170
  else
172
171
  order.line_items
173
172
  end
@@ -243,17 +242,13 @@ module Spree
243
242
  end
244
243
 
245
244
  def manifest_restock(item)
246
- stock_location.restock item.variant, item.quantity, self
247
- end
245
+ if item.states["on_hand"].to_i > 0
246
+ stock_location.restock item.variant, item.states["on_hand"], self
247
+ end
248
248
 
249
- def generate_shipment_number
250
- return number unless number.blank?
251
- record = true
252
- while record
253
- random = "H#{Array.new(11) { rand(9) }.join}"
254
- record = self.class.where(number: random).first
249
+ if item.states["backordered"].to_i > 0
250
+ stock_location.restock_backordered item.variant, item.states["backordered"]
255
251
  end
256
- self.number = random
257
252
  end
258
253
 
259
254
  def description_for_shipping_charge
@@ -43,7 +43,8 @@ module Spree
43
43
  end
44
44
 
45
45
  def build_tracking_url(tracking)
46
- tracking_url.gsub(/:tracking/, tracking) unless tracking.blank? || tracking_url.blank?
46
+ return if tracking.blank? || tracking_url.blank?
47
+ tracking_url.gsub(/:tracking/, ERB::Util.url_encode(tracking)) # :url_encode exists in 1.8.7 through 2.1.0
47
48
  end
48
49
 
49
50
  def self.calculators
@@ -22,5 +22,9 @@ module Spree
22
22
  Spree::Money.new(price, { currency: currency })
23
23
  end
24
24
  alias_method :display_cost, :display_price
25
+
26
+ def shipping_method
27
+ Spree::ShippingMethod.unscoped { super }
28
+ end
25
29
  end
26
30
  end
@@ -15,7 +15,8 @@ module Spree
15
15
 
16
16
  shipping_methods.each do |shipping_method|
17
17
  cost = calculate_cost(shipping_method, package)
18
- shipping_rates << shipping_method.shipping_rates.new(:cost => cost) unless cost.nil?
18
+ rate = shipping_method.shipping_rates.new(:cost => cost) unless cost.nil?
19
+ shipping_rates << rate unless rate.nil?
19
20
  end
20
21
 
21
22
  shipping_rates.sort_by! { |r| r.cost || 0 }
@@ -34,17 +35,30 @@ module Spree
34
35
  end
35
36
 
36
37
  private
38
+
37
39
  def shipping_methods(package)
38
- shipping_methods = package.shipping_methods
39
- shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package) }
40
- shipping_methods.delete_if { |ship_method| !ship_method.include?(order.ship_address) }
41
- shipping_methods.delete_if { |ship_method| !(ship_method.calculator.preferences[:currency].nil? || ship_method.calculator.preferences[:currency] == currency) }
42
- shipping_methods
40
+ package.shipping_methods.select do |ship_method|
41
+ calculator = ship_method.calculator
42
+ begin
43
+ calculator.available?(package) &&
44
+ ship_method.include?(order.ship_address) &&
45
+ (calculator.preferences[:currency].nil? ||
46
+ calculator.preferences[:currency] == currency)
47
+ rescue Exception => exception
48
+ log_calculator_exception(ship_method, exception)
49
+ end
50
+ end
43
51
  end
44
52
 
45
53
  def calculate_cost(shipping_method, package)
46
54
  shipping_method.calculator.compute(package)
47
55
  end
56
+
57
+ def log_calculator_exception(ship_method, exception)
58
+ Rails.logger.error("Something went wrong calculating rates with the #{ship_method.name} (ID=#{ship_method.id}) shipping method.")
59
+ Rails.logger.error("*" * 50)
60
+ Rails.logger.error(exception.backtrace.join("\n"))
61
+ end
48
62
  end
49
63
  end
50
64
  end
@@ -20,7 +20,7 @@ module Spree
20
20
  def default_package
21
21
  package = Package.new(stock_location, order)
22
22
  order.line_items.each do |line_item|
23
- if Config.track_inventory_levels
23
+ if line_item.should_track_inventory?
24
24
  next unless stock_location.stock_item(line_item.variant)
25
25
 
26
26
  on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity)
@@ -4,12 +4,12 @@ module Spree
4
4
  attr_reader :stock_items
5
5
 
6
6
  def initialize(variant)
7
- @variant = variant
7
+ @variant = resolve_variant_id(variant)
8
8
  @stock_items = Spree::StockItem.joins(:stock_location).where(:variant_id => @variant, Spree::StockLocation.table_name =>{ :active => true})
9
9
  end
10
10
 
11
11
  def total_on_hand
12
- if Spree::Config.track_inventory_levels
12
+ if @variant.should_track_inventory?
13
13
  stock_items.sum(:count_on_hand)
14
14
  else
15
15
  Float::INFINITY
@@ -23,6 +23,15 @@ module Spree
23
23
  def can_supply?(required)
24
24
  total_on_hand >= required || backorderable?
25
25
  end
26
+
27
+ private
28
+
29
+ # return variant when passed either variant object or variant id
30
+ def resolve_variant_id(variant)
31
+ variant = Spree::Variant.find_by_id(variant) unless variant.respond_to?(:should_track_inventory?)
32
+ variant
33
+ end
34
+
26
35
  end
27
36
  end
28
37
  end
@@ -11,7 +11,7 @@ module Spree
11
11
 
12
12
  attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id
13
13
 
14
- delegate :weight, to: :variant
14
+ delegate :weight, :should_track_inventory?, to: :variant
15
15
 
16
16
  def backordered_inventory_units
17
17
  Spree::InventoryUnit.backordered_for_stock_item(self)
@@ -48,6 +48,11 @@ module Spree
48
48
  move(variant, quantity, originator)
49
49
  end
50
50
 
51
+ def restock_backordered(variant, quantity, originator = nil)
52
+ item = stock_item_or_create(variant)
53
+ item.update_column(:count_on_hand, item.count_on_hand + quantity)
54
+ end
55
+
51
56
  def unstock(variant, quantity, originator = nil)
52
57
  move(variant, -quantity, originator)
53
58
  end
@@ -17,10 +17,12 @@ module Spree
17
17
  end
18
18
 
19
19
  private
20
+
20
21
  def update_stock_item_quantity
21
- return unless Spree::Config[:track_inventory_levels]
22
+ return unless self.stock_item.should_track_inventory?
22
23
  stock_item.adjust_count_on_hand quantity
23
24
  end
25
+
24
26
  end
25
27
  end
26
28
 
@@ -11,7 +11,8 @@ module Spree
11
11
  attr_accessible :name, :presentation, :cost_price, :lock_version,
12
12
  :position, :option_value_ids,
13
13
  :product_id, :option_values_attributes, :price,
14
- :weight, :height, :width, :depth, :sku, :cost_currency
14
+ :weight, :height, :width, :depth, :sku, :cost_currency,
15
+ :track_inventory, :options
15
16
 
16
17
  has_many :inventory_units
17
18
  has_many :line_items
@@ -44,7 +45,7 @@ module Spree
44
45
  after_create :set_position
45
46
 
46
47
  # default variant scope only lists non-deleted variants
47
- scope :deleted, lambda { where('deleted_at IS NOT NULL') }
48
+ scope :deleted, lambda { where("#{quoted_table_name}.deleted_at IS NOT NULL") }
48
49
 
49
50
  def self.active(currency = nil)
50
51
  joins(:prices).where(deleted_at: nil).where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
@@ -80,6 +81,12 @@ module Spree
80
81
  deleted_at
81
82
  end
82
83
 
84
+ def options=(options = {})
85
+ options.each do |option|
86
+ set_option_value(option[:name], option[:value])
87
+ end
88
+ end
89
+
83
90
  def set_option_value(opt_name, opt_value)
84
91
  # no option values on master
85
92
  return if self.is_master
@@ -146,6 +153,12 @@ module Spree
146
153
  Spree::Product.unscoped { super }
147
154
  end
148
155
 
156
+ # Shortcut method to determine if inventory tracking is enabled for this variant
157
+ # This considers both variant tracking flag and site-wide inventory tracking settings
158
+ def should_track_inventory?
159
+ self.track_inventory? && Spree::Config.track_inventory_levels
160
+ end
161
+
149
162
  private
150
163
  # strips all non-price-like characters from the price, taking into account locale settings
151
164
  def parse_price(price)
@@ -133,7 +133,7 @@ module Spree
133
133
 
134
134
  def remove_defunct_members
135
135
  if zone_members.any?
136
- zone_members.where('zoneable_id IS NULL OR zoneable_type != ?', "Spree::#{kind.capitalize}").destroy_all
136
+ zone_members.where('zoneable_id IS NULL OR zoneable_type != ?', "Spree::#{kind.classify}").destroy_all
137
137
  end
138
138
  end
139
139
 
@@ -702,6 +702,7 @@ en:
702
702
  no_rules_added: No rules added
703
703
  no_resource_found: ! 'No %{resource} found'
704
704
  no_shipping_methods_found: No shipping methods found
705
+ no_eligible_shipping_methods_found: No eligible shipping methods found
705
706
  no_trackers_found: No Trackers Found
706
707
  no_stock_locations_found: No stock locations found
707
708
  no_tracking_present: No tracking details provided.
@@ -954,6 +955,7 @@ en:
954
955
  shipment_state: Shipment State
955
956
  shipment_states:
956
957
  backorder: backorder
958
+ canceled: canceled
957
959
  partial: partial
958
960
  pending: pending
959
961
  ready: ready
@@ -1052,6 +1054,8 @@ en:
1052
1054
  time: Time
1053
1055
  to_add_variants_you_must_first_define: To add variants, you must first define
1054
1056
  total: Total
1057
+ total_price: Total price
1058
+ track_inventory: Track Inventory
1055
1059
  tracking: Tracking
1056
1060
  tracking_number: Tracking Number
1057
1061
  tracking_url: Tracking URL
@@ -0,0 +1,5 @@
1
+ class AddIndexToSourceColumnsOnAdjustments < ActiveRecord::Migration
2
+ def change
3
+ add_index :spree_adjustments, [:source_type, :source_id]
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddTrackInventoryToVariant < ActiveRecord::Migration
2
+ def change
3
+ add_column :spree_variants, :track_inventory, :boolean, :default => true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddIndexToVariantIdAndCurrencyOnPrices < ActiveRecord::Migration
2
+ def change
3
+ add_index :spree_prices, [:variant_id, :currency]
4
+ end
5
+ end
@@ -53,9 +53,9 @@ module Spree
53
53
  def test_dummy_inject_extension_requirements
54
54
  if DummyGeneratorHelper.inject_extension_requirements
55
55
  inside dummy_path do
56
- %w(spree_frontend spree_backend spree_api).each do |requirement|
57
- inject_into_file 'config/application.rb', "require '#{requirement}'\n", :before => /require '#{@lib_name}'/, :verbose => true
58
- end
56
+ inject_require_for('spree_frontend') if Object.const_defined?("Spree::Frontend")
57
+ inject_require_for('spree_backend') if Object.const_defined?("Spree::Backend")
58
+ inject_require_for('spree_api') if Object.const_defined?("Spree::Api")
59
59
  end
60
60
  end
61
61
  end
@@ -82,6 +82,11 @@ module Spree
82
82
  attr :database
83
83
 
84
84
  protected
85
+
86
+ def inject_require_for(requirement)
87
+ inject_into_file 'config/application.rb', "require '#{requirement}'\n", :before => /require '#{@lib_name}'/, :verbose => true
88
+ end
89
+
85
90
  def dummy_path
86
91
  ENV['DUMMY_PATH'] || 'spec/dummy'
87
92
  end