solidus_core 4.4.1 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/spree/core/controller_helpers/auth.rb +66 -0
- data/app/helpers/spree/core/controller_helpers/common.rb +82 -0
- data/app/helpers/spree/core/controller_helpers/order.rb +86 -0
- data/app/helpers/spree/core/controller_helpers/payment_parameters.rb +165 -0
- data/app/helpers/spree/core/controller_helpers/pricing.rb +19 -0
- data/app/helpers/spree/core/controller_helpers/search.rb +16 -0
- data/app/helpers/spree/core/controller_helpers/store.rb +19 -0
- data/app/helpers/spree/core/controller_helpers/strong_parameters.rb +74 -0
- data/app/models/concerns/spree/metadata.rb +64 -0
- data/app/models/concerns/spree/user_address_book.rb +4 -5
- data/app/models/spree/core/state_machines/inventory_unit.rb +42 -0
- data/app/models/spree/core/state_machines/order/class_methods.rb +217 -0
- data/app/models/spree/core/state_machines/order.rb +42 -0
- data/app/models/spree/core/state_machines/payment.rb +61 -0
- data/app/models/spree/core/state_machines/reimbursement.rb +33 -0
- data/app/models/spree/core/state_machines/return_authorization.rb +32 -0
- data/app/models/spree/core/state_machines/return_item/acceptance_status.rb +51 -0
- data/app/models/spree/core/state_machines/return_item/reception_status.rb +42 -0
- data/app/models/spree/core/state_machines/shipment.rb +58 -0
- data/app/models/spree/customer_return.rb +2 -0
- data/app/models/spree/item_total.rb +28 -0
- data/app/models/spree/legacy_user.rb +1 -0
- data/app/models/spree/line_item.rb +21 -0
- data/app/models/spree/money.rb +120 -0
- data/app/models/spree/order.rb +20 -9
- data/app/models/spree/order_merger.rb +1 -1
- data/app/models/spree/order_shipping.rb +0 -1
- data/app/models/spree/order_taxation.rb +1 -0
- data/app/models/spree/order_updater.rb +13 -30
- data/app/models/spree/payment.rb +1 -0
- data/app/models/spree/permission_sets/base.rb +45 -0
- data/app/models/spree/permission_sets/configuration_display.rb +53 -0
- data/app/models/spree/permission_sets/configuration_management.rb +52 -0
- data/app/models/spree/permission_sets/dashboard_display.rb +28 -0
- data/app/models/spree/permission_sets/default_customer.rb +83 -0
- data/app/models/spree/permission_sets/order_display.rb +50 -0
- data/app/models/spree/permission_sets/order_management.rb +50 -0
- data/app/models/spree/permission_sets/product_display.rb +43 -0
- data/app/models/spree/permission_sets/product_management.rb +47 -0
- data/app/models/spree/permission_sets/restricted_stock_display.rb +33 -0
- data/app/models/spree/permission_sets/restricted_stock_management.rb +33 -0
- data/app/models/spree/permission_sets/stock_display.rb +26 -0
- data/app/models/spree/permission_sets/stock_management.rb +26 -0
- data/app/models/spree/permission_sets/super_user.rb +26 -0
- data/app/models/spree/permission_sets/user_display.rb +27 -0
- data/app/models/spree/permission_sets/user_management.rb +44 -0
- data/app/models/spree/product.rb +7 -0
- data/app/models/spree/refund.rb +2 -0
- data/app/models/spree/return_authorization.rb +2 -0
- data/app/models/spree/shipment.rb +2 -0
- data/app/models/spree/simple_order_contents.rb +4 -1
- data/app/models/spree/store_credit_event.rb +1 -0
- data/app/models/spree/tax/tax_helpers.rb +12 -1
- data/app/models/spree/tax_calculator/default.rb +1 -1
- data/app/models/spree/taxon.rb +22 -2
- data/app/models/spree/taxon_brand_selector.rb +22 -0
- data/app/models/spree/unauthorized_redirect_handler.rb +24 -0
- data/app/models/spree/user_address.rb +9 -3
- data/app/models/spree/variant.rb +14 -1
- data/config/locales/en.yml +16 -0
- data/db/migrate/20220419170826_remove_archived_user_addresses.rb +12 -0
- data/db/migrate/20250129061658_add_metadata_to_spree_resources.rb +29 -0
- data/db/migrate/20250201172950_add_gtin_and_condition_to_spree_variant.rb +6 -0
- data/db/migrate/20250207104016_add_primary_taxon_to_products.rb +7 -0
- data/lib/generators/solidus/install/app_templates/authentication/custom.rb +0 -5
- data/lib/generators/solidus/install/app_templates/frontend/starter.rb +1 -1
- data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
- data/lib/generators/spree/dummy/templates/rails/application.rb.tt +1 -1
- data/lib/generators/spree/dummy/templates/rails/manifest.js +3 -0
- data/lib/spree/app_configuration.rb +49 -0
- data/lib/spree/core/controller_helpers/auth.rb +5 -61
- data/lib/spree/core/controller_helpers/common.rb +5 -80
- data/lib/spree/core/controller_helpers/order.rb +5 -86
- data/lib/spree/core/controller_helpers/payment_parameters.rb +5 -163
- data/lib/spree/core/controller_helpers/pricing.rb +5 -17
- data/lib/spree/core/controller_helpers/search.rb +5 -14
- data/lib/spree/core/controller_helpers/store.rb +5 -17
- data/lib/spree/core/controller_helpers/strong_parameters.rb +5 -71
- data/lib/spree/core/engine.rb +5 -0
- data/lib/spree/core/state_machines/inventory_unit.rb +5 -40
- data/lib/spree/core/state_machines/order.rb +5 -250
- data/lib/spree/core/state_machines/payment.rb +5 -59
- data/lib/spree/core/state_machines/reimbursement.rb +5 -31
- data/lib/spree/core/state_machines/return_authorization.rb +5 -30
- data/lib/spree/core/state_machines/return_item/acceptance_status.rb +5 -49
- data/lib/spree/core/state_machines/return_item/reception_status.rb +5 -40
- data/lib/spree/core/state_machines/shipment.rb +5 -56
- data/lib/spree/core/state_machines.rb +48 -81
- data/lib/spree/core/version.rb +2 -2
- data/lib/spree/core.rb +4 -10
- data/lib/spree/money.rb +5 -118
- data/lib/spree/permission_sets/base.rb +5 -42
- data/lib/spree/permission_sets/configuration_display.rb +5 -51
- data/lib/spree/permission_sets/configuration_management.rb +5 -50
- data/lib/spree/permission_sets/dashboard_display.rb +5 -26
- data/lib/spree/permission_sets/default_customer.rb +5 -81
- data/lib/spree/permission_sets/order_display.rb +5 -48
- data/lib/spree/permission_sets/order_management.rb +5 -48
- data/lib/spree/permission_sets/product_display.rb +5 -41
- data/lib/spree/permission_sets/product_management.rb +5 -45
- data/lib/spree/permission_sets/restricted_stock_display.rb +5 -31
- data/lib/spree/permission_sets/restricted_stock_management.rb +5 -31
- data/lib/spree/permission_sets/stock_display.rb +5 -24
- data/lib/spree/permission_sets/stock_management.rb +5 -24
- data/lib/spree/permission_sets/super_user.rb +5 -24
- data/lib/spree/permission_sets/user_display.rb +5 -25
- data/lib/spree/permission_sets/user_management.rb +5 -42
- data/lib/spree/permission_sets.rb +5 -16
- data/lib/spree/permitted_attributes.rb +18 -7
- data/lib/spree/preferences/configuration.rb +4 -0
- data/lib/spree/preferences/persistable.rb +1 -1
- data/lib/spree/testing_support/capybara_ext.rb +10 -0
- data/lib/spree/testing_support/dummy_app.rb +1 -1
- data/lib/spree/testing_support/extension_rake.rb +2 -2
- data/lib/spree/testing_support/factories/order_factory.rb +9 -1
- data/lib/spree/user_class_handle.rb +2 -2
- data/solidus_core.gemspec +1 -1
- metadata +64 -24
- data/lib/generators/spree/dummy/templates/rails/script/rails +0 -6
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
module Order
|
7
|
+
module ClassMethods
|
8
|
+
attr_accessor :previous_states
|
9
|
+
attr_writer :next_event_transitions, :checkout_steps, :removed_transitions
|
10
|
+
|
11
|
+
def checkout_flow(&block)
|
12
|
+
if block_given?
|
13
|
+
@checkout_flow = block
|
14
|
+
define_state_machine!
|
15
|
+
else
|
16
|
+
@checkout_flow
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_state_machine!
|
21
|
+
self.checkout_steps = {}
|
22
|
+
self.next_event_transitions = []
|
23
|
+
self.previous_states = [:cart]
|
24
|
+
self.removed_transitions = []
|
25
|
+
|
26
|
+
# Build the checkout flow using the checkout_flow defined either
|
27
|
+
# within the Order class, or a decorator for that class.
|
28
|
+
#
|
29
|
+
# This method may be called multiple times depending on if the
|
30
|
+
# checkout_flow is re-defined in a decorator or not.
|
31
|
+
instance_eval(&checkout_flow)
|
32
|
+
|
33
|
+
klass = self
|
34
|
+
|
35
|
+
# To avoid multiple occurrences of the same transition being defined
|
36
|
+
# On first definition, state_machines will not be defined
|
37
|
+
state_machines.clear if respond_to?(:state_machines)
|
38
|
+
state_machine :state, initial: :cart, use_transactions: false do
|
39
|
+
klass.next_event_transitions.each { |state| transition(state.merge(on: :next)) }
|
40
|
+
|
41
|
+
# Persist the state on the order
|
42
|
+
after_transition do |order, transition|
|
43
|
+
# Hard to say if this is really necessary, it was introduced in this commit:
|
44
|
+
# https://github.com/mamhoff/solidus/commit/fa1d66c42e4c04ee7cd1c20d87e4cdb74a226d3d
|
45
|
+
# But it seems to be harmless, so we'll keep it for now.
|
46
|
+
order.state = order.state # rubocop:disable Lint/SelfAssignment
|
47
|
+
|
48
|
+
order.state_changes.create(
|
49
|
+
previous_state: transition.from,
|
50
|
+
next_state: transition.to,
|
51
|
+
name: 'order',
|
52
|
+
user_id: order.user_id
|
53
|
+
)
|
54
|
+
order.save
|
55
|
+
end
|
56
|
+
|
57
|
+
event :cancel do
|
58
|
+
transition to: :canceled, if: :allow_cancel?, from: :complete
|
59
|
+
end
|
60
|
+
|
61
|
+
event :return do
|
62
|
+
transition to: :returned, from: [:complete, :awaiting_return], if: :all_inventory_units_returned?
|
63
|
+
end
|
64
|
+
|
65
|
+
event :resume do
|
66
|
+
transition to: :resumed, from: :canceled, if: :canceled?
|
67
|
+
end
|
68
|
+
|
69
|
+
event :authorize_return do
|
70
|
+
transition to: :awaiting_return, from: :complete
|
71
|
+
end
|
72
|
+
|
73
|
+
event :complete do
|
74
|
+
transition to: :complete, from: klass.checkout_steps.keys.last
|
75
|
+
end
|
76
|
+
|
77
|
+
if states[:payment]
|
78
|
+
event :payment_failed do
|
79
|
+
transition to: :payment, from: :confirm
|
80
|
+
end
|
81
|
+
|
82
|
+
after_transition to: :complete, do: :add_payment_sources_to_wallet
|
83
|
+
before_transition to: :payment, do: :add_default_payment_from_wallet
|
84
|
+
before_transition to: :payment, do: :ensure_billing_address
|
85
|
+
|
86
|
+
before_transition to: :confirm, do: :add_store_credit_payments
|
87
|
+
|
88
|
+
# see also process_payments_before_complete below which needs to
|
89
|
+
# be added in the correct sequence.
|
90
|
+
end
|
91
|
+
|
92
|
+
before_transition from: :cart, do: :ensure_line_items_present
|
93
|
+
|
94
|
+
if states[:address]
|
95
|
+
before_transition to: :address, do: :assign_default_user_addresses
|
96
|
+
before_transition from: :address, do: :persist_user_address!
|
97
|
+
end
|
98
|
+
|
99
|
+
if states[:delivery]
|
100
|
+
before_transition to: :delivery, do: :ensure_shipping_address
|
101
|
+
before_transition to: :delivery, do: :create_proposed_shipments
|
102
|
+
before_transition to: :delivery, do: :ensure_available_shipping_rates
|
103
|
+
end
|
104
|
+
|
105
|
+
before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
|
106
|
+
before_transition to: :resumed, do: :validate_line_item_availability
|
107
|
+
|
108
|
+
# Sequence of before_transition to: :complete
|
109
|
+
# calls matter so that we do not process payments
|
110
|
+
# until validations have passed
|
111
|
+
before_transition to: :complete, do: :validate_line_item_availability
|
112
|
+
before_transition to: :complete, do: :ensure_promotions_eligible
|
113
|
+
before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
|
114
|
+
before_transition to: :complete, do: :ensure_inventory_units
|
115
|
+
if states[:payment]
|
116
|
+
before_transition to: :complete, do: :process_payments_before_complete
|
117
|
+
end
|
118
|
+
|
119
|
+
after_transition to: :complete, do: :finalize
|
120
|
+
after_transition to: :resumed, do: :after_resume
|
121
|
+
after_transition to: :canceled, do: :after_cancel
|
122
|
+
|
123
|
+
after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
|
124
|
+
order.recalculate
|
125
|
+
end
|
126
|
+
|
127
|
+
after_transition do |order, transition|
|
128
|
+
order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
|
129
|
+
end
|
130
|
+
|
131
|
+
after_failure do |order, transition|
|
132
|
+
order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def go_to_state(name, options = {})
|
138
|
+
checkout_steps[name] = options
|
139
|
+
previous_states.each do |state|
|
140
|
+
add_transition({ from: state, to: name }.merge(options))
|
141
|
+
end
|
142
|
+
if options[:if]
|
143
|
+
previous_states << name
|
144
|
+
else
|
145
|
+
self.previous_states = [name]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def insert_checkout_step(name, options = {})
|
150
|
+
before = options.delete(:before)
|
151
|
+
after = options.delete(:after) unless before
|
152
|
+
after = checkout_steps.keys.last unless before || after
|
153
|
+
|
154
|
+
cloned_steps = checkout_steps.clone
|
155
|
+
cloned_removed_transitions = removed_transitions.clone
|
156
|
+
checkout_flow do
|
157
|
+
cloned_steps.each_pair do |key, value|
|
158
|
+
go_to_state(name, options) if key == before
|
159
|
+
go_to_state(key, value)
|
160
|
+
go_to_state(name, options) if key == after
|
161
|
+
end
|
162
|
+
cloned_removed_transitions.each do |transition|
|
163
|
+
remove_transition(transition)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def remove_checkout_step(name)
|
169
|
+
cloned_steps = checkout_steps.clone
|
170
|
+
cloned_removed_transitions = removed_transitions.clone
|
171
|
+
checkout_flow do
|
172
|
+
cloned_steps.each_pair do |key, value|
|
173
|
+
go_to_state(key, value) unless key == name
|
174
|
+
end
|
175
|
+
cloned_removed_transitions.each do |transition|
|
176
|
+
remove_transition(transition)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def remove_transition(options = {})
|
182
|
+
removed_transitions << options
|
183
|
+
next_event_transitions.delete(find_transition(options))
|
184
|
+
end
|
185
|
+
|
186
|
+
def find_transition(options = {})
|
187
|
+
return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
|
188
|
+
|
189
|
+
next_event_transitions.detect do |transition|
|
190
|
+
transition[options[:from].to_sym] == options[:to].to_sym
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def next_event_transitions
|
195
|
+
@next_event_transitions ||= []
|
196
|
+
end
|
197
|
+
|
198
|
+
def checkout_steps
|
199
|
+
@checkout_steps ||= {}
|
200
|
+
end
|
201
|
+
|
202
|
+
def checkout_step_names
|
203
|
+
checkout_steps.keys
|
204
|
+
end
|
205
|
+
|
206
|
+
def add_transition(options)
|
207
|
+
next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
|
208
|
+
end
|
209
|
+
|
210
|
+
def removed_transitions
|
211
|
+
@removed_transitions ||= []
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
module Order
|
7
|
+
def self.included(klass)
|
8
|
+
klass.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
def checkout_steps
|
12
|
+
steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
|
13
|
+
next if options.include?(:if) && !options[:if].call(self)
|
14
|
+
|
15
|
+
checkout_steps << step
|
16
|
+
}.map(&:to_s)
|
17
|
+
# Ensure there is always a complete step
|
18
|
+
steps << "complete" unless steps.include?("complete")
|
19
|
+
steps
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_checkout_step?(step)
|
23
|
+
step.present? && checkout_steps.include?(step)
|
24
|
+
end
|
25
|
+
|
26
|
+
def passed_checkout_step?(step)
|
27
|
+
has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
|
28
|
+
end
|
29
|
+
|
30
|
+
def checkout_step_index(step)
|
31
|
+
checkout_steps.index(step).to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def can_go_to_state?(state)
|
35
|
+
return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
|
36
|
+
|
37
|
+
checkout_step_index(state) > checkout_step_index(self.state)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
# Payments' state machine
|
7
|
+
#
|
8
|
+
# for each event the following instance methods are dynamically implemented:
|
9
|
+
# #<event_name>
|
10
|
+
# #<event_name>!
|
11
|
+
# #can_<event_name>?
|
12
|
+
#
|
13
|
+
# for each state the following instance methods are implemented:
|
14
|
+
# #<state_name>?
|
15
|
+
#
|
16
|
+
module Payment
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
state_machine initial: :checkout do
|
21
|
+
# With card payments, happens before purchase or authorization happens
|
22
|
+
#
|
23
|
+
# Setting it after creating a profile and authorizing a full amount will
|
24
|
+
# prevent the payment from being authorized again once Order transitions
|
25
|
+
# to complete
|
26
|
+
event :started_processing do
|
27
|
+
transition from: [:checkout, :pending, :completed, :processing], to: :processing
|
28
|
+
end
|
29
|
+
# When processing during checkout fails
|
30
|
+
event :failure do
|
31
|
+
transition from: [:pending, :processing], to: :failed
|
32
|
+
end
|
33
|
+
# With card payments this represents authorizing the payment
|
34
|
+
event :pend do
|
35
|
+
transition from: [:checkout, :processing], to: :pending
|
36
|
+
end
|
37
|
+
# With card payments this represents completing a purchase or capture transaction
|
38
|
+
event :complete do
|
39
|
+
transition from: [:processing, :pending, :checkout], to: :completed
|
40
|
+
end
|
41
|
+
event :void do
|
42
|
+
transition from: [:pending, :processing, :completed, :checkout], to: :void
|
43
|
+
end
|
44
|
+
# when the card brand isnt supported
|
45
|
+
event :invalidate do
|
46
|
+
transition from: [:checkout], to: :invalid
|
47
|
+
end
|
48
|
+
|
49
|
+
after_transition do |payment, transition|
|
50
|
+
payment.state_changes.create!(
|
51
|
+
previous_state: transition.from,
|
52
|
+
next_state: transition.to,
|
53
|
+
name: 'payment'
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
# Reimbursement' state machine
|
7
|
+
#
|
8
|
+
# for each event the following instance methods are dynamically implemented:
|
9
|
+
# #<event_name>
|
10
|
+
# #<event_name>!
|
11
|
+
# #can_<event_name>?
|
12
|
+
#
|
13
|
+
# for each state the following instance methods are implemented:
|
14
|
+
# #<state_name>?
|
15
|
+
#
|
16
|
+
module Reimbursement
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
state_machine :reimbursement_status, initial: :pending do
|
21
|
+
event :errored do
|
22
|
+
transition to: :errored, from: [:pending, :errored]
|
23
|
+
end
|
24
|
+
|
25
|
+
event :reimbursed do
|
26
|
+
transition to: :reimbursed, from: [:pending, :errored]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
# Return Authorizations' state machine
|
7
|
+
#
|
8
|
+
# for each event the following instance methods are dynamically implemented:
|
9
|
+
# #<event_name>
|
10
|
+
# #<event_name>!
|
11
|
+
# #can_<event_name>?
|
12
|
+
#
|
13
|
+
# for each state the following instance methods are implemented:
|
14
|
+
# #<state_name>?
|
15
|
+
#
|
16
|
+
module ReturnAuthorization
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
state_machine initial: :authorized do
|
21
|
+
before_transition to: :canceled, do: :cancel_return_items
|
22
|
+
|
23
|
+
event :cancel do
|
24
|
+
transition to: :canceled, from: :authorized,
|
25
|
+
if: lambda { |return_authorization| return_authorization.can_cancel_return_items? }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
module ReturnItem
|
7
|
+
# Return Items' acceptance status state machine
|
8
|
+
#
|
9
|
+
# for each event the following instance methods are dynamically implemented:
|
10
|
+
# #<event_name>
|
11
|
+
# #<event_name>!
|
12
|
+
# #can_<event_name>?
|
13
|
+
#
|
14
|
+
# for each state the following instance methods are implemented:
|
15
|
+
# #<state_name>?
|
16
|
+
#
|
17
|
+
module AcceptanceStatus
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
included do
|
21
|
+
state_machine :acceptance_status, initial: :pending do
|
22
|
+
event :attempt_accept do
|
23
|
+
transition to: :accepted, from: :accepted
|
24
|
+
transition to: :accepted, from: :pending, if: ->(return_item) { return_item.eligible_for_return? }
|
25
|
+
transition to: :manual_intervention_required, from: :pending, if: ->(return_item) { return_item.requires_manual_intervention? }
|
26
|
+
transition to: :rejected, from: :pending
|
27
|
+
end
|
28
|
+
|
29
|
+
# bypasses eligibility checks
|
30
|
+
event :accept do
|
31
|
+
transition to: :accepted, from: [:accepted, :pending, :manual_intervention_required]
|
32
|
+
end
|
33
|
+
|
34
|
+
# bypasses eligibility checks
|
35
|
+
event :reject do
|
36
|
+
transition to: :rejected, from: [:accepted, :pending, :manual_intervention_required]
|
37
|
+
end
|
38
|
+
|
39
|
+
# bypasses eligibility checks
|
40
|
+
event :require_manual_intervention do
|
41
|
+
transition to: :manual_intervention_required, from: [:accepted, :pending, :manual_intervention_required]
|
42
|
+
end
|
43
|
+
|
44
|
+
after_transition any => any, do: :persist_acceptance_status_errors
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
module ReturnItem
|
7
|
+
# Return Items' reception status state machine
|
8
|
+
#
|
9
|
+
# for each event the following instance methods are dynamically implemented:
|
10
|
+
# #<event_name>
|
11
|
+
# #<event_name>!
|
12
|
+
# #can_<event_name>?
|
13
|
+
#
|
14
|
+
# for each state the following instance methods are implemented:
|
15
|
+
# #<state_name>?
|
16
|
+
#
|
17
|
+
module ReceptionStatus
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
included do
|
21
|
+
state_machine :reception_status, initial: :awaiting do
|
22
|
+
after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :attempt_accept, if: :can_attempt_accept?
|
23
|
+
after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :check_unexchange
|
24
|
+
after_transition to: :received, do: :process_inventory_unit!
|
25
|
+
|
26
|
+
event(:cancel) { transition to: :cancelled, from: :awaiting }
|
27
|
+
|
28
|
+
event(:receive) { transition to: :received, from: ::Spree::ReturnItem::INTERMEDIATE_RECEPTION_STATUSES + [:awaiting] }
|
29
|
+
event(:unexchange) { transition to: :unexchanged, from: [:awaiting] }
|
30
|
+
event(:give) { transition to: :given_to_customer, from: :awaiting }
|
31
|
+
event(:lost) { transition to: :lost_in_transit, from: :awaiting }
|
32
|
+
event(:wrong_item_shipped) { transition to: :shipped_wrong_item, from: :awaiting }
|
33
|
+
event(:short_shipped) { transition to: :short_shipped, from: :awaiting }
|
34
|
+
event(:in_transit) { transition to: :in_transit, from: :awaiting }
|
35
|
+
event(:expired) { transition to: :expired, from: :awaiting }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
class StateMachines
|
6
|
+
# Shipments' state machine
|
7
|
+
#
|
8
|
+
# for each event the following instance methods are dynamically implemented:
|
9
|
+
# #<event_name>
|
10
|
+
# #<event_name>!
|
11
|
+
# #can_<event_name>?
|
12
|
+
#
|
13
|
+
# for each state the following instance methods are implemented:
|
14
|
+
# #<state_name>?
|
15
|
+
#
|
16
|
+
module Shipment
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
state_machine initial: :pending, use_transactions: false do
|
21
|
+
event :ready do
|
22
|
+
transition from: :pending, to: :shipped, if: :can_transition_from_pending_to_shipped?
|
23
|
+
transition from: :pending, to: :ready, if: :can_transition_from_pending_to_ready?
|
24
|
+
end
|
25
|
+
|
26
|
+
event :pend do
|
27
|
+
transition from: :ready, to: :pending
|
28
|
+
end
|
29
|
+
|
30
|
+
event :ship do
|
31
|
+
transition from: [:ready, :canceled], to: :shipped
|
32
|
+
end
|
33
|
+
after_transition to: :shipped, do: :after_ship
|
34
|
+
|
35
|
+
event :cancel do
|
36
|
+
transition to: :canceled, from: [:pending, :ready]
|
37
|
+
end
|
38
|
+
after_transition to: :canceled, do: :after_cancel
|
39
|
+
|
40
|
+
event :resume do
|
41
|
+
transition from: :canceled, to: :ready, if: :can_transition_from_canceled_to_ready?
|
42
|
+
transition from: :canceled, to: :pending
|
43
|
+
end
|
44
|
+
after_transition from: :canceled, to: [:pending, :ready, :shipped], do: :after_resume
|
45
|
+
|
46
|
+
after_transition do |shipment, transition|
|
47
|
+
shipment.state_changes.create!(
|
48
|
+
previous_state: transition.from,
|
49
|
+
next_state: transition.to,
|
50
|
+
name: 'shipment'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Spree::ItemTotal
|
4
|
+
def initialize(item)
|
5
|
+
@item = item
|
6
|
+
end
|
7
|
+
|
8
|
+
def recalculate!
|
9
|
+
tax_adjustments = item.adjustments.select do |adjustment|
|
10
|
+
adjustment.tax? && !adjustment.marked_for_destruction?
|
11
|
+
end
|
12
|
+
|
13
|
+
# Included tax adjustments are those which are included in the price.
|
14
|
+
# These ones should not affect the eventual total price.
|
15
|
+
#
|
16
|
+
# Additional tax adjustments are the opposite, affecting the final total.
|
17
|
+
item.included_tax_total = tax_adjustments.select(&:included?).sum(&:amount)
|
18
|
+
item.additional_tax_total = tax_adjustments.reject(&:included?).sum(&:amount)
|
19
|
+
|
20
|
+
item.adjustment_total = item.adjustments.reject { |adjustment|
|
21
|
+
adjustment.marked_for_destruction? || adjustment.included?
|
22
|
+
}.sum(&:amount)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :item
|
28
|
+
end
|
@@ -10,6 +10,8 @@ module Spree
|
|
10
10
|
# promotion system.
|
11
11
|
#
|
12
12
|
class LineItem < Spree::Base
|
13
|
+
include Metadata
|
14
|
+
|
13
15
|
belongs_to :order, class_name: "Spree::Order", inverse_of: :line_items, touch: true, optional: true
|
14
16
|
belongs_to :variant, -> { with_discarded }, class_name: "Spree::Variant", inverse_of: :line_items, optional: true
|
15
17
|
belongs_to :tax_category, class_name: "Spree::TaxCategory", optional: true
|
@@ -36,6 +38,7 @@ module Spree
|
|
36
38
|
before_destroy :destroy_inventory_units
|
37
39
|
|
38
40
|
delegate :name, :description, :sku, :should_track_inventory?, to: :variant
|
41
|
+
delegate :tax_category, :tax_category_id, to: :variant, prefix: true
|
39
42
|
delegate :currency, to: :order, allow_nil: true
|
40
43
|
|
41
44
|
attr_accessor :target_shipment, :price_currency
|
@@ -128,6 +131,24 @@ module Spree
|
|
128
131
|
Spree::Config.pricing_options_class.from_line_item(self)
|
129
132
|
end
|
130
133
|
|
134
|
+
# @return [Spree::TaxCategory] the variant's tax category
|
135
|
+
#
|
136
|
+
# This returns the variant's tax category if the tax category ID on the line_item is nil. It looks
|
137
|
+
# like an association, but really is an override.
|
138
|
+
#
|
139
|
+
def tax_category
|
140
|
+
super || variant_tax_category
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Integer] the variant's tax category ID
|
144
|
+
#
|
145
|
+
# This returns the variant's tax category ID if the tax category ID on the line_id is nil. It looks
|
146
|
+
# like an association, but really is an override.
|
147
|
+
#
|
148
|
+
def tax_category_id
|
149
|
+
super || variant_tax_category_id
|
150
|
+
end
|
151
|
+
|
131
152
|
private
|
132
153
|
|
133
154
|
# Sets the quantity to zero if it is nil or less than zero.
|