spree_core 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/friendly_id/slug_decorator.rb +3 -0
- data/app/models/spree/adjustment.rb +1 -1
- data/app/models/spree/calculator.rb +5 -0
- data/app/models/spree/customer_return.rb +22 -16
- data/app/models/spree/gateway/bogus.rb +4 -0
- data/app/models/spree/line_item.rb +1 -1
- data/app/models/spree/order.rb +22 -48
- data/app/models/spree/order/checkout.rb +270 -255
- data/app/models/spree/order_contents.rb +64 -61
- data/app/models/spree/order_merger.rb +65 -0
- data/app/models/spree/payment.rb +5 -0
- data/app/models/spree/payment/processing.rb +2 -1
- data/app/models/spree/payment_method/check.rb +12 -2
- data/app/models/spree/product.rb +5 -0
- data/app/models/spree/promotion_handler/cart.rb +18 -14
- data/app/models/spree/shipment.rb +1 -1
- data/app/models/spree/stock/availability_validator.rb +10 -9
- data/app/models/spree/stock/content_item.rb +8 -0
- data/app/models/spree/stock/package.rb +8 -0
- data/app/models/spree/stock_item.rb +5 -1
- data/app/models/spree/stock_movement.rb +6 -1
- data/app/models/spree/variant.rb +18 -15
- data/app/models/spree/zone.rb +39 -29
- data/app/views/spree/order_mailer/cancel_email.html.erb +1 -1
- data/app/views/spree/order_mailer/cancel_email.text.erb +1 -1
- data/app/views/spree/order_mailer/confirm_email.html.erb +1 -1
- data/app/views/spree/order_mailer/confirm_email.text.erb +1 -1
- data/config/initializers/user_class_extensions.rb +4 -0
- data/config/locales/en.yml +4 -3
- data/db/default/spree/default_reimbursement_type.rb +1 -0
- data/db/migrate/20150515211137_fix_adjustment_order_id.rb +70 -0
- data/db/migrate/20150522181728_add_deleted_at_to_friendly_id_slugs.rb +6 -0
- data/db/migrate/20150609093816_increase_scale_on_pre_tax_amounts.rb +16 -0
- data/db/migrate/20150707204155_enable_acts_as_paranoid_on_calculators.rb +6 -0
- data/lib/spree/core/controller_helpers/auth.rb +1 -1
- data/lib/spree/core/engine.rb +7 -0
- data/lib/spree/core/validators/email.rb +7 -3
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/permitted_attributes.rb +2 -2
- data/lib/spree/testing_support/common_rake.rb +3 -8
- data/lib/spree/testing_support/factories.rb +1 -1
- data/lib/spree/testing_support/factories/order_factory.rb +11 -0
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- metadata +11 -4
data/app/models/spree/variant.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spree
|
2
2
|
class Variant < Spree::Base
|
3
3
|
acts_as_paranoid
|
4
|
-
acts_as_list
|
4
|
+
acts_as_list scope: :product
|
5
5
|
|
6
6
|
include Spree::DefaultPrice
|
7
7
|
|
@@ -37,13 +37,20 @@ module Spree
|
|
37
37
|
validates_uniqueness_of :sku, allow_blank: true, conditions: -> { where(deleted_at: nil) }
|
38
38
|
|
39
39
|
after_create :create_stock_items
|
40
|
-
after_create :set_position
|
41
40
|
after_create :set_master_out_of_stock, unless: :is_master?
|
42
41
|
|
43
42
|
after_touch :clear_in_stock_cache
|
44
43
|
|
45
44
|
scope :in_stock, -> { joins(:stock_items).where('count_on_hand > ? OR track_inventory = ?', 0, false) }
|
46
45
|
|
46
|
+
LOCALIZED_NUMBERS = %w(cost_price weight depth width height)
|
47
|
+
|
48
|
+
LOCALIZED_NUMBERS.each do |m|
|
49
|
+
define_method("#{m}=") do |argument|
|
50
|
+
self[m] = Spree::LocalizedNumber.parse(argument) if argument.present?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
47
54
|
def self.active(currency = nil)
|
48
55
|
joins(:prices).where(deleted_at: nil).where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
|
49
56
|
end
|
@@ -60,14 +67,6 @@ module Spree
|
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
63
|
-
def cost_price=(price)
|
64
|
-
self[:cost_price] = Spree::LocalizedNumber.parse(price) if price.present?
|
65
|
-
end
|
66
|
-
|
67
|
-
def weight=(weight)
|
68
|
-
self[:weight] = Spree::LocalizedNumber.parse(weight) if weight.present?
|
69
|
-
end
|
70
|
-
|
71
70
|
# returns number of units currently on backorder for this variant.
|
72
71
|
def on_backorder
|
73
72
|
inventory_units.with_state('backordered').size
|
@@ -153,7 +152,7 @@ module Spree
|
|
153
152
|
end
|
154
153
|
|
155
154
|
def price_in(currency)
|
156
|
-
prices.
|
155
|
+
prices.detect { |price| price.currency == currency } || Spree::Price.new(variant_id: id, currency: currency)
|
157
156
|
end
|
158
157
|
|
159
158
|
def amount_in(currency)
|
@@ -214,6 +213,14 @@ module Spree
|
|
214
213
|
self.track_inventory? && Spree::Config.track_inventory_levels
|
215
214
|
end
|
216
215
|
|
216
|
+
def volume
|
217
|
+
(width || 0) * (height || 0) * (depth || 0)
|
218
|
+
end
|
219
|
+
|
220
|
+
def dimension
|
221
|
+
(width || 0) + (height || 0) + (depth || 0)
|
222
|
+
end
|
223
|
+
|
217
224
|
private
|
218
225
|
|
219
226
|
def set_master_out_of_stock
|
@@ -245,10 +252,6 @@ module Spree
|
|
245
252
|
end
|
246
253
|
end
|
247
254
|
|
248
|
-
def set_position
|
249
|
-
self.update_column(:position, product.variants.maximum(:position).to_i + 1)
|
250
|
-
end
|
251
|
-
|
252
255
|
def in_stock_cache_key
|
253
256
|
"variant-#{id}-in_stock"
|
254
257
|
end
|
data/app/models/spree/zone.rb
CHANGED
@@ -2,12 +2,10 @@ module Spree
|
|
2
2
|
class Zone < Spree::Base
|
3
3
|
has_many :zone_members, dependent: :destroy, class_name: "Spree::ZoneMember", inverse_of: :zone
|
4
4
|
has_many :tax_rates, dependent: :destroy, inverse_of: :zone
|
5
|
-
has_many :countries, through: :zone_members, source: :zoneable,
|
6
|
-
|
7
|
-
has_many :states, through: :zone_members, source: :zoneable,
|
8
|
-
source_type: "Spree::State"
|
5
|
+
has_many :countries, through: :zone_members, source: :zoneable, source_type: "Spree::Country"
|
6
|
+
has_many :states, through: :zone_members, source: :zoneable, source_type: "Spree::State"
|
9
7
|
|
10
|
-
has_and_belongs_to_many :shipping_methods, :
|
8
|
+
has_and_belongs_to_many :shipping_methods, join_table: 'spree_shipping_methods_zones'
|
11
9
|
|
12
10
|
validates :name, presence: true, uniqueness: { allow_blank: true }
|
13
11
|
|
@@ -47,10 +45,14 @@ module Spree
|
|
47
45
|
# Returns the matching zone with the highest priority zone type (State, Country, Zone.)
|
48
46
|
# Returns nil in the case of no matches.
|
49
47
|
def self.match(address)
|
50
|
-
return unless address
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
return unless address &&
|
49
|
+
matches = includes(:zone_members).
|
50
|
+
order('spree_zones.zone_members_count', 'spree_zones.created_at').
|
51
|
+
where("(spree_zone_members.zoneable_type = 'Spree::Country' AND " +
|
52
|
+
"spree_zone_members.zoneable_id = ?) OR " +
|
53
|
+
"(spree_zone_members.zoneable_type = 'Spree::State' AND " +
|
54
|
+
"spree_zone_members.zoneable_id = ?)", address.country_id, address.state_id).
|
55
|
+
references(:zones)
|
54
56
|
|
55
57
|
['state', 'country'].each do |zone_kind|
|
56
58
|
if match = matches.detect { |zone| zone_kind == zone.kind }
|
@@ -96,9 +98,12 @@ module Spree
|
|
96
98
|
# convenience method for returning the countries contained within a zone
|
97
99
|
def country_list
|
98
100
|
@countries ||= case kind
|
99
|
-
when 'country' then
|
100
|
-
|
101
|
-
|
101
|
+
when 'country' then
|
102
|
+
zoneables
|
103
|
+
when 'state' then
|
104
|
+
zoneables.collect(&:country)
|
105
|
+
else
|
106
|
+
[]
|
102
107
|
end.flatten.compact.uniq
|
103
108
|
end
|
104
109
|
|
@@ -139,11 +144,15 @@ module Spree
|
|
139
144
|
# Indicates whether the specified zone falls entirely within the zone performing
|
140
145
|
# the check.
|
141
146
|
def contains?(target)
|
142
|
-
return false if
|
147
|
+
return false if state? && target.country?
|
143
148
|
return false if zone_members.empty? || target.zone_members.empty?
|
144
149
|
|
145
150
|
if kind == target.kind
|
146
|
-
|
151
|
+
if state?
|
152
|
+
return false if (target.states.pluck(:id) - states.pluck(:id)).present?
|
153
|
+
elsif country?
|
154
|
+
return false if (target.countries.pluck(:id) - countries.pluck(:id)).present?
|
155
|
+
end
|
147
156
|
else
|
148
157
|
return false if (target.states.pluck(:country_id) - countries.pluck(:id)).present?
|
149
158
|
end
|
@@ -151,24 +160,25 @@ module Spree
|
|
151
160
|
end
|
152
161
|
|
153
162
|
private
|
154
|
-
def remove_defunct_members
|
155
|
-
if zone_members.any?
|
156
|
-
zone_members.where('zoneable_id IS NULL OR zoneable_type != ?', "Spree::#{kind.classify}").destroy_all
|
157
|
-
end
|
158
|
-
end
|
159
163
|
|
160
|
-
|
161
|
-
|
164
|
+
def remove_defunct_members
|
165
|
+
if zone_members.any?
|
166
|
+
zone_members.where('zoneable_id IS NULL OR zoneable_type != ?', "Spree::#{kind.classify}").destroy_all
|
162
167
|
end
|
168
|
+
end
|
163
169
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
170
|
+
def remove_previous_default
|
171
|
+
Spree::Zone.where('id != ?', id).update_all(default_tax: false) if default_tax
|
172
|
+
end
|
173
|
+
|
174
|
+
def set_zone_members(ids, type)
|
175
|
+
zone_members.destroy_all
|
176
|
+
ids.reject(&:blank?).map do |id|
|
177
|
+
member = ZoneMember.new
|
178
|
+
member.zoneable_type = type
|
179
|
+
member.zoneable_id = id
|
180
|
+
members << member
|
172
181
|
end
|
182
|
+
end
|
173
183
|
end
|
174
184
|
end
|
@@ -18,7 +18,7 @@
|
|
18
18
|
<%= raw(item.variant.product.name) %>
|
19
19
|
<%= raw(item.variant.options_text) -%>
|
20
20
|
</td>
|
21
|
-
<td>(<%=item.quantity%>)
|
21
|
+
<td>(<%=item.quantity%>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %></td>
|
22
22
|
</tr>
|
23
23
|
<% end %>
|
24
24
|
<tr>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= Spree.t('order_mailer.cancel_email.order_summary_canceled') %>
|
7
7
|
============================================================
|
8
8
|
<% @order.line_items.each do |item| %>
|
9
|
-
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>)
|
9
|
+
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %>
|
10
10
|
<% end %>
|
11
11
|
============================================================
|
12
12
|
<%= Spree.t('order_mailer.cancel_email.subtotal') %> <%= @order.display_item_total %>
|
@@ -18,7 +18,7 @@
|
|
18
18
|
<%= raw(item.variant.product.name) %>
|
19
19
|
<%= raw(item.variant.options_text) -%>
|
20
20
|
</td>
|
21
|
-
<td>(<%=item.quantity%>)
|
21
|
+
<td>(<%=item.quantity%>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %></td>
|
22
22
|
</tr>
|
23
23
|
<% end %>
|
24
24
|
<tr>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= Spree.t('order_mailer.confirm_email.order_summary') %>
|
7
7
|
============================================================
|
8
8
|
<% @order.line_items.each do |item| %>
|
9
|
-
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>)
|
9
|
+
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %>
|
10
10
|
<% end %>
|
11
11
|
============================================================
|
12
12
|
<%= Spree.t('order_mailer.confirm_email.subtotal') %> <%= @order.display_item_total %>
|
data/config/locales/en.yml
CHANGED
@@ -463,6 +463,7 @@ en:
|
|
463
463
|
are_you_sure: Are you sure?
|
464
464
|
are_you_sure_delete: Are you sure you want to delete this record?
|
465
465
|
associated_adjustment_closed: The associated adjustment is closed, and will not be recalculated. Do you want to open it?
|
466
|
+
at_symbol: '@'
|
466
467
|
authorization_failure: Authorization Failure
|
467
468
|
authorized: Authorized
|
468
469
|
auto_capture: Auto Capture
|
@@ -767,6 +768,7 @@ en:
|
|
767
768
|
line_item_adjustments: "Line item adjustments"
|
768
769
|
list: List
|
769
770
|
loading: Loading
|
771
|
+
loading_tree: Loading tree. Please wait…
|
770
772
|
locale_changed: Locale Changed
|
771
773
|
location: Location
|
772
774
|
lock: Lock
|
@@ -798,6 +800,7 @@ en:
|
|
798
800
|
meta_title: Meta Title
|
799
801
|
metadata: Metadata
|
800
802
|
minimal_amount: Minimal Amount
|
803
|
+
missing_return_authorization: ! 'Missing Return Authorization for %{item_name}.'
|
801
804
|
month: Month
|
802
805
|
more: More
|
803
806
|
move_stock_between_locations: Move Stock Between Locations
|
@@ -805,7 +808,7 @@ en:
|
|
805
808
|
my_orders: My Orders
|
806
809
|
name: Name
|
807
810
|
name_on_card: Name on card
|
808
|
-
name_or_sku: Name or SKU (enter at least first
|
811
|
+
name_or_sku: Name or SKU (enter at least first 3 characters of product name)
|
809
812
|
new: New
|
810
813
|
new_adjustment: New Adjustment
|
811
814
|
new_customer: New Customer
|
@@ -928,7 +931,6 @@ en:
|
|
928
931
|
order_total: Order Total
|
929
932
|
order_updated: Order Updated
|
930
933
|
orders: Orders
|
931
|
-
other_items_in_other: Other Items in Order
|
932
934
|
out_of_stock: Out of Stock
|
933
935
|
overview: Overview
|
934
936
|
package_from: package from
|
@@ -1126,7 +1128,6 @@ en:
|
|
1126
1128
|
return_number: Return Number
|
1127
1129
|
return_quantity: Return Quantity
|
1128
1130
|
returned: Returned
|
1129
|
-
returns: Returns
|
1130
1131
|
review: Review
|
1131
1132
|
risk: Risk
|
1132
1133
|
risk_analysis: Risk Analysis
|
@@ -0,0 +1 @@
|
|
1
|
+
Spree::RefundReason.find_or_create_by(name: "Return processing", mutable: false)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class FixAdjustmentOrderId < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
say 'Populate order_id from adjustable_id where appropriate'
|
4
|
+
execute(<<-SQL.squish)
|
5
|
+
UPDATE
|
6
|
+
spree_adjustments
|
7
|
+
SET
|
8
|
+
order_id = adjustable_id
|
9
|
+
WHERE
|
10
|
+
adjustable_type = 'Spree::Order'
|
11
|
+
;
|
12
|
+
SQL
|
13
|
+
|
14
|
+
# Submitter of change does not care about MySQL, as it is not officially supported.
|
15
|
+
# Still spree officials decided to provide a working code path for MySQL users, hence
|
16
|
+
# submitter made a AR code path he could validate on PostgreSQL.
|
17
|
+
#
|
18
|
+
# Whoever runs a big enough MySQL installation where the AR solution hurts:
|
19
|
+
# Will have to write a better MySQL specific equivalent.
|
20
|
+
if Spree::Order.connection.adapter_name.eql?('MySQL')
|
21
|
+
Spree::Adjustment.where(adjustable_type: 'Spree::LineItem').find_each do |adjustment|
|
22
|
+
adjustment.update_columns(order_id: Spree::LineItem.find(adjustment.adjustable_id).order_id)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
execute(<<-SQL.squish)
|
26
|
+
UPDATE
|
27
|
+
spree_adjustments
|
28
|
+
SET
|
29
|
+
order_id =
|
30
|
+
(SELECT order_id FROM spree_line_items WHERE spree_line_items.id = spree_adjustments.adjustable_id)
|
31
|
+
WHERE
|
32
|
+
adjustable_type = 'Spree::LineItem'
|
33
|
+
SQL
|
34
|
+
end
|
35
|
+
|
36
|
+
say 'Fix schema for spree_adjustments order_id column'
|
37
|
+
change_table :spree_adjustments do |t|
|
38
|
+
t.change :order_id, :integer, null: false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Improved schema for postgresql, uncomment if you like it:
|
42
|
+
#
|
43
|
+
# # Negated Logical implication.
|
44
|
+
# #
|
45
|
+
# # When adjustable_type is 'Spree::Order' (p) the adjustable_id must be order_id (q).
|
46
|
+
# #
|
47
|
+
# # When adjustable_type is NOT 'Spree::Order' the adjustable id allowed to be any value (including of order_id in
|
48
|
+
# # case foreign keys match). XOR does not work here.
|
49
|
+
# #
|
50
|
+
# # Postgresql does not have an operator for logical implication. So we need to build the following truth table
|
51
|
+
# # via AND with OR:
|
52
|
+
# #
|
53
|
+
# # p q | CHECK = !(p -> q)
|
54
|
+
# # -----------
|
55
|
+
# # t t | t
|
56
|
+
# # t f | f
|
57
|
+
# # f t | t
|
58
|
+
# # f f | t
|
59
|
+
# #
|
60
|
+
# # According to de-morgans law the logical implication q -> p is equivalent to !p || q
|
61
|
+
# #
|
62
|
+
# execute(<<-SQL.squish)
|
63
|
+
# ALTER TABLE ONLY spree_adjustments
|
64
|
+
# ADD CONSTRAINT fk_spree_adjustments FOREIGN KEY (order_id)
|
65
|
+
# REFERENCES spree_orders(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
66
|
+
# ADD CONSTRAINT check_spree_adjustments_order_id CHECK
|
67
|
+
# (adjustable_type <> 'Spree::Order' OR order_id = adjustable_id);
|
68
|
+
# SQL
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class IncreaseScaleOnPreTaxAmounts < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
# set pre_tax_amount on shipments to discounted_amount - included_tax_total
|
4
|
+
# so that the null: false option on the shipment pre_tax_amount doesn't generate
|
5
|
+
# errors.
|
6
|
+
#
|
7
|
+
execute(<<-SQL)
|
8
|
+
UPDATE spree_shipments
|
9
|
+
SET pre_tax_amount = (cost + promo_total) - included_tax_total
|
10
|
+
WHERE pre_tax_amount IS NULL;
|
11
|
+
SQL
|
12
|
+
|
13
|
+
change_column :spree_line_items, :pre_tax_amount, :decimal, precision: 12, scale: 4, default: 0.0, null: false
|
14
|
+
change_column :spree_shipments, :pre_tax_amount, :decimal, precision: 12, scale: 4, default: 0.0, null: false
|
15
|
+
end
|
16
|
+
end
|
@@ -19,7 +19,7 @@ module Spree
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def redirect_back_or_default(default)
|
22
|
-
redirect_to(session["spree_user_return_to"] || default)
|
22
|
+
redirect_to(session["spree_user_return_to"] || request.env["HTTP_REFERER"] || default)
|
23
23
|
session["spree_user_return_to"] = nil
|
24
24
|
end
|
25
25
|
|
data/lib/spree/core/engine.rb
CHANGED
@@ -102,6 +102,13 @@ module Spree
|
|
102
102
|
initializer "spree.core.checking_migrations" do |app|
|
103
103
|
Migrations.new(config, engine_name).check
|
104
104
|
end
|
105
|
+
|
106
|
+
config.to_prepare do
|
107
|
+
# Load application's model / class decorators
|
108
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../../app/**/*_decorator*.rb')) do |c|
|
109
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
110
|
+
end
|
111
|
+
end
|
105
112
|
end
|
106
113
|
end
|
107
114
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
class EmailValidator < ActiveModel::EachValidator
|
2
|
-
def validate_each(record,attribute,value)
|
3
|
-
unless value =~
|
4
|
-
|
2
|
+
def validate_each(record, attribute, value)
|
3
|
+
unless value =~ %r{\A(([A-Za-z0-9]+_+)|
|
4
|
+
([A-Za-z0-9]+\-+)|
|
5
|
+
([A-Za-z0-9]+\.+)|
|
6
|
+
([A-Za-z0-9]+\++))*[A-Za-z0-9_]+@((\w+\-+)|
|
7
|
+
(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}\z}xi
|
8
|
+
record.errors.add(attribute, :invalid, { value: value }.merge!(options))
|
5
9
|
end
|
6
10
|
end
|
7
11
|
end
|
data/lib/spree/core/version.rb
CHANGED
@@ -61,8 +61,8 @@ module Spree
|
|
61
61
|
:meta_keywords, :price, :sku, :deleted_at, :prototype_id,
|
62
62
|
:option_values_hash, :weight, :height, :width, :depth,
|
63
63
|
:shipping_category_id, :tax_category_id,
|
64
|
-
:
|
65
|
-
option_type_ids: []
|
64
|
+
:cost_currency, :cost_price,
|
65
|
+
option_type_ids: [], taxon_ids: []
|
66
66
|
]
|
67
67
|
|
68
68
|
@@property_attributes = [:name, :presentation]
|