spree_core 2.0.3 → 2.0.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/assets/images/logo/spree_50.png +0 -0
- data/app/assets/images/noimage/large.png +0 -0
- data/app/assets/images/noimage/mini.png +0 -0
- data/app/assets/images/noimage/product.png +0 -0
- data/app/assets/images/noimage/small.png +0 -0
- data/app/controllers/spree/base_controller.rb +3 -0
- data/app/helpers/spree/base_helper.rb +15 -11
- data/app/models/spree/adjustment.rb +5 -0
- data/app/models/spree/app_configuration.rb +3 -3
- data/app/models/spree/calculator/default_tax.rb +2 -2
- data/app/models/spree/calculator/percent_per_item.rb +9 -5
- data/app/models/spree/calculator.rb +1 -1
- data/app/models/spree/credit_card.rb +25 -0
- data/app/models/spree/line_item.rb +9 -0
- data/app/models/spree/new_adjustment.rb +4 -0
- data/app/models/spree/order/checkout.rb +4 -5
- data/app/models/spree/order.rb +52 -25
- data/app/models/spree/order_contents.rb +8 -7
- data/app/models/spree/order_inventory.rb +13 -13
- data/app/models/spree/order_populator.rb +4 -14
- data/app/models/spree/order_updater.rb +1 -1
- data/app/models/spree/payment/processing.rb +5 -0
- data/app/models/spree/payment.rb +12 -1
- data/app/models/spree/payment_method.rb +1 -4
- data/app/models/spree/product.rb +44 -17
- data/app/models/spree/promotion/actions/create_adjustment.rb +1 -1
- data/app/models/spree/promotion/actions/create_line_items.rb +32 -2
- data/app/models/spree/promotion.rb +2 -1
- data/app/models/spree/shipment.rb +5 -5
- data/app/models/spree/shipping_adjustment.rb +4 -0
- data/app/models/spree/shipping_method.rb +6 -0
- data/app/models/spree/shipping_rate.rb +1 -0
- data/app/models/spree/stock/availability_validator.rb +5 -3
- data/app/models/spree/stock/coordinator.rb +16 -4
- data/app/models/spree/stock/estimator.rb +16 -6
- data/app/models/spree/stock/packer.rb +2 -1
- data/app/models/spree/stock_location.rb +16 -6
- data/app/models/spree/tax_category.rb +1 -7
- data/app/models/spree/tax_rate.rb +1 -0
- data/app/models/spree/variant.rb +16 -3
- data/app/models/spree/zone.rb +1 -1
- data/config/initializers/user_class_extensions.rb +1 -1
- data/config/locales/en.yml +15 -1
- data/db/migrate/20130228210442_create_shipping_method_zone.rb +6 -1
- data/db/migrate/20130306181701_add_address_fields_to_stock_location.rb +4 -1
- data/db/migrate/20130515180736_add_backorderable_default_to_spree_stock_location.rb +5 -0
- data/db/migrate/20130516151222_add_propage_all_variants_to_spree_stock_location.rb +5 -0
- data/db/migrate/20130626232741_add_cvv_result_code_and_cvv_result_message_to_spree_payments.rb +6 -0
- data/db/migrate/20130628021056_add_unique_index_to_permalink_on_spree_products.rb +5 -0
- data/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +7 -0
- data/db/migrate/20130708052307_add_deleted_at_to_spree_tax_rates.rb +5 -0
- data/db/migrate/20130711200933_remove_lock_version_from_inventory_units.rb +6 -0
- data/db/migrate/20130718042445_add_cost_price_to_line_item.rb +5 -0
- data/db/migrate/20130718233855_set_backorderable_to_default_to_false.rb +6 -0
- data/db/migrate/20130725031716_add_created_by_id_to_spree_orders.rb +5 -0
- data/db/migrate/20130729214043_index_completed_at_on_spree_orders.rb +5 -0
- data/db/migrate/20130802014537_add_tax_category_id_to_spree_line_items.rb +5 -0
- data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +9 -0
- data/db/migrate/20130805043440_create_spree_new_adjustments.rb +8 -0
- data/lib/generators/spree/dummy/templates/rails/database.yml +8 -7
- data/lib/generators/spree/install/install_generator.rb +1 -1
- data/lib/spree/core/calculated_adjustments.rb +12 -1
- data/lib/spree/core/controller_helpers/order.rb +5 -3
- data/lib/spree/core/controller_helpers/search.rb +14 -0
- data/lib/spree/core/permalinks.rb +13 -13
- data/lib/spree/core/s3_support.rb +1 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +7 -5
- data/lib/spree/i18n/base.rb +17 -0
- data/lib/spree/i18n/initializer.rb +1 -0
- data/lib/spree/i18n.rb +28 -7
- data/lib/spree/money.rb +2 -0
- data/lib/spree/testing_support/authorization_helpers.rb +6 -15
- data/lib/spree/testing_support/capybara_ext.rb +20 -11
- data/lib/spree/testing_support/common_rake.rb +13 -0
- data/lib/spree/testing_support/factories/country_factory.rb +1 -1
- data/lib/spree/testing_support/factories/order_factory.rb +0 -2
- data/lib/spree/testing_support/factories/payment_method_factory.rb +1 -1
- data/lib/spree/testing_support/factories/product_factory.rb +8 -18
- data/lib/spree/testing_support/factories/return_authorization_factory.rb +4 -0
- data/lib/spree/testing_support/factories/shipment_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_item_factory.rb +2 -1
- data/lib/spree/testing_support/factories/stock_location_factory.rb +5 -2
- data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +14 -1
- data/vendor/assets/javascripts/jquery.validate/localization/messages_et.js +23 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_eu.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_hr.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_ka.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_ko.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_my.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_pt_BR.js +26 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_pt_PT.js +26 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_sl.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_sv.js +23 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_uk.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_zh.js +25 -0
- data/vendor/assets/javascripts/jquery.validate/localization/messages_zh_TW.js +26 -0
- metadata +118 -67
data/app/models/spree/product.rb
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
module Spree
|
|
22
22
|
class Product < ActiveRecord::Base
|
|
23
|
+
acts_as_paranoid
|
|
23
24
|
has_many :product_option_types, dependent: :destroy
|
|
24
25
|
has_many :option_types, through: :product_option_types
|
|
25
26
|
has_many :product_properties, dependent: :destroy
|
|
@@ -44,12 +45,11 @@ module Spree
|
|
|
44
45
|
|
|
45
46
|
has_many :variants_including_master,
|
|
46
47
|
class_name: 'Spree::Variant',
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
has_many :variants_including_master_and_deleted, class_name: 'Spree::Variant'
|
|
48
|
+
dependent: :destroy,
|
|
49
|
+
order: "#{::Spree::Variant.quoted_table_name}.position ASC"
|
|
51
50
|
|
|
52
51
|
has_many :prices, through: :variants, order: 'spree_variants.position, spree_variants.id, currency'
|
|
52
|
+
has_many :stock_items, through: :variants
|
|
53
53
|
|
|
54
54
|
delegate_belongs_to :master, :sku, :price, :currency, :display_amount, :display_price, :weight, :height, :width, :depth, :is_master, :has_default_price?, :cost_currency, :price_in, :amount_in
|
|
55
55
|
delegate_belongs_to :master, :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
|
|
@@ -66,16 +66,35 @@ module Spree
|
|
|
66
66
|
|
|
67
67
|
accepts_nested_attributes_for :variants, allow_destroy: true
|
|
68
68
|
|
|
69
|
-
validates :name,
|
|
69
|
+
validates :name, presence: true
|
|
70
|
+
validates :permalink, presence: true
|
|
70
71
|
validates :price, presence: true, if: proc { Spree::Config[:require_master_price] }
|
|
72
|
+
validates :shipping_category_id, presence: true
|
|
71
73
|
|
|
72
74
|
attr_accessor :option_values_hash
|
|
73
75
|
|
|
74
|
-
attr_accessible :
|
|
75
|
-
:
|
|
76
|
-
:
|
|
77
|
-
:
|
|
78
|
-
:
|
|
76
|
+
attr_accessible :available_on,
|
|
77
|
+
:cost_currency,
|
|
78
|
+
:deleted_at,
|
|
79
|
+
:depth,
|
|
80
|
+
:description,
|
|
81
|
+
:height,
|
|
82
|
+
:meta_description,
|
|
83
|
+
:meta_keywords,
|
|
84
|
+
:name,
|
|
85
|
+
:option_type_ids,
|
|
86
|
+
:option_values_hash,
|
|
87
|
+
:permalink,
|
|
88
|
+
:price,
|
|
89
|
+
:product_properties_attributes,
|
|
90
|
+
:prototype_id,
|
|
91
|
+
:shipping_category_id,
|
|
92
|
+
:sku,
|
|
93
|
+
:tax_category_id,
|
|
94
|
+
:taxon_ids,
|
|
95
|
+
:weight,
|
|
96
|
+
:width,
|
|
97
|
+
:variants_attributes
|
|
79
98
|
|
|
80
99
|
attr_accessible :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
|
|
81
100
|
|
|
@@ -109,13 +128,6 @@ module Spree
|
|
|
109
128
|
end
|
|
110
129
|
end
|
|
111
130
|
|
|
112
|
-
# override the delete method to set deleted_at value
|
|
113
|
-
# instead of actually deleting the product.
|
|
114
|
-
def delete
|
|
115
|
-
self.update_column(:deleted_at, Time.now)
|
|
116
|
-
variants_including_master.update_all(deleted_at: Time.now)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
131
|
# Adding properties and option types on creation based on a chosen prototype
|
|
120
132
|
attr_reader :prototype_id
|
|
121
133
|
def prototype_id=(value)
|
|
@@ -197,6 +209,21 @@ module Spree
|
|
|
197
209
|
Spree::Promotion.advertised.where(id: promotion_ids).reject(&:expired?)
|
|
198
210
|
end
|
|
199
211
|
|
|
212
|
+
def total_on_hand
|
|
213
|
+
if Spree::Config.track_inventory_levels
|
|
214
|
+
self.stock_items.sum(&:count_on_hand)
|
|
215
|
+
else
|
|
216
|
+
Float::INFINITY
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Master variant may be deleted (i.e. when the product is deleted)
|
|
221
|
+
# which would make AR's default finder return nil.
|
|
222
|
+
# This is a stopgap for that little problem.
|
|
223
|
+
def master
|
|
224
|
+
super || variants_including_master.with_deleted.where(:is_master => true).first
|
|
225
|
+
end
|
|
226
|
+
|
|
200
227
|
private
|
|
201
228
|
|
|
202
229
|
# Builds variants from a hash of option types & values
|
|
@@ -17,7 +17,7 @@ module Spree
|
|
|
17
17
|
# through options hash
|
|
18
18
|
def perform(options = {})
|
|
19
19
|
order = options[:order]
|
|
20
|
-
return if order.promotion_credit_exists?(self
|
|
20
|
+
return if order.promotion_credit_exists?(self)
|
|
21
21
|
|
|
22
22
|
self.create_adjustment("#{Spree.t(:promotion)} (#{promotion.name})", order, order)
|
|
23
23
|
end
|
|
@@ -6,14 +6,44 @@ module Spree
|
|
|
6
6
|
accepts_nested_attributes_for :promotion_action_line_items
|
|
7
7
|
attr_accessible :promotion_action_line_items_attributes
|
|
8
8
|
|
|
9
|
+
delegate :eligible?, :to => :promotion
|
|
9
10
|
|
|
11
|
+
# Adds a line item to the Order if the promotion is eligible
|
|
12
|
+
#
|
|
13
|
+
# This doesn't play right with Add to Cart events because at the moment
|
|
14
|
+
# the item was added to cart the promo may not be eligible. However it
|
|
15
|
+
# might become eligible as the order gets updated.
|
|
16
|
+
#
|
|
17
|
+
# e.g.
|
|
18
|
+
# - A promo adds a line item to cart if order total greater then $30
|
|
19
|
+
# - Customer add 1 item of $10 to cart
|
|
20
|
+
# - This action shouldn't perform because the order is not eligible
|
|
21
|
+
# - Customer increases item quantity to 5 (order total goes to $50)
|
|
22
|
+
# - Now the order is eligible for the promo and the action should perform
|
|
23
|
+
#
|
|
24
|
+
# Another complication is when the same line item created by the promo
|
|
25
|
+
# is also added to cart on a separate action.
|
|
26
|
+
#
|
|
27
|
+
# e.g.
|
|
28
|
+
# - Promo adds 1 item A to cart if order total greater then $30
|
|
29
|
+
# - Customer add 2 items B to cart, current order total is $40
|
|
30
|
+
# - This action performs adding item A to cart since order is eligible
|
|
31
|
+
# - Customer changes his mind and updates item B quantity to 1
|
|
32
|
+
# - At this point order is no longer eligible and one might expect
|
|
33
|
+
# that item A should be removed
|
|
34
|
+
#
|
|
35
|
+
# It doesn't remove items from the order here because there's no way
|
|
36
|
+
# it can know whether that item was added via this promo action or if
|
|
37
|
+
# it was manually populated somewhere else. In that case the item
|
|
38
|
+
# needs to be manually removed from the order by the customer
|
|
10
39
|
def perform(options = {})
|
|
11
|
-
|
|
40
|
+
order = options[:order]
|
|
41
|
+
return unless self.eligible? order
|
|
42
|
+
|
|
12
43
|
promotion_action_line_items.each do |item|
|
|
13
44
|
current_quantity = order.quantity_of(item.variant)
|
|
14
45
|
if current_quantity < item.quantity
|
|
15
46
|
order.contents.add(item.variant, item.quantity - current_quantity)
|
|
16
|
-
order.update!
|
|
17
47
|
end
|
|
18
48
|
end
|
|
19
49
|
end
|
|
@@ -44,9 +44,10 @@ module Spree
|
|
|
44
44
|
def activate(payload)
|
|
45
45
|
return unless order_activatable? payload[:order]
|
|
46
46
|
|
|
47
|
+
# make sure code is always downcased (old databases might have mixed case codes)
|
|
47
48
|
if code.present?
|
|
48
49
|
event_code = payload[:coupon_code]
|
|
49
|
-
return unless event_code == self.code
|
|
50
|
+
return unless event_code == self.code.downcase.strip
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
if path.present?
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
|
6
6
|
belongs_to :address, class_name: 'Spree::Address'
|
|
7
7
|
belongs_to :stock_location, class_name: 'Spree::StockLocation'
|
|
8
8
|
|
|
9
|
-
has_many :shipping_rates
|
|
9
|
+
has_many :shipping_rates, dependent: :destroy
|
|
10
10
|
has_many :shipping_methods, through: :shipping_rates
|
|
11
11
|
has_many :state_changes, as: :stateful
|
|
12
12
|
has_many :inventory_units, dependent: :destroy
|
|
@@ -16,7 +16,7 @@ module Spree
|
|
|
16
16
|
after_save :ensure_correct_adjustment, :update_order
|
|
17
17
|
|
|
18
18
|
attr_accessor :special_instructions
|
|
19
|
-
attr_accessible :order, :special_instructions, :stock_location_id,
|
|
19
|
+
attr_accessible :order, :special_instructions, :stock_location_id, :number,
|
|
20
20
|
:tracking, :address, :inventory_units, :selected_shipping_rate_id
|
|
21
21
|
|
|
22
22
|
accepts_nested_attributes_for :address
|
|
@@ -158,7 +158,7 @@ module Spree
|
|
|
158
158
|
end
|
|
159
159
|
|
|
160
160
|
def manifest
|
|
161
|
-
inventory_units.group_by(&:variant).map do |variant, units|
|
|
161
|
+
inventory_units.includes(:variant).group_by(&:variant).map do |variant, units|
|
|
162
162
|
states = {}
|
|
163
163
|
units.group_by(&:state).each { |state, iu| states[state] = iu.count }
|
|
164
164
|
OpenStruct.new(variant: variant, quantity: units.length, states: states)
|
|
@@ -223,8 +223,8 @@ module Spree
|
|
|
223
223
|
|
|
224
224
|
def to_package
|
|
225
225
|
package = Stock::Package.new(stock_location, order)
|
|
226
|
-
inventory_units.each do |inventory_unit|
|
|
227
|
-
package.add inventory_unit.variant, 1, inventory_unit.
|
|
226
|
+
inventory_units.includes(:variant).each do |inventory_unit|
|
|
227
|
+
package.add inventory_unit.variant, 1, inventory_unit.state_name
|
|
228
228
|
end
|
|
229
229
|
package
|
|
230
230
|
end
|
|
@@ -8,6 +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
12
|
|
|
12
13
|
has_and_belongs_to_many :zones, :join_table => 'spree_shipping_methods_zones',
|
|
13
14
|
:class_name => 'Spree::Zone',
|
|
@@ -49,6 +50,11 @@ module Spree
|
|
|
49
50
|
spree_calculators.send(model_name_without_spree_namespace).select{|c| c.name.start_with?("Spree::Calculator::Shipping::")}
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
# Some shipping methods are only meant to be set via backend
|
|
54
|
+
def frontend?
|
|
55
|
+
self.display_on != "back_end"
|
|
56
|
+
end
|
|
57
|
+
|
|
52
58
|
private
|
|
53
59
|
def at_least_one_shipping_category
|
|
54
60
|
if self.shipping_categories.empty?
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module Stock
|
|
3
3
|
class AvailabilityValidator < ActiveModel::Validator
|
|
4
|
-
|
|
5
4
|
def validate(line_item)
|
|
6
5
|
quantifier = Stock::Quantifier.new(line_item.variant_id)
|
|
7
6
|
|
|
8
7
|
unless quantifier.can_supply? line_item.quantity
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
variant = line_item.variant
|
|
9
|
+
display_name = %Q{#{variant.name}}
|
|
10
|
+
display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank?
|
|
11
11
|
|
|
12
|
+
line_item.errors[:quantity] << Spree.t(:out_of_stock, :scope => :order_populator, :item => display_name.inspect)
|
|
13
|
+
end
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
end
|
|
@@ -8,21 +8,33 @@ module Spree
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def packages
|
|
11
|
-
packages =
|
|
12
|
-
packages = build_packages(packages)
|
|
11
|
+
packages = build_packages
|
|
13
12
|
packages = prioritize_packages(packages)
|
|
14
13
|
packages = estimate_packages(packages)
|
|
15
14
|
end
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
# Build packages as per stock location
|
|
17
|
+
#
|
|
18
|
+
# It needs to check whether each stock location holds at least one stock
|
|
19
|
+
# item for the order. In case none is found it wouldn't make any sense
|
|
20
|
+
# to build a package because it would be empty. Plus we avoid errors down
|
|
21
|
+
# the stack because it would assume the stock location has stock items
|
|
22
|
+
# for the given order
|
|
23
|
+
#
|
|
24
|
+
# Returns an array of Package instances
|
|
25
|
+
def build_packages(packages = Array.new)
|
|
19
26
|
StockLocation.active.each do |stock_location|
|
|
27
|
+
next unless order.line_items.any? do |item|
|
|
28
|
+
stock_location.stock_item(item.variant)
|
|
29
|
+
end
|
|
30
|
+
|
|
20
31
|
packer = build_packer(stock_location, order)
|
|
21
32
|
packages += packer.packages
|
|
22
33
|
end
|
|
23
34
|
packages
|
|
24
35
|
end
|
|
25
36
|
|
|
37
|
+
private
|
|
26
38
|
def prioritize_packages(packages)
|
|
27
39
|
prioritizer = Prioritizer.new(order, packages)
|
|
28
40
|
prioritizer.prioritized_packages
|
|
@@ -8,25 +8,35 @@ module Spree
|
|
|
8
8
|
@currency = order.currency
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def shipping_rates(package)
|
|
11
|
+
def shipping_rates(package, frontend_only = true)
|
|
12
12
|
shipping_rates = Array.new
|
|
13
13
|
shipping_methods = shipping_methods(package)
|
|
14
14
|
return [] unless shipping_methods
|
|
15
|
+
|
|
15
16
|
shipping_methods.each do |shipping_method|
|
|
16
17
|
cost = calculate_cost(shipping_method, package)
|
|
17
|
-
|
|
18
|
-
shipping_rates << ShippingRate.new( :shipping_method => shipping_method,
|
|
19
|
-
:cost => cost)
|
|
18
|
+
shipping_rates << shipping_method.shipping_rates.new(:cost => cost)
|
|
20
19
|
end
|
|
20
|
+
|
|
21
21
|
shipping_rates.sort_by! { |r| r.cost || 0 }
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
unless shipping_rates.empty?
|
|
24
|
+
if frontend_only
|
|
25
|
+
shipping_rates.each do |rate|
|
|
26
|
+
rate.selected = true and break if rate.shipping_method.frontend?
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
shipping_rates.first.selected = true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
23
33
|
shipping_rates
|
|
24
34
|
end
|
|
25
35
|
|
|
26
36
|
private
|
|
27
37
|
def shipping_methods(package)
|
|
28
38
|
shipping_methods = package.shipping_methods
|
|
29
|
-
shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package
|
|
39
|
+
shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package) }
|
|
30
40
|
shipping_methods.delete_if { |ship_method| !ship_method.include?(order.ship_address) }
|
|
31
41
|
shipping_methods.delete_if { |ship_method| !(ship_method.calculator.preferences[:currency].nil? || ship_method.calculator.preferences[:currency] == currency) }
|
|
32
42
|
shipping_methods
|
|
@@ -16,6 +16,8 @@ module Spree
|
|
|
16
16
|
def default_package
|
|
17
17
|
package = Package.new(stock_location, order)
|
|
18
18
|
order.line_items.each do |line_item|
|
|
19
|
+
next unless stock_location.stock_item(line_item.variant)
|
|
20
|
+
|
|
19
21
|
on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity)
|
|
20
22
|
package.add line_item.variant, on_hand, :on_hand if on_hand > 0
|
|
21
23
|
package.add line_item.variant, backordered, :backordered if backordered > 0
|
|
@@ -34,4 +36,3 @@ module Spree
|
|
|
34
36
|
end
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
|
-
|
|
@@ -9,11 +9,24 @@ module Spree
|
|
|
9
9
|
validates_presence_of :name
|
|
10
10
|
|
|
11
11
|
attr_accessible :name, :active, :address1, :address2, :city, :zipcode,
|
|
12
|
-
|
|
12
|
+
:backorderable_default, :state_name, :state_id, :country_id, :phone,
|
|
13
|
+
:country_id, :propagate_all_variants
|
|
13
14
|
|
|
14
15
|
scope :active, -> { where(active: true) }
|
|
15
16
|
|
|
16
|
-
after_create :create_stock_items
|
|
17
|
+
after_create :create_stock_items, :if => "self.propagate_all_variants?"
|
|
18
|
+
|
|
19
|
+
# Wrapper for creating a new stock item respecting the backorderable config
|
|
20
|
+
def propagate_variant(variant)
|
|
21
|
+
self.stock_items.create!(variant: variant, backorderable: self.backorderable_default)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Return either an existing stock item or create a new one. Useful in
|
|
25
|
+
# scenarios where the user might not know whether there is already a stock
|
|
26
|
+
# item for a given variant
|
|
27
|
+
def set_up_stock_item(variant)
|
|
28
|
+
self.stock_item(variant) || propagate_variant(variant)
|
|
29
|
+
end
|
|
17
30
|
|
|
18
31
|
def stock_item(variant)
|
|
19
32
|
stock_items.where(variant_id: variant).order(:id).first
|
|
@@ -63,11 +76,8 @@ module Spree
|
|
|
63
76
|
end
|
|
64
77
|
|
|
65
78
|
private
|
|
66
|
-
|
|
67
79
|
def create_stock_items
|
|
68
|
-
|
|
69
|
-
self.stock_items.create!(variant: v)
|
|
70
|
-
end
|
|
80
|
+
Variant.find_each { |variant| self.propagate_variant(variant) }
|
|
71
81
|
end
|
|
72
82
|
end
|
|
73
83
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class TaxCategory < ActiveRecord::Base
|
|
3
|
+
acts_as_paranoid
|
|
3
4
|
validates :name, presence: true, uniqueness: { scope: :deleted_at }
|
|
4
5
|
|
|
5
6
|
has_many :tax_rates, dependent: :destroy
|
|
@@ -8,8 +9,6 @@ module Spree
|
|
|
8
9
|
|
|
9
10
|
before_save :set_default_category
|
|
10
11
|
|
|
11
|
-
default_scope where(deleted_at: nil)
|
|
12
|
-
|
|
13
12
|
def set_default_category
|
|
14
13
|
#set existing default tax category to false if this one has been marked as default
|
|
15
14
|
|
|
@@ -17,10 +16,5 @@ module Spree
|
|
|
17
16
|
tax_category.update_column(:is_default, false) unless tax_category == self
|
|
18
17
|
end
|
|
19
18
|
end
|
|
20
|
-
|
|
21
|
-
def mark_deleted!
|
|
22
|
-
self.deleted_at = Time.now
|
|
23
|
-
save
|
|
24
|
-
end
|
|
25
19
|
end
|
|
26
20
|
end
|
data/app/models/spree/variant.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Variant < ActiveRecord::Base
|
|
3
|
+
acts_as_paranoid
|
|
4
|
+
|
|
3
5
|
belongs_to :product, touch: true, class_name: 'Spree::Product'
|
|
4
6
|
|
|
5
7
|
delegate_belongs_to :product, :name, :description, :permalink, :available_on,
|
|
@@ -14,7 +16,7 @@ module Spree
|
|
|
14
16
|
has_many :inventory_units
|
|
15
17
|
has_many :line_items
|
|
16
18
|
|
|
17
|
-
has_many :stock_items, dependent: :destroy
|
|
19
|
+
has_many :stock_items, dependent: :destroy, :order => "id ASC"
|
|
18
20
|
has_many :stock_locations, through: :stock_items
|
|
19
21
|
has_many :stock_movements
|
|
20
22
|
|
|
@@ -133,6 +135,17 @@ module Spree
|
|
|
133
135
|
Spree::Stock::Quantifier.new(self).can_supply?(quantity)
|
|
134
136
|
end
|
|
135
137
|
|
|
138
|
+
def total_on_hand
|
|
139
|
+
Spree::Stock::Quantifier.new(self).total_on_hand
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Product may be created with deleted_at already set,
|
|
143
|
+
# which would make AR's default finder return nil.
|
|
144
|
+
# This is a stopgap for that little problem.
|
|
145
|
+
def product
|
|
146
|
+
Spree::Product.unscoped { super }
|
|
147
|
+
end
|
|
148
|
+
|
|
136
149
|
private
|
|
137
150
|
# strips all non-price-like characters from the price, taking into account locale settings
|
|
138
151
|
def parse_price(price)
|
|
@@ -167,8 +180,8 @@ module Spree
|
|
|
167
180
|
end
|
|
168
181
|
|
|
169
182
|
def create_stock_items
|
|
170
|
-
|
|
171
|
-
stock_location.
|
|
183
|
+
StockLocation.all.each do |stock_location|
|
|
184
|
+
stock_location.propagate_variant(self) if stock_location.propagate_all_variants?
|
|
172
185
|
end
|
|
173
186
|
end
|
|
174
187
|
|
data/app/models/spree/zone.rb
CHANGED
data/config/locales/en.yml
CHANGED
|
@@ -193,6 +193,12 @@ en:
|
|
|
193
193
|
spree/zone:
|
|
194
194
|
one: Zone
|
|
195
195
|
other: Zones
|
|
196
|
+
errors:
|
|
197
|
+
models:
|
|
198
|
+
spree/credit_card:
|
|
199
|
+
attributes:
|
|
200
|
+
base:
|
|
201
|
+
card_expired: "Card has expired"
|
|
196
202
|
devise:
|
|
197
203
|
confirmations:
|
|
198
204
|
confirmed: Your account was successfully confirmed. You are now signed in.
|
|
@@ -295,6 +301,7 @@ en:
|
|
|
295
301
|
reports: "Reports"
|
|
296
302
|
configuration: "Configuration"
|
|
297
303
|
promotions: "Promotions"
|
|
304
|
+
users: "Users"
|
|
298
305
|
administration: Administration
|
|
299
306
|
agree_to_privacy_policy: Agree to Privacy Policy
|
|
300
307
|
agree_to_terms_of_service: Agree to Terms of Service
|
|
@@ -343,7 +350,7 @@ en:
|
|
|
343
350
|
back_to_shipping_categories: Back To Shipping Categories
|
|
344
351
|
back_to_shipping_methods_list: Back To Shipping Methods List
|
|
345
352
|
back_to_states_list: Back To States List
|
|
346
|
-
back_to_stock_locations_list: Back to Stock
|
|
353
|
+
back_to_stock_locations_list: Back to Stock Locations List
|
|
347
354
|
back_to_stock_movements_list: Back to Stock Movements List
|
|
348
355
|
back_to_stock_transfers_list: Back to Stock Transfers List
|
|
349
356
|
back_to_store: Go Back To Store
|
|
@@ -583,6 +590,7 @@ en:
|
|
|
583
590
|
operators:
|
|
584
591
|
gt: greater than
|
|
585
592
|
gte: greater than or equal to
|
|
593
|
+
items_cannot_be_shipped: We are unable to ship the selected items to your shipping address. Please choose another shipping address.
|
|
586
594
|
jirafe: Jirafe
|
|
587
595
|
landing_page_rule:
|
|
588
596
|
path: Path
|
|
@@ -661,12 +669,14 @@ en:
|
|
|
661
669
|
no_actions_added: No actions added
|
|
662
670
|
no_orders_found: No orders found
|
|
663
671
|
no_payment_methods_found: No payment methods found
|
|
672
|
+
no_pending_payments: No pending payments
|
|
664
673
|
no_products_found: No products found
|
|
665
674
|
no_promotions_found: No promotions found
|
|
666
675
|
no_results: No results
|
|
667
676
|
no_rules_added: No rules added
|
|
668
677
|
no_shipping_methods_found: No shipping methods found
|
|
669
678
|
no_trackers_found: No Trackers Found
|
|
679
|
+
no_stock_locations_found: No stock locations found
|
|
670
680
|
no_tracking_present: No tracking details provided.
|
|
671
681
|
none: None
|
|
672
682
|
normal_amount: Normal Amount
|
|
@@ -685,6 +695,7 @@ en:
|
|
|
685
695
|
open: Open
|
|
686
696
|
open_all_adjustments: Open All Adjustments
|
|
687
697
|
option_type: Option Type
|
|
698
|
+
option_type_placeholder: Choose an option type
|
|
688
699
|
option_types: Option Types
|
|
689
700
|
option_value: Option Value
|
|
690
701
|
option_values: Option Values
|
|
@@ -965,6 +976,7 @@ en:
|
|
|
965
976
|
stock_location_info: Stock location info
|
|
966
977
|
stock_locations: Stock Locations
|
|
967
978
|
stock_management: Stock Management
|
|
979
|
+
stock_management_requires_a_stock_location: Please create a stock location in order to manage stock.
|
|
968
980
|
stock_movements: Stock Movements
|
|
969
981
|
stock_movements_for_stock_location: Stock Movements for %{stock_location_name}
|
|
970
982
|
stock_successfully_transferred: Stock was successfully transferred between locations.
|
|
@@ -1004,6 +1016,7 @@ en:
|
|
|
1004
1016
|
subject: Test Mail
|
|
1005
1017
|
test_mode: Test Mode
|
|
1006
1018
|
thank_you_for_your_order: Thank you for your business. Please print out a copy of this confirmation page for your records.
|
|
1019
|
+
there_are_no_items_for_this_order: There are no items for this order. Please add an item to the order to continue.
|
|
1007
1020
|
there_were_problems_with_the_following_fields: There were problems with the following fields
|
|
1008
1021
|
thumbnail: Thumbnail
|
|
1009
1022
|
time: Time
|
|
@@ -1043,6 +1056,7 @@ en:
|
|
|
1043
1056
|
must_be_non_negative: must be a non-negative value
|
|
1044
1057
|
value: Value
|
|
1045
1058
|
variant: Variant
|
|
1059
|
+
variant_placeholder: Choose a variant
|
|
1046
1060
|
variants: Variants
|
|
1047
1061
|
version: Version
|
|
1048
1062
|
void: Void
|
|
@@ -4,7 +4,12 @@ class CreateShippingMethodZone < ActiveRecord::Migration
|
|
|
4
4
|
t.integer :shipping_method_id
|
|
5
5
|
t.integer :zone_id
|
|
6
6
|
end
|
|
7
|
-
|
|
7
|
+
# This association has been corrected in a latter migration
|
|
8
|
+
# but when this database migration runs, the table is still incorrectly named
|
|
9
|
+
# 'shipping_methods_zones' instead of 'spre_shipping_methods_zones'
|
|
10
|
+
Spree::ShippingMethod.has_and_belongs_to_many :zones, :join_table => 'shipping_methods_zones',
|
|
11
|
+
:class_name => 'Spree::Zone',
|
|
12
|
+
:foreign_key => 'shipping_method_id'
|
|
8
13
|
Spree::ShippingMethod.all.each{|sm| sm.zones << Spree::Zone.find(sm.zone_id)}
|
|
9
14
|
|
|
10
15
|
remove_column :spree_shipping_methods, :zone_id
|
|
@@ -13,7 +13,10 @@ class AddAddressFieldsToStockLocation < ActiveRecord::Migration
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
usa = Spree::Country.where(:iso => 'US').first
|
|
16
|
+
# In case USA isn't found.
|
|
17
|
+
# See #3115
|
|
18
|
+
country = usa || Spree::Country.first
|
|
16
19
|
Spree::Country.reset_column_information
|
|
17
|
-
Spree::StockLocation.update_all(:country_id =>
|
|
20
|
+
Spree::StockLocation.update_all(:country_id => country)
|
|
18
21
|
end
|
|
19
22
|
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration
|
|
2
|
+
def add
|
|
3
|
+
add_index "spree_orders", ["number"], :name => "number_idx_unique", :unique => true
|
|
4
|
+
add_index "spree_shipments", ["number"], :name => "number_idx_unique", :unique => true
|
|
5
|
+
add_index "spree_stock_transfers", ["number"], :name => "number_idx_unique", :unique => true
|
|
6
|
+
end
|
|
7
|
+
end
|