solidus_core 2.1.1 → 2.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_core might be problematic. Click here for more details.

Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -1
  3. data/app/assets/config/solidus_core_manifest.js +1 -0
  4. data/app/assets/javascripts/spree.js.erb +72 -0
  5. data/app/helpers/spree/store_helper.rb +5 -0
  6. data/app/jobs/spree/promotion_code_batch_job.rb +24 -0
  7. data/app/mailers/spree/promotion_code_batch_mailer.rb +13 -0
  8. data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
  9. data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
  10. data/app/models/concerns/spree/user_address_book.rb +4 -4
  11. data/app/models/concerns/spree/user_methods.rb +7 -0
  12. data/app/models/concerns/spree/user_payment_source.rb +12 -5
  13. data/app/models/spree/address.rb +14 -3
  14. data/app/models/spree/adjustment.rb +13 -1
  15. data/app/models/spree/app_configuration.rb +0 -19
  16. data/app/models/spree/base.rb +2 -0
  17. data/app/models/spree/credit_card.rb +34 -43
  18. data/app/models/spree/gateway/bogus.rb +1 -1
  19. data/app/models/spree/gateway.rb +6 -4
  20. data/app/models/spree/inventory_unit.rb +3 -2
  21. data/app/models/spree/order/checkout.rb +187 -273
  22. data/app/models/spree/order.rb +137 -71
  23. data/app/models/spree/order_contents.rb +1 -1
  24. data/app/models/spree/order_inventory.rb +11 -11
  25. data/app/models/spree/order_promotion.rb +2 -0
  26. data/app/models/spree/order_update_attributes.rb +1 -8
  27. data/app/models/spree/order_updater.rb +67 -63
  28. data/app/models/spree/payment.rb +0 -1
  29. data/app/models/spree/payment_create.rb +27 -7
  30. data/app/models/spree/payment_method/store_credit.rb +3 -3
  31. data/app/models/spree/payment_method.rb +4 -1
  32. data/app/models/spree/payment_source.rb +45 -0
  33. data/app/models/spree/product/scopes.rb +24 -24
  34. data/app/models/spree/product.rb +4 -4
  35. data/app/models/spree/promotion.rb +2 -0
  36. data/app/models/spree/promotion_code/batch_builder.rb +63 -0
  37. data/app/models/spree/promotion_code.rb +1 -0
  38. data/app/models/spree/promotion_code_batch.rb +25 -0
  39. data/app/models/spree/promotion_handler/cart.rb +2 -2
  40. data/app/models/spree/promotion_handler/coupon.rb +1 -2
  41. data/app/models/spree/promotion_handler/free_shipping.rb +32 -21
  42. data/app/models/spree/promotion_handler/page.rb +1 -1
  43. data/app/models/spree/reimbursement.rb +1 -1
  44. data/app/models/spree/return_authorization.rb +0 -28
  45. data/app/models/spree/return_item.rb +1 -1
  46. data/app/models/spree/shipment.rb +4 -4
  47. data/app/models/spree/shipping_method.rb +2 -2
  48. data/app/models/spree/shipping_rate.rb +1 -1
  49. data/app/models/spree/stock/availability_validator.rb +16 -17
  50. data/app/models/spree/stock/coordinator.rb +3 -3
  51. data/app/models/spree/stock/package.rb +1 -1
  52. data/app/models/spree/stock/quantifier.rb +5 -4
  53. data/app/models/spree/stock_location.rb +2 -2
  54. data/app/models/spree/store.rb +2 -2
  55. data/app/models/spree/store_credit.rb +1 -1
  56. data/app/models/spree/tax/tax_helpers.rb +3 -3
  57. data/app/models/spree/tax_rate.rb +7 -1
  58. data/app/models/spree/taxonomy.rb +1 -1
  59. data/app/models/spree/variant/scopes.rb +5 -5
  60. data/app/models/spree/variant/vat_price_generator.rb +8 -5
  61. data/app/models/spree/variant.rb +1 -0
  62. data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +19 -10
  63. data/app/models/spree/wallet/default_payment_builder.rb +6 -6
  64. data/app/models/spree/wallet.rb +71 -0
  65. data/app/models/spree/wallet_payment_source.rb +17 -0
  66. data/app/models/spree/zone.rb +1 -1
  67. data/app/views/spree/carton_mailer/shipped_email.text.erb +1 -1
  68. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +2 -0
  69. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +2 -0
  70. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +0 -7
  71. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +0 -5
  72. data/app/views/spree/shared/_error_messages.html.erb +1 -1
  73. data/app/views/spree/shipment_mailer/shipped_email.html.erb +1 -1
  74. data/config/initializers/assets.rb +1 -1
  75. data/config/initializers/friendly_id.rb +1 -1
  76. data/config/locales/en.yml +50 -12
  77. data/db/default/spree/store_credit.rb +2 -1
  78. data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +4 -6
  79. data/db/migrate/20160420044191_create_spree_wallet_payment_sources.rb +23 -0
  80. data/db/migrate/20160420181916_migrate_credit_cards_to_wallet_payment_sources.rb +26 -0
  81. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +36 -0
  82. data/db/migrate/20161129035810_add_index_to_spree_payments_number.rb +5 -0
  83. data/db/migrate/20170223235001_remove_spree_store_credits_column.rb +5 -0
  84. data/lib/generators/spree/dummy/templates/rails/application.rb +1 -1
  85. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  86. data/lib/generators/spree/install/install_generator.rb +6 -5
  87. data/lib/spree/core/controller_helpers/payment_parameters.rb +54 -0
  88. data/lib/spree/core/engine.rb +6 -9
  89. data/lib/spree/core/version.rb +1 -1
  90. data/lib/spree/core.rb +0 -1
  91. data/lib/spree/money.rb +18 -0
  92. data/lib/spree/permission_sets/default_customer.rb +1 -1
  93. data/lib/spree/permitted_attributes.rb +1 -1
  94. data/lib/spree/testing_support/authorization_helpers.rb +1 -0
  95. data/lib/spree/testing_support/capybara_ext.rb +13 -0
  96. data/lib/spree/testing_support/factories/order_factory.rb +5 -1
  97. data/lib/spree/testing_support/factories/payment_factory.rb +1 -1
  98. data/lib/spree/testing_support/factories/shipment_factory.rb +0 -1
  99. data/solidus_core.gemspec +3 -3
  100. data/spec/jobs/promotion_code_batch_job_spec.rb +65 -0
  101. data/spec/lib/calculated_adjustments_spec.rb +105 -1
  102. data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +4 -1
  103. data/spec/lib/spree/core/testing_support/factories/payment_factory_spec.rb +8 -0
  104. data/spec/lib/spree/money_spec.rb +32 -0
  105. data/spec/lib/spree/permission_sets/default_customer_spec.rb +20 -0
  106. data/spec/mailers/promotion_code_batch_mailer_spec.rb +45 -0
  107. data/spec/models/spree/credit_card_spec.rb +86 -86
  108. data/spec/models/spree/gateway_spec.rb +3 -1
  109. data/spec/models/spree/inventory_unit_spec.rb +12 -4
  110. data/spec/models/spree/order/checkout_spec.rb +11 -32
  111. data/spec/models/spree/order/tax_spec.rb +2 -2
  112. data/spec/models/spree/order_contents_spec.rb +24 -1
  113. data/spec/models/spree/order_inventory_spec.rb +130 -83
  114. data/spec/models/spree/order_spec.rb +15 -117
  115. data/spec/models/spree/order_update_attributes_spec.rb +1 -44
  116. data/spec/models/spree/order_updater_spec.rb +10 -13
  117. data/spec/models/spree/payment_create_spec.rb +5 -1
  118. data/spec/models/spree/payment_method_spec.rb +16 -0
  119. data/spec/models/spree/payment_spec.rb +14 -8
  120. data/spec/models/spree/promotion_code/batch_builder_spec.rb +61 -0
  121. data/spec/models/spree/promotion_code_batch_spec.rb +58 -0
  122. data/spec/models/spree/promotion_code_spec.rb +4 -0
  123. data/spec/models/spree/promotion_spec.rb +3 -6
  124. data/spec/models/spree/return_authorization_spec.rb +0 -59
  125. data/spec/models/spree/shipment_spec.rb +4 -4
  126. data/spec/models/spree/stock/availability_validator_spec.rb +64 -9
  127. data/spec/models/spree/tax/item_adjuster_spec.rb +1 -2
  128. data/spec/models/spree/unit_cancel_spec.rb +0 -85
  129. data/spec/models/spree/user_spec.rb +3 -1
  130. data/spec/models/spree/variant/vat_price_generator_spec.rb +8 -2
  131. data/spec/models/spree/variant_spec.rb +16 -4
  132. data/spec/models/spree/wallet_payment_source_spec.rb +46 -0
  133. data/spec/models/spree/wallet_spec.rb +128 -0
  134. data/spec/support/concerns/payment_source.rb +64 -0
  135. metadata +51 -25
  136. data/app/assets/javascripts/spree.js.coffee.erb +0 -64
  137. data/app/models/spree/promotion_builder.rb +0 -55
  138. data/app/models/spree/promotion_code/code_builder.rb +0 -62
  139. data/config/initializers/premailer_assets.rb +0 -1
  140. data/lib/spree/core/unreturned_item_charger.rb +0 -106
  141. data/lib/tasks/exchanges.rake +0 -47
  142. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -126
  143. data/spec/lib/tasks/exchanges_spec.rb +0 -220
  144. data/spec/models/spree/promotion_builder_spec.rb +0 -120
  145. data/spec/models/spree/promotion_code/code_builder_spec.rb +0 -77
