spree_core 3.0.1 → 3.0.2
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/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]
|