solidus_core 2.1.1 → 2.2.0.beta1

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.
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