@@ -2,328 +2,242 @@ module Spree
2
2
  class Order < Spree::Base
3
3
  module Checkout
4
4
  def self.included(klass)
5
- klass.class_eval do
6
- class_attribute :next_event_transitions
7
- class_attribute :previous_states
8
- class_attribute :checkout_flow
9
- class_attribute :checkout_steps
10
- class_attribute :removed_transitions
11
-
12
- def self.checkout_flow(&block)
13
- if block_given?
14
- @checkout_flow = block
15
- define_state_machine!
16
- else
17
- @checkout_flow
18
- end
19
- end
20
-
21
- def self.define_state_machine!
22
- self.checkout_steps = {}
23
- self.next_event_transitions = []
24
- self.previous_states = [:cart]
25
- self.removed_transitions = []
26
-
27
- # Build the checkout flow using the checkout_flow defined either
28
- # within the Order class, or a decorator for that class.
29
- #
30
- # This method may be called multiple times depending on if the
31
- # checkout_flow is re-defined in a decorator or not.
32
- instance_eval(&checkout_flow)
33
-
34
- klass = self
35
-
36
- # To avoid multiple occurrences of the same transition being defined
37
- # On first definition, state_machines will not be defined
38
- state_machines.clear if respond_to?(:state_machines)
39
- state_machine :state, initial: :cart, use_transactions: false do
40
- klass.next_event_transitions.each { |t| transition(t.merge(on: :next)) }
41
-
42
- # Persist the state on the order
43
- after_transition do |order, transition|
44
- order.state = order.state
45
- order.state_changes.create(
46
- previous_state: transition.from,
47
- next_state: transition.to,
48
- name: 'order',
49
- user_id: order.user_id
50
- )
51
- order.save
52
- end
53
-
54
- event :cancel do
55
- transition to: :canceled, if: :allow_cancel?
56
- end
57
-
58
- event :return do
59
- transition to: :returned, from: [:returned, :complete, :awaiting_return, :canceled], if: :all_inventory_units_returned?
60
- end
5
+ klass.extend ClassMethods
6
+ end
61
7
 
