spree_core 2.1.3 → 2.1.4
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.
- checksums.yaml +4 -4
- data/app/helpers/spree/admin/images_helper.rb +1 -1
- data/app/helpers/spree/base_helper.rb +5 -2
- data/app/models/spree/address.rb +9 -1
- data/app/models/spree/adjustment.rb +2 -2
- data/app/models/spree/calculator/default_tax.rb +5 -1
- data/app/models/spree/credit_card.rb +2 -0
- data/app/models/spree/gateway.rb +1 -1
- data/app/models/spree/inventory_unit.rb +5 -4
- data/app/models/spree/legacy_user.rb +2 -11
- data/app/models/spree/line_item.rb +2 -3
- data/app/models/spree/log_entry.rb +4 -0
- data/app/models/spree/option_type.rb +6 -0
- data/app/models/spree/option_value.rb +12 -1
- data/app/models/spree/order.rb +34 -16
- data/app/models/spree/order/checkout.rb +4 -0
- data/app/models/spree/order_inventory.rb +1 -1
- data/app/models/spree/payment.rb +10 -2
- data/app/models/spree/payment/processing.rb +5 -4
- data/app/models/spree/payment_method.rb +2 -0
- data/app/models/spree/price.rb +5 -0
- data/app/models/spree/product.rb +6 -5
- data/app/models/spree/product/scopes.rb +12 -6
- data/app/models/spree/product_property.rb +1 -1
- data/app/models/spree/promotion.rb +1 -8
- data/app/models/spree/promotion/rules/user_logged_in.rb +1 -3
- data/app/models/spree/property.rb +8 -0
- data/app/models/spree/shipment.rb +9 -14
- data/app/models/spree/shipping_method.rb +3 -2
- data/app/models/spree/shipping_rate.rb +7 -9
- data/app/models/spree/stock/estimator.rb +21 -14
- data/app/models/spree/stock/package.rb +1 -1
- data/app/models/spree/stock/packer.rb +1 -1
- data/app/models/spree/stock/quantifier.rb +11 -2
- data/app/models/spree/stock_item.rb +2 -2
- data/app/models/spree/stock_location.rb +8 -0
- data/app/models/spree/stock_movement.rb +3 -1
- data/app/models/spree/taxon.rb +2 -2
- data/app/models/spree/variant.rb +19 -4
- data/app/models/spree/zone.rb +1 -1
- data/app/views/spree/shared/_routes.html.erb +1 -1
- data/config/locales/en.yml +15 -1
- data/db/default/spree/countries.rb +7 -7
- data/db/migrate/20130417120034_add_index_to_source_columns_on_adjustments.rb +5 -0
- data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +5 -2
- data/db/migrate/20131026154747_add_track_inventory_to_variant.rb +5 -0
- data/db/migrate/20131120234456_add_updated_at_to_variants.rb +5 -0
- data/db/migrate/20131211192741_unique_shipping_method_categories.rb +24 -0
- data/db/migrate/20140120160805_add_index_to_variant_id_and_currency_on_prices.rb +5 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +14 -3
- data/lib/generators/spree/dummy/templates/rails/database.yml +10 -0
- data/lib/spree/core.rb +3 -0
- data/lib/spree/core/controller_helpers/order.rb +4 -1
- data/lib/spree/core/controller_helpers/ssl.rb +5 -7
- data/lib/spree/core/controller_helpers/strong_parameters.rb +6 -0
- data/lib/spree/core/delegate_belongs_to.rb +16 -10
- data/lib/spree/core/engine.rb +11 -2
- data/lib/spree/core/mail_method.rb +27 -0
- data/lib/spree/core/mail_settings.rb +33 -38
- data/lib/spree/core/permalinks.rb +5 -1
- data/lib/spree/core/s3_support.rb +1 -1
- data/lib/spree/core/user_address.rb +30 -0
- data/lib/spree/core/validators/email.rb +9 -3
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/i18n.rb +1 -0
- data/lib/spree/migrations.rb +55 -0
- data/lib/spree/money.rb +171 -1
- data/lib/spree/permitted_attributes.rb +6 -6
- data/lib/spree/testing_support/capybara_ext.rb +6 -5
- data/lib/spree/testing_support/controller_requests.rb +20 -4
- data/lib/spree/testing_support/factories/product_factory.rb +4 -0
- data/lib/spree/testing_support/factories/variant_factory.rb +15 -0
- metadata +158 -164
| @@ -23,7 +23,7 @@ module Spree | |
| 23 23 | 
             
                    # We should not define price scopes here, as they require something slightly different
         | 
