spree_core 2.0.7 → 2.0.8

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 (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