62
- event :resume do
63
- transition to: :resumed, from: :canceled, if: :canceled?
64
- end
8
+ module ClassMethods
9
+ attr_accessor :next_event_transitions
10
+ attr_accessor :previous_states
11
+ attr_accessor :checkout_steps
12
+ attr_accessor :removed_transitions
65
13
 
66
- event :authorize_return do
67
- transition to: :awaiting_return
68
- end
14
+ def checkout_flow(&block)
15
+ if block_given?
16
+ @checkout_flow = block
17
+ define_state_machine!
18
+ else
19
+ @checkout_flow
20
+ end
21
+ end
69
22
 
70
- event :complete do
71
- transition to: :complete, from: :confirm
72
- end
23
+ def define_state_machine!
24
+ self.checkout_steps = {}
25
+ self.next_event_transitions = []
26
+ self.previous_states = [:cart]
27
+ self.removed_transitions = []
73
28
 
74
- if states[:payment]
75
- event :payment_failed do
76
- transition to: :payment, from: :confirm
77
- end
29
+ # Build the checkout flow using the checkout_flow defined either
30
+ # within the Order class, or a decorator for that class.
31
+ #
32
+ # This method may be called multiple times depending on if the
33
+ # checkout_flow is re-defined in a decorator or not.
34
+ instance_eval(&checkout_flow)
35
+
36
+ klass = self
37
+
38
+ # To avoid multiple occurrences of the same transition being defined
39
+ # On first definition, state_machines will not be defined
40
+ state_machines.clear if respond_to?(:state_machines)
41
+ state_machine :state, initial: :cart, use_transactions: false do
42
+ klass.next_event_transitions.each { |t| transition(t.merge(on: :next)) }
43
+
44
+ # Persist the state on the order
45
+ after_transition do |order, transition|
46
+ order.state = order.state
47
+ order.state_changes.create(
48
+ previous_state: transition.from,
49
+ next_state: transition.to,
50
+ name: 'order',
51
+ user_id: order.user_id
52
+ )
53
+ order.save
54
+ end
78
55
 