| 24 24 | 
             
                    next if name.to_s.include?("master_price")
         | 
| 25 25 | 
             
                    parts = name.to_s.match(/(.*)_by_(.*)/)
         | 
| 26 | 
            -
                    self.scope(name.to_s, -> {  | 
| 26 | 
            +
                    self.scope(name.to_s, -> { order("#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ?  "ASC" : "DESC"}") })
         | 
| 27 27 | 
             
                  end
         | 
| 28 28 | 
             
                end
         | 
| 29 29 |  | 
| @@ -207,13 +207,19 @@ module Spree | |
| 207 207 | 
             
                  group("spree_products.id").joins(:taxons).where(Taxon.arel_table[:name].eq(name))
         | 
| 208 208 | 
             
                end
         | 
| 209 209 |  | 
| 210 | 
            -
                 | 
| 211 | 
            -
                # problem shown in #1247.
         | 
| 212 | 
            -
                def self.group_by_products_id
         | 
| 210 | 
            +
                def self.distinct_by_product_ids(sort_order=nil)
         | 
| 213 211 | 
             
                  if (ActiveRecord::Base.connection.adapter_name == 'PostgreSQL')
         | 
| 214 | 
            -
                     | 
| 212 | 
            +
                    sort_column = sort_order.split(" ").first
         | 
| 213 | 
            +
                    # Don't allow sort_column, a variable coming from params,
         | 
| 214 | 
            +
                    # to be anything but a column in the database
         | 
| 215 | 
            +
                    if column_names.include?(sort_column)
         | 
| 216 | 
            +
                      distinct_fields = ["id", sort_column].compact.join(",")
         | 
| 217 | 
            +
                      select("DISTINCT ON(#{distinct_fields}) spree_products.*")
         | 
| 218 | 
            +
                    else
         | 
| 219 | 
            +
                      scoped
         | 
| 220 | 
            +
                    end
         | 
| 215 221 | 
             
                  else
         | 
| 216 | 
            -
                     | 
| 222 | 
            +
                    select("DISTINCT spree_products.*")
         | 
| 217 223 | 
             
                  end
         | 
| 218 224 | 
             
                end
         | 
| 219 225 |  | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module Spree
         | 
| 2 2 | 
             
              class ProductProperty < ActiveRecord::Base
         | 
| 3 | 
            -
                belongs_to :product, | 
| 3 | 
            +
                belongs_to :product, touch: true, class_name: 'Spree::Product'
         | 
| 4 4 | 
             
                belongs_to :property, class_name: 'Spree::Property'
         | 
| 5 5 |  | 
| 6 6 | 
             
                validates :property, presence: true
         | 
| @@ -21,13 +21,6 @@ module Spree | |
| 21 21 | 
             
                validates :path, presence: true, if: lambda{|r| r.event_name == 'spree.content.visited' }
         | 
| 22 22 | 
             
                validates :usage_limit, numericality: { greater_than: 0, allow_nil: true }
         | 
| 23 23 |  | 
| 24 | 
            -
                # TODO: This shouldn't be necessary with :autosave option but nested attribute updating of actions is broken without it
         | 
| 25 | 
            -
                after_save :save_rules_and_actions
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                def save_rules_and_actions
         | 
| 28 | 
            -
                  (rules + actions).each &:save
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
             | 
| 31 24 | 
             
                def self.advertised
         | 
| 32 25 | 
             
                  where(advertise: true)
         | 
| 33 26 | 
             
                end
         | 
| @@ -91,7 +84,7 @@ module Spree | |
| 91 84 | 
             
                end
         | 
| 92 85 |  | 
| 93 86 | 
             
                def credits
         | 
| 94 | 
            -
                  Adjustment.promotion.where(originator_id: actions.map(&:id))
         | 
| 87 | 
            +
                  Adjustment.eligible.promotion.where(originator_id: actions.map(&:id))
         | 
| 95 88 | 
             
                end
         | 
| 96 89 |  | 
| 97 90 | 
             
                def credits_count
         | 
| @@ -9,11 +9,19 @@ module Spree | |
| 9 9 |  | 
| 10 10 | 
             
                scope :sorted, -> { order(:name) }
         | 
| 11 11 |  | 
| 12 | 
            +
                after_touch :touch_all_products
         | 
| 13 | 
            +
             | 
| 12 14 | 
             
                def self.find_all_by_prototype(prototype)
         | 
| 13 15 | 
             
                  id = prototype
         | 
| 14 16 | 
             
                  id = prototype.id if prototype.class == Prototype
         | 
| 15 17 | 
             
                  joins("LEFT JOIN properties_prototypes ON property_id = #{self.table_name}.id").
         | 
| 16 18 | 
             
                    where(prototype_id: id)
         | 
| 17 19 | 
             
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                private
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def touch_all_products
         | 
| 24 | 
            +
                  products.each(&:touch)
         | 
| 25 | 
            +
                end
         | 
| 18 26 | 
             
              end
         | 
| 19 27 | 
             
            end
         | 
| @@ -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
         | 
| @@ -20,7 +19,7 @@ module Spree | |
| 20 19 | 
             
                accepts_nested_attributes_for :address
         | 
| 21 20 | 
             
                accepts_nested_attributes_for :inventory_units
         | 
| 22 21 |  | 
| 23 | 
            -
                make_permalink field: :number
         | 
| 22 | 
            +
                make_permalink field: :number, length: 11, prefix: 'H'
         | 
| 24 23 |  | 
| 25 24 | 
             
                scope :shipped, -> { with_state('shipped') }
         | 
| 26 25 | 
             
                scope :ready,   -> { with_state('ready') }
         | 
| @@ -164,8 +163,8 @@ module Spree | |
| 164 163 | 
             
                end
         | 
| 165 164 |  | 
| 166 165 | 
             
                def line_items
         | 
| 167 | 
            -
                  if order.complete? and Spree::Config | 
| 168 | 
            -
                    order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) }
         | 
