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
@@ -7,7 +7,9 @@ module Spree
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def add(variant, quantity = 1, options = {})
|
10
|
+
timestamp = Time.now
|
10
11
|
line_item = add_to_line_item(variant, quantity, options)
|
12
|
+
options[:line_item_created] = true if timestamp <= line_item.created_at
|
11
13
|
after_add_or_remove(line_item, options)
|
12
14
|
end
|
13
15
|
|
@@ -22,10 +24,10 @@ module Spree
|
|
22
24
|
# Update totals, then check if the order is eligible for any cart promotions.
|
23
25
|
# If we do not update first, then the item total will be wrong and ItemTotal
|
24
26
|
# promotion rules would not be triggered.
|
25
|
-
|
27
|
+
persist_totals
|
26
28
|
PromotionHandler::Cart.new(order).activate
|
27
29
|
order.ensure_updated_shipments
|
28
|
-
|
30
|
+
persist_totals
|
29
31
|
true
|
30
32
|
else
|
31
33
|
false
|
@@ -33,80 +35,81 @@ module Spree
|
|
33
35
|
end
|
34
36
|
|
35
37
|
private
|
36
|
-
def after_add_or_remove(line_item, options = {})
|
37
|
-
reload_totals
|
38
|
-
shipment = options[:shipment]
|
39
|
-
shipment.present? ? shipment.update_amounts : order.ensure_updated_shipments
|
40
|
-
PromotionHandler::Cart.new(order, line_item).activate
|
41
|
-
Adjustable::AdjustmentsUpdater.update(line_item)
|
42
|
-
reload_totals
|
43
|
-
line_item
|
44
|
-
end
|
45
38
|
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
def after_add_or_remove(line_item, options = {})
|
40
|
+
persist_totals
|
41
|
+
shipment = options[:shipment]
|
42
|
+
shipment.present? ? shipment.update_amounts : order.ensure_updated_shipments
|
43
|
+
PromotionHandler::Cart.new(order, line_item).activate
|
44
|
+
Adjustable::AdjustmentsUpdater.update(line_item)
|
45
|
+
TaxRate.adjust(order, [line_item]) if options[:line_item_created]
|
46
|
+
persist_totals
|
47
|
+
line_item
|
48
|
+
end
|
49
|
+
|
50
|
+
def filter_order_items(params)
|
51
|
+
filtered_params = params.symbolize_keys
|
52
|
+
return filtered_params if filtered_params[:line_items_attributes].nil? || filtered_params[:line_items_attributes][:id]
|
49
53
|
|
50
|
-
|
54
|
+
line_item_ids = order.line_items.pluck(:id)
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
+
params[:line_items_attributes].each_pair do |id, value|
|
57
|
+
unless line_item_ids.include?(value[:id].to_i) || value[:variant_id].present?
|
58
|
+
filtered_params[:line_items_attributes].delete(id)
|
56
59
|
end
|
57
|
-
filtered_params
|
58
60
|
end
|
61
|
+
filtered_params
|
62
|
+
end
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
def order_updater
|
65
|
+
@updater ||= OrderUpdater.new(order)
|
66
|
+
end
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
68
|
+
def persist_totals
|
69
|
+
order_updater.update_item_count
|
70
|
+
order_updater.update
|
71
|
+
end
|
69
72
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if line_item
|
74
|
-
line_item.quantity += quantity.to_i
|
75
|
-
line_item.currency = currency unless currency.nil?
|
76
|
-
else
|
77
|
-
opts = { currency: order.currency }.merge ActionController::Parameters.new(options).
|
78
|
-
permit(PermittedAttributes.line_item_attributes)
|
79
|
-
line_item = order.line_items.new(quantity: quantity,
|
80
|
-
variant: variant,
|
81
|
-
options: opts)
|
82
|
-
end
|
83
|
-
line_item.target_shipment = options[:shipment] if options.has_key? :shipment
|
84
|
-
line_item.save!
|
85
|
-
line_item
|
86
|
-
end
|
73
|
+
def add_to_line_item(variant, quantity, options = {})
|
74
|
+
line_item = grab_line_item_by_variant(variant, false, options)
|
87
75
|
|
88
|
-
|
89
|
-
line_item
|
90
|
-
line_item.
|
91
|
-
|
76
|
+
if line_item
|
77
|
+
line_item.quantity += quantity.to_i
|
78
|
+
line_item.currency = currency unless currency.nil?
|
79
|
+
else
|
80
|
+
opts = { currency: order.currency }.merge ActionController::Parameters.new(options).
|
81
|
+
permit(PermittedAttributes.line_item_attributes)
|
82
|
+
line_item = order.line_items.new(quantity: quantity,
|
83
|
+
variant: variant,
|
84
|
+
options: opts)
|
85
|
+
end
|
86
|
+
line_item.target_shipment = options[:shipment] if options.has_key? :shipment
|
87
|
+
line_item.save!
|
88
|
+
line_item
|
89
|
+
end
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
91
|
+
def remove_from_line_item(variant, quantity, options = {})
|
92
|
+
line_item = grab_line_item_by_variant(variant, true, options)
|
93
|
+
line_item.quantity -= quantity
|
94
|
+
line_item.target_shipment= options[:shipment]
|
98
95
|
|
99
|
-
|
96
|
+
if line_item.quantity.zero?
|
97
|
+
order.line_items.destroy(line_item)
|
98
|
+
else
|
99
|
+
line_item.save!
|
100
100
|
end
|
101
101
|
|
102
|
-
|
103
|
-
|
102
|
+
line_item
|
103
|
+
end
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
end
|
105
|
+
def grab_line_item_by_variant(variant, raise_error = false, options = {})
|
106
|
+
line_item = order.find_line_item_by_variant(variant, options)
|
108
107
|
|
109
|
-
|
108
|
+
if !line_item.present? && raise_error
|
109
|
+
raise ActiveRecord::RecordNotFound, "Line item not found for variant #{variant.sku}"
|
110
110
|
end
|
111
|
+
|
112
|
+
line_item
|
113
|
+
end
|
111
114
|
end
|
112
115
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Spree
|
2
|
+
class OrderMerger
|
3
|
+
attr_accessor :order
|
4
|
+
delegate :updater, to: :order
|
5
|
+
|
6
|
+
def initialize(order)
|
7
|
+
@order = order
|
8
|
+
end
|
9
|
+
|
10
|
+
def merge!(other_order, user = nil)
|
11
|
+
other_order.line_items.each do |other_order_line_item|
|
12
|
+
next unless other_order_line_item.currency == order.currency
|
13
|
+
|
14
|
+
current_line_item = find_matching_line_item(other_order_line_item)
|
15
|
+
handle_merge(current_line_item, other_order_line_item)
|
16
|
+
end
|
17
|
+
|
18
|
+
set_user(user)
|
19
|
+
persist_merge
|
20
|
+
|
21
|
+
# So that the destroy doesn't take out line items which may have been re-assigned
|
22
|
+
other_order.line_items.reload
|
23
|
+
other_order.destroy
|
24
|
+
end
|
25
|
+
|
26
|
+
# Compare the line item of the other order with mine.
|
27
|
+
# Make sure you allow any extensions to chime in on whether or
|
28
|
+
# not the extension-specific parts of the line item match
|
29
|
+
def find_matching_line_item(other_order_line_item)
|
30
|
+
order.line_items.detect do |my_li|
|
31
|
+
my_li.variant == other_order_line_item.variant &&
|
32
|
+
order.line_item_comparison_hooks.all? do |hook|
|
33
|
+
order.send(hook, my_li, other_order_line_item.serializable_hash)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_user(user = nil)
|
39
|
+
order.associate_user!(user) if !order.user && !user.blank?
|
40
|
+
end
|
41
|
+
|
42
|
+
# The idea is the end developer can choose to override the merge
|
43
|
+
# to their own choosing. Default is merge with errors.
|
44
|
+
def handle_merge(current_line_item, other_order_line_item)
|
45
|
+
if current_line_item
|
46
|
+
current_line_item.quantity += other_order_line_item.quantity
|
47
|
+
handle_error(current_line_item) unless current_line_item.save
|
48
|
+
else
|
49
|
+
other_order_line_item.order_id = order.id
|
50
|
+
handle_error(other_order_line_item) unless other_order_line_item.save
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Change the error messages as you choose.
|
55
|
+
def handle_error(line_item)
|
56
|
+
order.errors[:base] << line_item.errors.full_messages
|
57
|
+
end
|
58
|
+
|
59
|
+
def persist_merge
|
60
|
+
updater.update_item_count
|
61
|
+
updater.update_item_total
|
62
|
+
updater.persist_totals
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/app/models/spree/payment.rb
CHANGED
@@ -26,6 +26,7 @@ module Spree
|
|
26
26
|
has_many :capture_events, class_name: 'Spree::PaymentCaptureEvent'
|
27
27
|
has_many :refunds, inverse_of: :payment
|
28
28
|
|
29
|
+
validates_presence_of :payment_method
|
29
30
|
before_validation :validate_source
|
30
31
|
|
31
32
|
after_save :create_payment_profile, if: :profiles_supported?
|
@@ -173,6 +174,10 @@ module Spree
|
|
173
174
|
amount - captured_amount
|
174
175
|
end
|
175
176
|
|
177
|
+
def editable?
|
178
|
+
checkout? || pending?
|
179
|
+
end
|
180
|
+
|
176
181
|
private
|
177
182
|
|
178
183
|
def validate_source
|
@@ -15,17 +15,27 @@ module Spree
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def capture(*args)
|
18
|
-
|
18
|
+
simulated_successful_billing_response
|
19
19
|
end
|
20
20
|
|
21
21
|
def cancel(response); end
|
22
22
|
|
23
23
|
def void(*args)
|
24
|
-
|
24
|
+
simulated_successful_billing_response
|
25
25
|
end
|
26
26
|
|
27
27
|
def source_required?
|
28
28
|
false
|
29
29
|
end
|
30
|
+
|
31
|
+
def credit(*args)
|
32
|
+
simulated_successful_billing_response
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def simulated_successful_billing_response
|
38
|
+
ActiveMerchant::Billing::Response.new(true, "", {}, {})
|
39
|
+
end
|
30
40
|
end
|
31
41
|
end
|
data/app/models/spree/product.rb
CHANGED
@@ -74,6 +74,7 @@ module Spree
|
|
74
74
|
after_create :build_variants_from_option_values_hash, if: :option_values_hash
|
75
75
|
|
76
76
|
after_destroy :punch_slug
|
77
|
+
after_restore :update_slug_history
|
77
78
|
|
78
79
|
after_initialize :ensure_master
|
79
80
|
|
@@ -267,6 +268,10 @@ module Spree
|
|
267
268
|
update_column :slug, "#{Time.now.to_i}_#{slug}"[0..254] unless frozen?
|
268
269
|
end
|
269
270
|
|
271
|
+
def update_slug_history
|
272
|
+
self.save!
|
273
|
+
end
|
274
|
+
|
270
275
|
def anything_changed?
|
271
276
|
changed? || @nested_changes
|
272
277
|
end
|
@@ -29,22 +29,26 @@ module Spree
|
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
32
|
-
def promotions
|
33
|
-
promo_table = Promotion.arel_table
|
34
|
-
join_table = Arel::Table.new(:spree_orders_promotions)
|
35
32
|
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
def promotions
|
34
|
+
# AR cannot bind raw ASTs to prepared statements. There always must be a manager around.
|
35
|
+
# Also Postgresql requires an aliased table for `SELECT * FROM (subexpression) AS alias`.
|
36
|
+
# And Sqlite3 cannot work on outher parenthesis from `(left UNION right)`.
|
37
|
+
# So this construct makes both happy.
|
38
|
+
select = Arel::SelectManager.new(
|
39
|
+
Promotion,
|
40
|
+
Promotion.arel_table.create_table_alias(
|
41
|
+
order.promotions.active.union(Promotion.active.where(code: nil, path: nil)),
|
42
|
+
Promotion.table_name
|
43
|
+
),
|
44
|
+
)
|
45
|
+
select.project(Arel.star)
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
).or(join_table[:order_id].eq(order.id))
|
46
|
-
).distinct
|
47
|
-
end
|
47
|
+
Promotion.find_by_sql(
|
48
|
+
select,
|
49
|
+
order.promotions.bind_values
|
50
|
+
)
|
51
|
+
end
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
@@ -5,19 +5,20 @@ module Spree
|
|
5
5
|
unit_count = line_item.inventory_units.size
|
6
6
|
return if unit_count >= line_item.quantity
|
7
7
|
quantity = line_item.quantity - unit_count
|
8
|
+
return if quantity.zero?
|
8
9
|
|
9
10
|
quantifier = Stock::Quantifier.new(line_item.variant)
|
10
11
|
|
11
|
-
|
12
|
-
variant = line_item.variant
|
13
|
-
display_name = %Q{#{variant.name}}
|
14
|
-
display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank?
|
12
|
+
return if quantifier.can_supply?(quantity)
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
variant = line_item.variant
|
15
|
+
display_name = "#{variant.name}"
|
16
|
+
display_name += " (#{variant.options_text})" unless variant.options_text.blank?
|
17
|
+
|
18
|
+
line_item.errors[:quantity] << Spree.t(
|
19
|
+
:selected_quantity_not_available,
|
20
|
+
item: display_name.inspect
|
21
|
+
)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -8,7 +8,11 @@ module Spree
|
|
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
|
+
validates_numericality_of :count_on_hand,
|
13
|
+
greater_than_or_equal_to: 0,
|
14
|
+
less_than_or_equal_to: 2**31 - 1,
|
15
|
+
only_integer: true, if: :verify_count_on_hand?
|
12
16
|
|
13
17
|
delegate :weight, :should_track_inventory?, to: :variant
|
14
18
|
|
@@ -6,7 +6,12 @@ module Spree
|
|
6
6
|
after_create :update_stock_item_quantity
|
7
7
|
|
8
8
|
validates :stock_item, presence: true
|
9
|
-
validates :quantity, presence: true
|
9
|
+
validates :quantity, presence: true, numericality: {
|
10
|
+
greater_than_or_equal_to: -2**31,
|
11
|
+
less_than_or_equal_to: 2**31-1,
|
12
|
+
only_integer: true,
|
13
|
+
allow_nil: true
|
14
|
+
}
|
10
15
|
|
11
16
|
scope :recent, -> { order('created_at DESC') }
|
12
17
|
|