79
- after_transition to: :complete, do: :add_payment_sources_to_wallet
80
- before_transition to: :payment, do: :set_shipments_cost
81
- before_transition to: :payment, do: :assign_default_credit_card
56
+ event :cancel do
57
+ transition to: :canceled, if: :allow_cancel?
58
+ end
82
59
 
83
- before_transition to: :confirm, do: :add_store_credit_payments
60
+ event :return do
61
+ transition to: :returned, from: [:returned, :complete, :awaiting_return, :canceled], if: :all_inventory_units_returned?
62
+ end
84
63
 
85
- # see also process_payments_before_complete below which needs to
86
- # be added in the correct sequence.
87
- end
64
+ event :resume do
65
+ transition to: :resumed, from: :canceled, if: :canceled?
66
+ end
88
67
 
89
- before_transition from: :cart, do: :ensure_line_items_present
68
+ event :authorize_return do
69
+ transition to: :awaiting_return
70
+ end
90
71
 
91
- if states[:address]
92
- before_transition to: :address, do: :assign_default_addresses!
93
- before_transition from: :address, do: :persist_user_address!
94
- end
72
+ event :complete do
73
+ transition to: :complete, from: :confirm
74
+ end
95
75
 
96
- if states[:delivery]
97
- before_transition to: :delivery, do: :ensure_shipping_address
98
- before_transition to: :delivery, do: :create_proposed_shipments
99
- before_transition to: :delivery, do: :ensure_available_shipping_rates
100
- before_transition to: :delivery, do: :set_shipments_cost
101
- before_transition from: :delivery, do: :apply_free_shipping_promotions
76
+ if states[:payment]
77
+ event :payment_failed do
78
+ transition to: :payment, from: :confirm
102
79
  end
103
80
 
104
- before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
105
- before_transition to: :resumed, do: :validate_line_item_availability
81
+ after_transition to: :complete, do: :add_payment_sources_to_wallet
82
+ before_transition to: :payment, do: :add_default_payment_from_wallet
106
83
 