| 166 | 
            +
                  if order.complete? and Spree::Config.track_inventory_levels
         | 
| 167 | 
            +
                    order.line_items.select { |li| !li.should_track_inventory? || inventory_units.pluck(:variant_id).include?(li.variant_id) }
         | 
| 169 168 | 
             
                  else
         | 
| 170 169 | 
             
                    order.line_items
         | 
| 171 170 | 
             
                  end
         | 
| @@ -238,17 +237,13 @@ module Spree | |
| 238 237 | 
             
                  end
         | 
| 239 238 |  | 
| 240 239 | 
             
                  def manifest_restock(item)
         | 
| 241 | 
            -
                     | 
| 242 | 
            -
             | 
| 240 | 
            +
                    if item.states["on_hand"].to_i > 0
         | 
| 241 | 
            +
                     stock_location.restock item.variant, item.states["on_hand"], self
         | 
| 242 | 
            +
                    end
         | 
| 243 243 |  | 
| 244 | 
            -
             | 
| 245 | 
            -
             | 
| 246 | 
            -
                    record = true
         | 
| 247 | 
            -
                    while record
         | 
| 248 | 
            -
                      random = "H#{Array.new(11) { rand(9) }.join}"
         | 
| 249 | 
            -
                      record = self.class.where(number: random).first
         | 
| 244 | 
            +
                    if item.states["backordered"].to_i > 0
         | 
| 245 | 
            +
                      stock_location.restock_backordered item.variant, item.states["backordered"]
         | 
| 250 246 | 
             
                    end
         | 
| 251 | 
            -
                    self.number = random
         | 
| 252 247 | 
             
                  end
         | 
| 253 248 |  | 
| 254 249 | 
             
                  def description_for_shipping_charge
         | 
| @@ -8,7 +8,7 @@ module Spree | |
| 8 8 | 
             
                has_many :shipments
         | 
| 9 9 | 
             
                has_many :shipping_method_categories
         | 
| 10 10 | 
             
                has_many :shipping_categories, through: :shipping_method_categories
         | 
| 11 | 
            -
                has_many :shipping_rates
         | 
| 11 | 
            +
                has_many :shipping_rates, inverse_of: :shipping_method
         | 
| 12 12 |  | 
| 13 13 | 
             
                has_and_belongs_to_many :zones, :join_table => 'spree_shipping_methods_zones',
         | 
| 14 14 | 
             
                                                :class_name => 'Spree::Zone',
         | 
| @@ -30,7 +30,8 @@ module Spree | |
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 32 | 
             
                def build_tracking_url(tracking)
         | 
| 33 | 
            -
                   | 
| 33 | 
            +
                  return if tracking.blank? || tracking_url.blank?
         | 
| 34 | 
            +
                  tracking_url.gsub(/:tracking/, ERB::Util.url_encode(tracking)) # :url_encode exists in 1.8.7 through 2.1.0
         | 
| 34 35 | 
             
                end
         | 