107
- # Sequence of before_transition to: :complete
108
- # calls matter so that we do not process payments
109
- # until validations have passed
110
- before_transition to: :complete, do: :validate_line_item_availability, unless: :unreturned_exchange?
111
- if states[:delivery]
112
- before_transition to: :complete, do: :ensure_available_shipping_rates
113
- end
114
- before_transition to: :complete, do: :ensure_promotions_eligible
115
- before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
116
- before_transition to: :complete, do: :ensure_inventory_units, unless: :unreturned_exchange?
117
- if states[:payment]
118
- before_transition to: :complete, do: :process_payments_before_complete
119
- end
84
+ before_transition to: :confirm, do: :add_store_credit_payments
120
85
 
121
- after_transition to: :complete, do: :finalize!
122
- after_transition to: :resumed, do: :after_resume
123
- after_transition to: :canceled, do: :after_cancel
86
+ # see also process_payments_before_complete below which needs to
87
+ # be added in the correct sequence.
88
+ end
124
89
 
125
- after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
126
- order.update_totals
127
- order.persist_totals
128
- end
90
+ before_transition from: :cart, do: :ensure_line_items_present
129
91
 
130
- after_transition do |order, transition|
131
- order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
132
- end
92
+ if states[:address]
93
+ before_transition to: :address, do: :assign_default_addresses!
94
+ before_transition from: :address, do: :persist_user_address!
95
+ end
133
96
 
134
- after_failure do |order, transition|
135
- order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
136
- end
97
+ if states[:delivery]
98
+ before_transition to: :delivery, do: :ensure_shipping_address
99
+ before_transition to: :delivery, do: :create_proposed_shipments
100
+ before_transition to: :delivery, do: :ensure_available_shipping_rates
101
+ before_transition from: :delivery, do: :apply_free_shipping_promotions
137
102
  end
138
103
 
139
- alias_method :save_state, :save
140
- end
104
+ before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
105
+ before_transition to: :resumed, do: :validate_line_item_availability
141
106
 
142
- def self.go_to_state(name, options = {})
143
- checkout_steps[name] = options
144
- previous_states.each do |state|
145
- add_transition({ from: state, to: name }.merge(options))
107
+ # Sequence of before_transition to: :complete
108
+ # calls matter so that we do not process payments
109
+ # until validations have passed
110
+ before_transition to: :complete, do: :validate_line_item_availability
111
+ if states[:delivery]
112
+ before_transition to: :complete, do: :ensure_available_shipping_rates
146
113
  end
147
- if options[:if]
148
- previous_states << name
149
- else
150
- self.previous_states = [name]
114
+ before_transition to: :complete, do: :ensure_promotions_eligible
115
+ before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
116
+ before_transition to: :complete, do: :ensure_inventory_units
117
+ if states[:payment]
118
+ before_transition to: :complete, do: :process_payments_before_complete
151
119
  end
152
- end
153
120
 
154
- def self.insert_checkout_step(name, options = {})
155
- before = options.delete(:before)
156
- after = options.delete(:after) unless before
157
- after = checkout_steps.keys.last unless before || after
158
-
159
- cloned_steps = checkout_steps.clone
160
- cloned_removed_transitions = removed_transitions.clone
161
- checkout_flow do
162
- cloned_steps.each_pair do |key, value|
163
- go_to_state(name, options) if key == before
164
- go_to_state(key, value)
165
- go_to_state(name, options) if key == after
166
- end
167
- cloned_removed_transitions.each do |transition|
168
- remove_transition(transition)
169
- end
170
- end
171
- end
121
+ after_transition to: :complete, do: :finalize!
122
+ after_transition to: :resumed, do: :after_resume
123
+ after_transition to: :canceled, do: :after_cancel
172
124
 