| 35 36 |  | 
| 36 37 | 
             
                def self.calculators
         | 
| @@ -1,19 +1,13 @@ | |
| 1 1 | 
             
            module Spree
         | 
| 2 2 | 
             
              class ShippingRate < ActiveRecord::Base
         | 
| 3 3 | 
             
                belongs_to :shipment, class_name: 'Spree::Shipment'
         | 
| 4 | 
            -
                belongs_to :shipping_method, class_name: 'Spree::ShippingMethod'
         | 
| 4 | 
            +
                belongs_to :shipping_method, class_name: 'Spree::ShippingMethod', inverse_of: :shipping_rates
         | 
| 5 5 |  | 
| 6 | 
            -
                scope : | 
| 6 | 
            +
                scope :with_shipping_method,
         | 
| 7 7 | 
             
                  -> { includes(:shipping_method).
         | 
| 8 | 
            -
                      where(ShippingMethod.on_frontend_query).
         | 
| 9 | 
            -
                      references(:shipping_method).
         | 
| 10 | 
            -
                      order("cost ASC") }
         | 
| 11 | 
            -
                scope :backend,
         | 
| 12 | 
            -
                  -> { includes(:shipping_method).
         | 
| 13 | 
            -
                       where(ShippingMethod.on_backend_query).
         | 
| 14 8 | 
             
                       references(:shipping_method).
         | 
| 15 9 | 
             
                       order("cost ASC") }
         | 
| 16 | 
            -
             | 
| 10 | 
            +
             | 
| 17 11 | 
             
                delegate :order, :currency, to: :shipment
         | 
| 18 12 | 
             
                delegate :name, to: :shipping_method
         | 
| 19 13 |  | 
| @@ -28,5 +22,9 @@ module Spree | |
| 28 22 | 
             
                end
         | 
| 29 23 |  | 
| 30 24 | 
             
                alias_method :display_cost, :display_price
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def shipping_method
         | 
| 27 | 
            +
                  Spree::ShippingMethod.unscoped { super }
         | 
| 28 | 
            +
                end
         | 
| 31 29 | 
             
              end
         | 
| 32 30 | 
             
            end
         | 
| @@ -9,20 +9,17 @@ module Spree | |
| 9 9 | 
             
                  end
         | 
| 10 10 |  | 
| 11 11 | 
             
                  def shipping_rates(package, frontend_only = true)
         | 
| 12 | 
            -
                     | 
| 13 | 
            -
             | 
| 14 | 
            -
                     | 
| 15 | 
            -
             | 
| 16 | 
            -
                      available_rates.select! { |rate| rate.shipping_method.frontend? } if frontend_only
         | 
| 17 | 
            -
                      choose_default_shipping_rate(available_rates)
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                    sort_shipping_rates(shipping_rates)
         | 
| 12 | 
            +
                    rates = calculate_shipping_rates(package)
         | 
| 13 | 
            +
                    rates.select! { |rate| rate.shipping_method.frontend? } if frontend_only
         | 
| 14 | 
            +
                    choose_default_shipping_rate(rates)
         | 
| 15 | 
            +
                    sort_shipping_rates(rates)
         | 
| 21 16 | 
             
                  end
         | 
| 22 17 |  | 
| 23 18 | 
             
                  private
         | 
| 24 19 | 
             
                  def choose_default_shipping_rate(shipping_rates)
         | 
| 25 | 
            -
                    shipping_rates. | 
| 20 | 
            +
                    unless shipping_rates.empty?
         | 
| 21 | 
            +
                      shipping_rates.min_by(&:cost).selected = true
         | 
| 22 | 
            +
                    end
         | 
| 26 23 | 
             
                  end
         | 
| 27 24 |  | 
| 28 25 | 
             
                  def sort_shipping_rates(shipping_rates)
         | 
| @@ -39,12 +36,22 @@ module Spree | |
| 39 36 | 
             
                  def shipping_methods(package)
         | 
| 40 37 | 
             
                    package.shipping_methods.select do |ship_method|
         | 
| 41 38 | 
             
                      calculator = ship_method.calculator
         | 
| 42 | 
            -
                       | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 39 | 
            +
                      begin
         | 
| 40 | 
            +
                        calculator.available?(package) &&
         | 
| 41 | 
            +
                        ship_method.include?(order.ship_address) &&
         | 
| 42 | 
            +
                        (calculator.preferences[:currency].nil? ||
         | 
| 43 | 
            +
                         calculator.preferences[:currency] == currency)
         | 
| 44 | 
            +
                      rescue Exception => exception
         | 
| 45 | 
            +
                        log_calculator_exception(ship_method, exception)
         | 
| 46 | 
            +
                      end
         | 
| 46 47 | 
             
                    end
         | 
| 47 48 | 
             
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def log_calculator_exception(ship_method, exception)
         | 
| 51 | 
            +
                    Rails.logger.info("Something went wrong calculating rates with the #{ship_method.name} (ID=#{ship_method.id}) shipping method.")
         | 
| 52 | 
            +
                    Rails.logger.info("*" * 50)
         | 
| 53 | 
            +
                    Rails.logger.info(exception.backtrace.join("\n"))
         | 
| 54 | 
            +
                  end
         | 
| 48 55 | 
             
                end
         | 
| 49 56 | 
             
              end
         | 
| 50 57 | 
             
            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  | 
| 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  | 
| 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
         | 
| @@ -3,13 +3,13 @@ module Spree | |
| 3 3 | 
             
                acts_as_paranoid
         | 
| 4 4 |  | 
| 5 5 | 
             
                belongs_to :stock_location, class_name: 'Spree::StockLocation'
         | 
| 6 | 
            -
                belongs_to :variant, class_name: 'Spree::Variant'
         | 
| 6 | 
            +
                belongs_to :variant, class_name: 'Spree::Variant', touch: true
         | 
| 7 7 | 
             
                has_many :stock_movements
         | 
| 8 8 |  | 
| 9 9 | 
             
                validates_presence_of :stock_location, :variant
         | 
| 10 10 | 
             
                validates_uniqueness_of :variant_id, scope: [:stock_location_id, :deleted_at]
         | 
| 11 11 |  | 
| 12 | 
            -
                delegate :weight, to: :variant
         | 
| 12 | 
            +
                delegate :weight, :should_track_inventory?, to: :variant
         | 
| 13 13 |  | 
| 14 14 | 
             
                def backordered_inventory_units
         | 
| 15 15 | 
             
                  Spree::InventoryUnit.backordered_for_stock_item(self)
         | 
| @@ -44,6 +44,14 @@ module Spree | |
| 44 44 | 
             
                  move(variant, quantity, originator)
         | 
| 45 45 | 
             
                end
         | 
| 46 46 |  | 
| 47 | 
            +
                def restock_backordered(variant, quantity, originator = nil)
         | 
| 48 | 
            +
                  item = stock_item_or_create(variant)
         | 
| 49 | 
            +
                  item.update_columns(
         | 
| 50 | 
            +
                    count_on_hand: item.count_on_hand + quantity,
         | 
| 51 | 
            +
                    updated_at: Time.now
         | 
| 52 | 
            +
                  )
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 47 55 | 
             
                def unstock(variant, quantity, originator = nil)
         | 
| 48 56 | 
             
                  move(variant, -quantity, originator)
         | 
| 49 57 | 
             
                end
         | 
| @@ -16,10 +16,12 @@ module Spree | |
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 18 | 
             
                private
         | 
| 19 | 
            +
             | 
| 19 20 | 
             
                def update_stock_item_quantity
         | 
| 20 | 
            -
                  return unless  | 
| 21 | 
            +
                  return unless self.stock_item.should_track_inventory?
         | 
| 21 22 | 
             
                  stock_item.adjust_count_on_hand quantity
         | 
| 22 23 | 
             
                end
         | 
| 24 | 
            +
             | 
| 23 25 | 
             
              end
         | 
| 24 26 | 
             
            end
         | 
| 25 27 |  | 
    
        data/app/models/spree/taxon.rb
    CHANGED
    
    | @@ -16,7 +16,7 @@ module Spree | |
| 16 16 | 
             
                  url: '/spree/taxons/:id/:style/:basename.:extension',
         | 
| 17 17 | 
             
                  path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
         | 
| 18 18 | 
             
                  default_url: '/assets/default_taxon.png'
         | 
| 19 | 
            -
             | 
| 19 | 
            +
             | 
| 20 20 | 
             
                include Spree::Core::S3Support
         | 
| 21 21 | 
             
                supports_s3 :icon
         | 
| 22 22 |  | 
| @@ -76,7 +76,7 @@ module Spree | |
| 76 76 | 
             
                #
         | 
| 77 77 | 
             
                #  See #3390 for background.
         | 
| 78 78 | 
             
                def child_index=(idx)
         | 