173
- def self.remove_checkout_step(name)
174
- cloned_steps = checkout_steps.clone
175
- cloned_removed_transitions = removed_transitions.clone
176
- checkout_flow do
177
- cloned_steps.each_pair do |key, value|
178
- go_to_state(key, value) unless key == name
179
- end
180
- cloned_removed_transitions.each do |transition|
181
- remove_transition(transition)
182
- end
125
+ after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
126
+ order.update!
183
127
  end
184
- end
185
-
186
- def self.remove_transition(options = {})
187
- removed_transitions << options
188
- next_event_transitions.delete(find_transition(options))
189
- end
190
128
 
191
- def self.find_transition(options = {})
192
- return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
193
- next_event_transitions.detect do |transition|
194
- transition[options[:from].to_sym] == options[:to].to_sym
129
+ after_transition do |order, transition|
130
+ order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
195
131
  end
196
- end
197
-
198
- def self.next_event_transitions
199
- @next_event_transitions ||= []
200
- end
201
-
202
- def self.checkout_steps
203
- @checkout_steps ||= {}
204
- end
205
132
 
206
- def self.checkout_step_names
207
- checkout_steps.keys
208
- end
209
-
210
- def self.add_transition(options)
211
- next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
212
- end
213
-
214
- def checkout_steps
215
- steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
216
- next if options.include?(:if) && !options[:if].call(self)
217
- checkout_steps << step
218
- }.map(&:to_s)
219
- # Ensure there is always a complete step
220
- steps << "complete" unless steps.include?("complete")
221
- steps
222
- end
223
-
224
- def has_checkout_step?(step)
225
- step.present? && checkout_steps.include?(step)
226
- end
227
-
228
- def passed_checkout_step?(step)
229
- has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
133
+ after_failure do |order, transition|
134
+ order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
135
+ end
230
136
  end
137
+ end
231
138
 
232
- def checkout_step_index(step)
233
- checkout_steps.index(step).to_i
139
+ def go_to_state(name, options = {})
140
+ checkout_steps[name] = options
141
+ previous_states.each do |state|
142
+ add_transition({ from: state, to: name }.merge(options))
234
143
  end
235
-
236
- def self.removed_transitions
237
- @removed_transitions ||= []
144
+ if options[:if]
145
+ previous_states << name
146
+ else
147
+ self.previous_states = [name]
238
148
  end
149
+ end
239
150
 
240
- def can_go_to_state?(state)
241
- return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
242
- checkout_step_index(state) > checkout_step_index(self.state)
151
+ def insert_checkout_step(name, options = {})
152
+ before = options.delete(:before)
153
+ after = options.delete(:after) unless before
154
+ after = checkout_steps.keys.last unless before || after
155
+
156
+ cloned_steps = checkout_steps.clone
157
+ cloned_removed_transitions = removed_transitions.clone
158
+ checkout_flow do
159
+ cloned_steps.each_pair do |key, value|
160
+ go_to_state(name, options) if key == before
161
+ go_to_state(key, value)
162
+ go_to_state(name, options) if key == after
163
+ end
164
+ cloned_removed_transitions.each do |transition|
165
+ remove_transition(transition)
166
+ end
243
167
  end
168
+ end
244
169
 
245
- def bill_address_attributes=(attributes)
246
- self.bill_address = Address.immutable_merge(bill_address, attributes)
170
+ def remove_checkout_step(name)
171
+ cloned_steps = checkout_steps.clone
172
+ cloned_removed_transitions = removed_transitions.clone
173
+ checkout_flow do
174
+ cloned_steps.each_pair do |key, value|
175
+ go_to_state(key, value) unless key == name
176
+ end
177
+ cloned_removed_transitions.each do |transition|
178
+ remove_transition(transition)
179
+ end
247
180
  end
181
+ end
248
182
 
249
- def ship_address_attributes=(attributes)
250
- self.ship_address = Address.immutable_merge(ship_address, attributes)
251
- end
183
+ def remove_transition(options = {})
184
+ removed_transitions << options
185
+ next_event_transitions.delete(find_transition(options))
186
+ end
252
187
 