| 79 | 
            -
                  move_to_child_with_index(parent, idx.to_i)
         | 
| 79 | 
            +
                  move_to_child_with_index(parent, idx.to_i) unless self.new_record?
         | 
| 80 80 | 
             
                end
         | 
| 81 81 | 
             
              end
         | 
| 82 82 | 
             
            end
         | 
    
        data/app/models/spree/variant.rb
    CHANGED
    
    | @@ -23,7 +23,7 @@ module Spree | |
| 23 23 | 
             
                  class_name: 'Spree::Price',
         | 
| 24 24 | 
             
                  dependent: :destroy
         | 
| 25 25 |  | 
| 26 | 
            -
                delegate_belongs_to :default_price, :display_price, :display_amount, :price, :price=, :currency | 
| 26 | 
            +
                delegate_belongs_to :default_price, :display_price, :display_amount, :price, :price=, :currency
         | 
| 27 27 |  | 
| 28 28 | 
             
                has_many :prices,
         | 
| 29 29 | 
             
                  class_name: 'Spree::Price',
         | 
| @@ -40,7 +40,7 @@ module Spree | |
| 40 40 | 
             
                after_create :set_position
         | 
| 41 41 |  | 
| 42 42 | 
             
                # default variant scope only lists non-deleted variants
         | 
| 43 | 
            -
                scope :deleted, lambda { where( | 
| 43 | 
            +
                scope :deleted, lambda { where.not(deleted_at: nil) }
         | 
| 44 44 |  | 
| 45 45 | 
             
                def self.active(currency = nil)
         | 
| 46 46 | 
             
                  joins(:prices).where(deleted_at: nil).where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
         | 
| @@ -76,6 +76,12 @@ module Spree | |
| 76 76 | 
             
                  deleted_at
         | 
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 | 
            +
                def options=(options = {})
         | 
| 80 | 
            +
                  options.each do |option|
         | 
| 81 | 
            +
                    set_option_value(option[:name], option[:value])
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 79 85 | 
             
                def set_option_value(opt_name, opt_value)
         | 
| 80 86 | 
             
                  # no option values on master
         | 
| 81 87 | 
             
                  return if self.is_master
         | 
| @@ -94,7 +100,6 @@ module Spree | |
| 94 100 | 
             
                    # then we have to check to make sure that the product has the option type
         | 
| 95 101 | 
             
                    unless self.product.option_types.include? option_type
         | 
| 96 102 | 
             
                      self.product.option_types << option_type
         | 
| 97 | 
            -
                      self.product.save
         | 
| 98 103 | 
             
                    end
         | 
| 99 104 | 
             
                  end
         | 
| 100 105 |  | 
| @@ -127,13 +132,17 @@ module Spree | |
| 127 132 | 
             
                  "#{name} - #{sku}"
         | 
| 128 133 | 
             
                end
         | 
| 129 134 |  | 
| 135 | 
            +
                def sku_and_options_text
         | 
| 136 | 
            +
                  "#{sku} #{options_text}".strip
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 130 139 | 
             
                # Product may be created with deleted_at already set,
         | 
| 131 140 | 
             
                # which would make AR's default finder return nil.
         | 
| 132 141 | 
             
                # This is a stopgap for that little problem.
         | 
| 133 142 | 
             
                def product
         | 
| 134 143 | 
             
                  Spree::Product.unscoped { super }
         | 
| 135 144 | 
             
                end
         | 
| 136 | 
            -
             | 
| 145 | 
            +
             | 
| 137 146 | 
             
                def in_stock?(quantity=1)
         | 
| 138 147 | 
             
                  Spree::Stock::Quantifier.new(self).can_supply?(quantity)
         | 
| 139 148 | 
             
                end
         | 
| @@ -142,6 +151,12 @@ module Spree | |
| 142 151 | 
             
                  Spree::Stock::Quantifier.new(self).total_on_hand
         | 
| 143 152 | 
             
                end
         | 
| 144 153 |  | 
| 154 | 
            +
                # Shortcut method to determine if inventory tracking is enabled for this variant
         | 
| 155 | 
            +
                # This considers both variant tracking flag and site-wide inventory tracking settings
         | 
| 156 | 
            +
                def should_track_inventory?
         | 
| 157 | 
            +
                  self.track_inventory? && Spree::Config.track_inventory_levels
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 145 160 | 
             
                private
         | 
| 146 161 | 
             
                  # strips all non-price-like characters from the price, taking into account locale settings
         | 
| 147 162 | 
             
                  def parse_price(price)
         |