253
- def assign_default_addresses!
254
- if user
255
- # this is one of 2 places still using User#bill_address
256
- self.bill_address ||= user.bill_address if user.bill_address.try!(:valid?)
257
- # Skip setting ship address if order doesn't have a delivery checkout step
258
- # to avoid triggering validations on shipping address
259
- self.ship_address ||= user.ship_address if user.ship_address.try!(:valid?) && checkout_steps.include?("delivery")
260
- end
188
+ def find_transition(options = {})
189
+ return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
190
+ next_event_transitions.detect do |transition|
191
+ transition[options[:from].to_sym] == options[:to].to_sym
261
192
  end
193
+ end
262
194
 
263
- def persist_user_address!
264
- if !temporary_address && user && user.respond_to?(:persist_order_address) && bill_address_id
265
- user.persist_order_address(self)
266
- end
267
- end
195
+ def next_event_transitions
196
+ @next_event_transitions ||= []
197
+ end
268
198
 
269
- def add_payment_sources_to_wallet
270
- Spree::Config.
271
- add_payment_sources_to_wallet_class.new(self).
272
- add_to_wallet
273
- end
274
- alias_method :persist_user_credit_card, :add_payment_sources_to_wallet
275
- deprecate :persist_user_credit_card
199
+ def checkout_steps
200
+ @checkout_steps ||= {}
201
+ end
276
202
 
277
- def assign_default_credit_card
278
- builder = Spree::Config.default_payment_builder_class.new(self)
203
+ def checkout_step_names
204
+ checkout_steps.keys
205
+ end
279
206
 
280
- if payment = builder.build
281
- payments << payment
207
+ def add_transition(options)
208
+ next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
209
+ end
282
210
 
283
- if bill_address.nil?
284
- # this is one of 2 places still using User#bill_address
285
- self.bill_address = payment.source.try(:address) ||
286
- user.bill_address
287
- end
288
- end
289
- end
211
+ def removed_transitions
212
+ @removed_transitions ||= []
213
+ end
214
+ end
290
215
 
291
- private
216
+ def checkout_steps
217
+ steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
218
+ next if options.include?(:if) && !options[:if].call(self)
219
+ checkout_steps << step
220
+ }.map(&:to_s)
221
+ # Ensure there is always a complete step
222
+ steps << "complete" unless steps.include?("complete")
223
+ steps
224
+ end
292
225
 
293
- def process_payments_before_complete
294
- return if !payment_required?
226
+ def has_checkout_step?(step)
227
+ step.present? && checkout_steps.include?(step)
228
+ end
295
229
 
296
- if payments.valid.empty?
297
- errors.add(:base, Spree.t(:no_payment_found))
298
- return false
299
- end
230
+ def passed_checkout_step?(step)
231
+ has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
232
+ end
300
233
 
301
- if process_payments!
302
- true
303
- else
304
- saved_errors = errors[:base]
305
- payment_failed!
306
- saved_errors.each { |error| errors.add(:base, error) }
307
- false
308
- end
309
- end
234
+ def checkout_step_index(step)
235
+ checkout_steps.index(step).to_i
236
+ end
310
237
 
311
- # In case a existing credit card is provided it needs to build the payment
312
- # attributes from scratch so we can set the amount. example payload:
313
- #
314
- # {
315
- # "order": {
316
- # "existing_card": "2"
317
- # }
318
- # }
319
- #
320
- def update_params_payment_source
321
- if @updating_params[:order] && (@updating_params[:order][:payments_attributes] || @updating_params[:order][:existing_card])
322
- @updating_params[:order][:payments_attributes] ||= [{}]
323
- @updating_params[:order][:payments_attributes].first[:amount] = total
324
- end
325
- end
326
- end
238
+ def can_go_to_state?(state)
239
+ return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
240
+ checkout_step_index(state) > checkout_step_index(self.state)
327
241
  end
328
242
  end
329
243
  end