spree_core 3.0.5 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,267 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::LineItem, :type => :model do
4
+ let(:order) { create :order_with_line_items, line_items_count: 1 }
5
+ let(:line_item) { order.line_items.first }
6
+
7
+ before { create(:store) }
8
+
9
+ context '#save' do
10
+ it 'touches the order' do
11
+ expect(line_item.order).to receive(:touch)
12
+ line_item.touch
13
+ end
14
+ end
15
+
16
+ context '#destroy' do
17
+ it "fetches deleted products" do
18
+ line_item.product.destroy
19
+ expect(line_item.reload.product).to be_a Spree::Product
20
+ end
21
+
22
+ it "fetches deleted variants" do
23
+ line_item.variant.destroy
24
+ expect(line_item.reload.variant).to be_a Spree::Variant
25
+ end
26
+
27
+ it "returns inventory when a line item is destroyed" do
28
+ expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
29
+ line_item.destroy
30
+ end
31
+
32
+ it "deletes inventory units" do
33
+ expect { line_item.destroy }.to change { line_item.inventory_units.count }.from(1).to(0)
34
+ end
35
+ end
36
+
37
+ context "#save" do
38
+ context "line item changes" do
39
+ before do
40
+ line_item.quantity = line_item.quantity + 1
41
+ end
42
+
43
+ it "triggers adjustment total recalculation" do
44
+ expect(line_item).to receive(:update_tax_charge) # Regression test for https://github.com/spree/spree/issues/4671
45
+ expect(line_item).to receive(:recalculate_adjustments)
46
+ line_item.save
47
+ end
48
+ end
49
+
50
+ context "line item does not change" do
51
+ it "does not trigger adjustment total recalculation" do
52
+ expect(line_item).not_to receive(:recalculate_adjustments)
53
+ line_item.save
54
+ end
55
+ end
56
+
57
+ context "target_shipment is provided" do
58
+ it "verifies inventory" do
59
+ line_item.target_shipment = Spree::Shipment.new
60
+ expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
61
+ line_item.save
62
+ end
63
+ end
64
+ end
65
+
66
+ context "#create" do
67
+ let(:variant) { create(:variant) }
68
+
69
+ before do
70
+ create(:tax_rate, :zone => order.tax_zone, :tax_category => variant.tax_category)
71
+ end
72
+
73
+ context "when order has a tax zone" do
74
+ before do
75
+ expect(order.tax_zone).to be_present
76
+ end
77
+
78
+ it "creates a tax adjustment" do
79
+ order.contents.add(variant)
80
+ line_item = order.find_line_item_by_variant(variant)
81
+ expect(line_item.adjustments.tax.count).to eq(1)
82
+ end
83
+ end
84
+
85
+ context "when order does not have a tax zone" do
86
+ before do
87
+ order.bill_address = nil
88
+ order.ship_address = nil
89
+ order.save
90
+ expect(order.reload.tax_zone).to be_nil
91
+ end
92
+
93
+ it "does not create a tax adjustment" do
94
+ order.contents.add(variant)
95
+ line_item = order.find_line_item_by_variant(variant)
96
+ expect(line_item.adjustments.tax.count).to eq(0)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Test for #3391
102
+ context '#copy_price' do
103
+ it "copies over a variant's prices" do
104
+ line_item.price = nil
105
+ line_item.cost_price = nil
106
+ line_item.currency = nil
107
+ line_item.copy_price
108
+ variant = line_item.variant
109
+ expect(line_item.price).to eq(variant.price)
110
+ expect(line_item.cost_price).to eq(variant.cost_price)
111
+ expect(line_item.currency).to eq(variant.currency)
112
+ end
113
+ end
114
+
115
+ # Test for #3481
116
+ context '#copy_tax_category' do
117
+ it "copies over a variant's tax category" do
118
+ line_item.tax_category = nil
119
+ line_item.copy_tax_category
120
+ expect(line_item.tax_category).to eq(line_item.variant.tax_category)
121
+ end
122
+ end
123
+
124
+ describe '.discounted_amount' do
125
+ it "returns the amount minus any discounts" do
126
+ line_item.price = 10
127
+ line_item.quantity = 2
128
+ line_item.promo_total = -5
129
+ expect(line_item.discounted_amount).to eq(15)
130
+ end
131
+ end
132
+
133
+ describe "#discounted_money" do
134
+ it "should return a money object with the discounted amount" do
135
+ expect(line_item.discounted_money.to_s).to eq "$10.00"
136
+ end
137
+ end
138
+
139
+ describe '.currency' do
140
+ it 'returns the globally configured currency' do
141
+ line_item.currency == 'USD'
142
+ end
143
+ end
144
+
145
+ describe ".money" do
146
+ before do
147
+ line_item.price = 3.50
148
+ line_item.quantity = 2
149
+ end
150
+
151
+ it "returns a Spree::Money representing the total for this line item" do
152
+ expect(line_item.money.to_s).to eq("$7.00")
153
+ end
154
+ end
155
+
156
+ describe '.single_money' do
157
+ before { line_item.price = 3.50 }
158
+ it "returns a Spree::Money representing the price for one variant" do
159
+ expect(line_item.single_money.to_s).to eq("$3.50")
160
+ end
161
+ end
162
+
163
+ context "has inventory (completed order so items were already unstocked)" do
164
+ let(:order) { Spree::Order.create(email: 'spree@example.com') }
165
+ let(:variant) { create(:variant) }
166
+
167
+ context "nothing left on stock" do
168
+ before do
169
+ variant.stock_items.update_all count_on_hand: 5, backorderable: false
170
+ order.contents.add(variant, 5)
171
+ order.create_proposed_shipments
172
+ order.finalize!
173
+ end
174
+
175
+ it "allows to decrease item quantity" do
176
+ line_item = order.line_items.first
177
+ line_item.quantity -= 1
178
+ line_item.target_shipment = order.shipments.first
179
+
180
+ line_item.save
181
+ expect(line_item.errors_on(:quantity).size).to eq(0)
182
+ end
183
+
184
+ it "doesnt allow to increase item quantity" do
185
+ line_item = order.line_items.first
186
+ line_item.quantity += 2
187
+ line_item.target_shipment = order.shipments.first
188
+
189
+ line_item.save
190
+ expect(line_item.errors_on(:quantity).size).to eq(1)
191
+ end
192
+ end
193
+
194
+ context "2 items left on stock" do
195
+ before do
196
+ variant.stock_items.update_all count_on_hand: 7, backorderable: false
197
+ order.contents.add(variant, 5)
198
+ order.create_proposed_shipments
199
+ order.finalize!
200
+ end
201
+
202
+ it "allows to increase quantity up to stock availability" do
203
+ line_item = order.line_items.first
204
+ line_item.quantity += 2
205
+ line_item.target_shipment = order.shipments.first
206
+
207
+ line_item.save
208
+ expect(line_item.errors_on(:quantity).size).to eq(0)
209
+ end
210
+
211
+ it "doesnt allow to increase quantity over stock availability" do
212
+ line_item = order.line_items.first
213
+ line_item.quantity += 3
214
+ line_item.target_shipment = order.shipments.first
215
+
216
+ line_item.save
217
+ expect(line_item.errors_on(:quantity).size).to eq(1)
218
+ end
219
+ end
220
+ end
221
+
222
+ context "currency same as order.currency" do
223
+ it "is a valid line item" do
224
+ line_item = order.line_items.first
225
+ line_item.currency = order.currency
226
+ line_item.valid?
227
+
228
+ expect(line_item.error_on(:currency).size).to eq(0)
229
+ end
230
+ end
231
+
232
+ context "currency different than order.currency" do
233
+ it "is not a valid line item" do
234
+ line_item = order.line_items.first
235
+ line_item.currency = "no currency"
236
+ line_item.valid?
237
+
238
+ expect(line_item.error_on(:currency).size).to eq(1)
239
+ end
240
+ end
241
+
242
+ describe "#options=" do
243
+ it "can handle updating a blank line item with no order" do
244
+ line_item.options = { price: 123 }
245
+ end
246
+
247
+ it "updates the data provided in the options" do
248
+ line_item.options = { price: 123 }
249
+ expect(line_item.price).to eq 123
250
+ end
251
+
252
+ it "updates the price based on the options provided" do
253
+ expect(line_item).to receive(:gift_wrap=).with(true)
254
+ expect(line_item.variant).to receive(:gift_wrap_price_modifier_amount_in).with("USD", true).and_return 1.99
255
+ line_item.options = { gift_wrap: true }
256
+ expect(line_item.price).to eq 21.98
257
+ end
258
+ end
259
+
260
+ describe "precision of pre_tax_amount" do
261
+ let!(:line_item) { create :line_item, pre_tax_amount: 4.2051 }
262
+
263
+ it "keeps four digits of precision even when reloading" do
264
+ expect(line_item.reload.pre_tax_amount).to eq(4.2051)
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OptionType, :type => :model do
4
+ context "touching" do
5
+ it "should touch a product" do
6
+ product_option_type = create(:product_option_type)
7
+ option_type = product_option_type.option_type
8
+ product = product_option_type.product
9
+ product.update_column(:updated_at, 1.day.ago)
10
+ option_type.touch
11
+ expect(product.reload.updated_at).to be_within(3.seconds).of(Time.now)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OptionValue, :type => :model do
4
+ context "touching" do
5
+ it "should touch a variant" do
6
+ variant = create(:variant)
7
+ option_value = variant.option_values.first
8
+ variant.update_column(:updated_at, 1.day.ago)
9
+ option_value.touch
10
+ expect(variant.reload.updated_at).to be_within(3.seconds).of(Time.now)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Order, :type => :model do
4
+ let(:order) { Spree::Order.new }
5
+
6
+ context 'validation' do
7
+ context "when @use_billing is populated" do
8
+ before do
9
+ order.bill_address = stub_model(Spree::Address)
10
+ order.ship_address = nil
11
+ end
12
+
13
+ context "with true" do
14
+ before { order.use_billing = true }
15
+
16
+ it "clones the bill address to the ship address" do
17
+ order.valid?
18
+ expect(order.ship_address).to eq(order.bill_address)
19
+ end
20
+ end
21
+
22
+ context "with 'true'" do
23
+ before { order.use_billing = 'true' }
24
+
25
+ it "clones the bill address to the shipping" do
26
+ order.valid?
27
+ expect(order.ship_address).to eq(order.bill_address)
28
+ end
29
+ end
30
+
31
+ context "with '1'" do
32
+ before { order.use_billing = '1' }
33
+
34
+ it "clones the bill address to the shipping" do
35
+ order.valid?
36
+ expect(order.ship_address).to eq(order.bill_address)
37
+ end
38
+ end
39
+
40
+ context "with something other than a 'truthful' value" do
41
+ before { order.use_billing = '0' }
42
+
43
+ it "does not clone the bill address to the shipping" do
44
+ order.valid?
45
+ expect(order.ship_address).to be_nil
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Order do
4
+ context "when an order has an adjustment that zeroes the total, but another adjustment for shipping that raises it above zero" do
5
+ let!(:persisted_order) { create(:order) }
6
+ let!(:line_item) { create(:line_item) }
7
+ let!(:shipping_method) do
8
+ sm = create(:shipping_method)
9
+ sm.calculator.preferred_amount = 10
10
+ sm.save
11
+ sm
12
+ end
13
+
14
+ before do
15
+ # Don't care about available payment methods in this test
16
+ allow(persisted_order).to receive_messages(:has_available_payment => false)
17
+ persisted_order.line_items << line_item
18
+ create(:adjustment, amount: -line_item.amount, label: "Promotion", adjustable: line_item, order: persisted_order)
19
+ persisted_order.state = 'delivery'
20
+ persisted_order.save # To ensure new state_change event
21
+ end
22
+
23
+ it "transitions from delivery to payment" do
24
+ allow(persisted_order).to receive_messages(payment_required?: true)
25
+ persisted_order.next!
26
+ expect(persisted_order.state).to eq("payment")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Order, :type => :model do
4
+ let(:order) { stub_model(Spree::Order) }
5
+ before do
6
+ Spree::Order.define_state_machine!
7
+ end
8
+
9
+ context "validations" do
10
+ context "email validation" do
11
+ # Regression test for #1238
12
+ it "o'brien@gmail.com is a valid email address" do
13
+ order.state = 'address'
14
+ order.email = "o'brien@gmail.com"
15
+ expect(order.error_on(:email).size).to eq(0)
16
+ end
17
+ end
18
+ end
19
+
20
+ context "#save" do
21
+ context "when associated with a registered user" do
22
+ let(:user) { double(:user, :email => "test@example.com") }
23
+
24
+ before do
25
+ allow(order).to receive_messages :user => user
26
+ end
27
+
28
+ it "should assign the email address of the user" do
29
+ order.run_callbacks(:create)
30
+ expect(order.email).to eq(user.email)
31
+ end
32
+ end
33
+ end
34
+
35
+ context "in the cart state" do
36
+ it "should not validate email address" do
37
+ order.state = "cart"
38
+ order.email = nil
39
+ expect(order.error_on(:email).size).to eq(0)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,764 @@
1
+ require 'spec_helper'
2
+ require 'spree/testing_support/order_walkthrough'
3
+
4
+ describe Spree::Order, :type => :model do
5
+ let(:order) { Spree::Order.new }
6
+
7
+ before { create(:store) }
8
+
9
+ def assert_state_changed(order, from, to)
10
+ state_change_exists = order.state_changes.where(:previous_state => from, :next_state => to).exists?
11
+ assert state_change_exists, "Expected order to transition from #{from} to #{to}, but didn't."
12
+ end
13
+
14
+ context "with default state machine" do
15
+ let(:transitions) do
16
+ [
17
+ { :address => :delivery },
18
+ { :delivery => :payment },
19
+ { :payment => :confirm },
20
+ { :confirm => :complete },
21
+ { :payment => :complete },
22
+ { :delivery => :complete }
23
+ ]
24
+ end
25
+
26
+ it "has the following transitions" do
27
+ transitions.each do |transition|
28
+ transition = Spree::Order.find_transition(:from => transition.keys.first, :to => transition.values.first)
29
+ expect(transition).not_to be_nil
30
+ end
31
+ end
32
+
33
+ it "does not have a transition from delivery to confirm" do
34
+ transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
35
+ expect(transition).to be_nil
36
+ end
37
+
38
+ it '.find_transition when contract was broken' do
39
+ expect(Spree::Order.find_transition({foo: :bar, baz: :dog})).to be_falsey
40
+ end
41
+
42
+ it '.remove_transition' do
43
+ options = {:from => transitions.first.keys.first, :to => transitions.first.values.first}
44
+ expect(Spree::Order).to receive_messages(
45
+ removed_transitions: [],
46
+ next_event_transitions: transitions.dup
47
+ )
48
+ expect(Spree::Order.remove_transition(options)).to be_truthy
49
+ expect(Spree::Order.removed_transitions).to eql([options])
50
+ expect(Spree::Order.next_event_transitions).to_not include(transitions.first)
51
+ end
52
+
53
+ it '.remove_transition when contract was broken' do
54
+ expect(Spree::Order.remove_transition(nil)).to be_falsey
55
+ end
56
+
57
+ it "always return integer on checkout_step_index" do
58
+ expect(order.checkout_step_index("imnotthere")).to be_a Integer
59
+ expect(order.checkout_step_index("delivery")).to be > 0
60
+ end
61
+
62
+ it "passes delivery state when transitioning from address over delivery to payment" do
63
+ allow(order).to receive_messages :payment_required? => true
64
+ order.state = "address"
65
+ expect(order.passed_checkout_step?("delivery")).to be false
66
+ order.state = "delivery"
67
+ expect(order.passed_checkout_step?("delivery")).to be false
68
+ order.state = "payment"
69
+ expect(order.passed_checkout_step?("delivery")).to be true
70
+ end
71
+
72
+ context "#checkout_steps" do
73
+ context "when confirmation not required" do
74
+ before do
75
+ allow(order).to receive_messages :confirmation_required? => false
76
+ allow(order).to receive_messages :payment_required? => true
77
+ end
78
+
79
+ specify do
80
+ expect(order.checkout_steps).to eq(%w(address delivery payment complete))
81
+ end
82
+ end
83
+
84
+ context "when confirmation required" do
85
+ before do
86
+ allow(order).to receive_messages :confirmation_required? => true
87
+ allow(order).to receive_messages :payment_required? => true
88
+ end
89
+
90
+ specify do
91
+ expect(order.checkout_steps).to eq(%w(address delivery payment confirm complete))
92
+ end
93
+ end
94
+
95
+ context "when payment not required" do
96
+ before { allow(order).to receive_messages :payment_required? => false }
97
+ specify do
98
+ expect(order.checkout_steps).to eq(%w(address delivery complete))
99
+ end
100
+ end
101
+
102
+ context "when payment required" do
103
+ before { allow(order).to receive_messages :payment_required? => true }
104
+ specify do
105
+ expect(order.checkout_steps).to eq(%w(address delivery payment complete))
106
+ end
107
+ end
108
+ end
109
+
110
+ it "starts out at cart" do
111
+ expect(order.state).to eq("cart")
112
+ end
113
+
114
+ context "to address" do
115
+ before do
116
+ order.email = "user@example.com"
117
+ order.save!
118
+ end
119
+
120
+ context "with a line item" do
121
+ before do
122
+ order.line_items << FactoryGirl.create(:line_item)
123
+ end
124
+
125
+ it "transitions to address" do
126
+ order.next!
127
+ assert_state_changed(order, 'cart', 'address')
128
+ expect(order.state).to eq("address")
129
+ end
130
+
131
+ it "doesn't raise an error if the default address is invalid" do
132
+ order.user = mock_model(Spree::LegacyUser, ship_address: Spree::Address.new, bill_address: Spree::Address.new)
133
+ expect { order.next! }.to_not raise_error
134
+ end
135
+
136
+ context "with default addresses" do
137
+ let(:default_address) { FactoryGirl.create(:address) }
138
+
139
+ before do
140
+ order.user = FactoryGirl.create(:user, "#{address_kind}_address" => default_address)
141
+ order.next!
142
+ order.reload
143
+ end
144
+
145
+ shared_examples "it cloned the default address" do
146
+ it do
147
+ default_attributes = default_address.attributes
148
+ order_attributes = order.send("#{address_kind}_address".to_sym).try(:attributes) || {}
149
+
150
+ expect(order_attributes.except('id', 'created_at', 'updated_at')).to eql(default_attributes.except('id', 'created_at', 'updated_at'))
151
+ end
152
+ end
153
+
154
+ it_behaves_like "it cloned the default address" do
155
+ let(:address_kind) { 'ship' }
156
+ end
157
+
158
+ it_behaves_like "it cloned the default address" do
159
+ let(:address_kind) { 'bill' }
160
+ end
161
+ end
162
+ end
163
+
164
+ it "cannot transition to address without any line items" do
165
+ expect(order.line_items).to be_blank
166
+ expect { order.next! }.to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:there_are_no_items_for_this_order)}/)
167
+ end
168
+ end
169
+
170
+ context "from address" do
171
+ before do
172
+ order.state = 'address'
173
+ allow(order).to receive(:has_available_payment)
174
+ shipment = FactoryGirl.create(:shipment, :order => order)
175
+ order.email = "user@example.com"
176
+ order.save!
177
+ end
178
+
179
+ it "updates totals" do
180
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
181
+ line_item = FactoryGirl.create(:line_item, :price => 10, :adjustment_total => 10)
182
+ order.line_items << line_item
183
+ tax_rate = create(:tax_rate, :tax_category => line_item.tax_category, :amount => 0.05)
184
+ allow(Spree::TaxRate).to receive_messages :match => [tax_rate]
185
+ FactoryGirl.create(:tax_adjustment, :adjustable => line_item, :source => tax_rate, order: order)
186
+ order.email = "user@example.com"
187
+ order.next!
188
+ expect(order.adjustment_total).to eq(0.5)
189
+ expect(order.additional_tax_total).to eq(0.5)
190
+ expect(order.included_tax_total).to eq(0)
191
+ expect(order.total).to eq(10.5)
192
+ end
193
+
194
+ it "transitions to delivery" do
195
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
196
+ order.next!
197
+ assert_state_changed(order, 'address', 'delivery')
198
+ expect(order.state).to eq("delivery")
199
+ end
200
+
201
+ it "does not call persist_order_address if there is no address on the order" do
202
+ # otherwise, it will crash
203
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
204
+
205
+ order.user = FactoryGirl.create(:user)
206
+ order.save!
207
+
208
+ expect(order.user).to_not receive(:persist_order_address).with(order)
209
+ order.next!
210
+ end
211
+
212
+ it "calls persist_order_address on the order's user" do
213
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
214
+
215
+ order.user = FactoryGirl.create(:user)
216
+ order.ship_address = FactoryGirl.create(:address)
217
+ order.bill_address = FactoryGirl.create(:address)
218
+ order.save!
219
+
220
+ expect(order.user).to receive(:persist_order_address).with(order)
221
+ order.next!
222
+ end
223
+
224
+ it "does not call persist_order_address on the order's user for a temporary address" do
225
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
226
+
227
+ order.user = FactoryGirl.create(:user)
228
+ order.temporary_address = true
229
+ order.save!
230
+
231
+ expect(order.user).to_not receive(:persist_order_address)
232
+ order.next!
233
+ end
234
+
235
+ context "cannot transition to delivery" do
236
+ context "with an existing shipment" do
237
+ before do
238
+ line_item = FactoryGirl.create(:line_item, :price => 10)
239
+ order.line_items << line_item
240
+ end
241
+
242
+ context "if there are no shipping rates for any shipment" do
243
+ it "raises an InvalidTransitionError" do
244
+ transition = lambda { order.next! }
245
+ expect(transition).to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:items_cannot_be_shipped)}/)
246
+ end
247
+
248
+ it "deletes all the shipments" do
249
+ order.next
250
+ expect(order.shipments).to be_empty
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ context "to delivery" do
258
+ context 'when order has default selected_shipping_rate_id' do
259
+ let(:shipment) { create(:shipment, order: order) }
260
+ let(:shipping_method) { create(:shipping_method) }
261
+ let(:shipping_rate) { [
262
+ Spree::ShippingRate.create!(shipping_method: shipping_method, cost: 10.00, shipment: shipment)
263
+ ] }
264
+
265
+ before do
266
+ order.state = 'address'
267
+ shipment.selected_shipping_rate_id = shipping_rate.first.id
268
+ order.email = "user@example.com"
269
+ order.save!
270
+
271
+ allow(order).to receive(:has_available_payment)
272
+ allow(order).to receive(:create_proposed_shipments)
273
+ allow(order).to receive(:ensure_available_shipping_rates) { true }
274
+ end
275
+
276
+ it 'should invoke set_shipment_cost' do
277
+ expect(order).to receive(:set_shipments_cost)
278
+ order.next!
279
+ end
280
+
281
+ it 'should update shipment_total' do
282
+ expect { order.next! }.to change{ order.shipment_total }.by(10.00)
283
+ end
284
+ end
285
+ end
286
+
287
+ context "from delivery" do
288
+ before do
289
+ order.state = 'delivery'
290
+ allow(order).to receive(:apply_free_shipping_promotions)
291
+ end
292
+
293
+ it "attempts to apply free shipping promotions" do
294
+ expect(order).to receive(:apply_free_shipping_promotions)
295
+ order.next!
296
+ end
297
+
298
+ context "with payment required" do
299
+ before do
300
+ allow(order).to receive_messages :payment_required? => true
301
+ end
302
+
303
+ it "transitions to payment" do
304
+ expect(order).to receive(:set_shipments_cost)
305
+ order.next!
306
+ assert_state_changed(order, 'delivery', 'payment')
307
+ expect(order.state).to eq('payment')
308
+ end
309
+ end
310
+
311
+ context "without payment required" do
312
+ before do
313
+ allow(order).to receive_messages :payment_required? => false
314
+ end
315
+
316
+ it "transitions to complete" do
317
+ order.next!
318
+ expect(order.state).to eq("complete")
319
+ end
320
+ end
321
+
322
+ context "correctly determining payment required based on shipping information" do
323
+ let(:shipment) do
324
+ FactoryGirl.create(:shipment)
325
+ end
326
+
327
+ before do
328
+ # Needs to be set here because we're working with a persisted order object
329
+ order.email = "test@example.com"
330
+ order.save!
331
+ order.shipments << shipment
332
+ end
333
+
334
+ context "with a shipment that has a price" do
335
+ before do
336
+ shipment.shipping_rates.first.update_column(:cost, 10)
337
+ order.set_shipments_cost
338
+ end
339
+
340
+ it "transitions to payment" do
341
+ order.next!
342
+ expect(order.state).to eq("payment")
343
+ end
344
+ end
345
+
346
+ context "with a shipment that is free" do
347
+ before do
348
+ shipment.shipping_rates.first.update_column(:cost, 0)
349
+ order.set_shipments_cost
350
+ end
351
+
352
+ it "skips payment, transitions to complete" do
353
+ order.next!
354
+ expect(order.state).to eq("complete")
355
+ end
356
+ end
357
+ end
358
+ end
359
+
360
+ context "to payment" do
361
+ before do
362
+ @default_credit_card = FactoryGirl.create(:credit_card)
363
+ order.user = mock_model(Spree::LegacyUser, default_credit_card: @default_credit_card, email: 'spree@example.org')
364
+
365
+ allow(order).to receive_messages(payment_required?: true)
366
+ allow(order).to receive_messages(total: 20.00)
367
+ order.state = 'delivery'
368
+ order.save!
369
+ end
370
+
371
+ it "assigns the user's default credit card" do
372
+ order.next!
373
+ order.reload
374
+
375
+ expect(order.state).to eq 'payment'
376
+ expect(order.payments.count).to eq 1
377
+ expect(order.payments.first.amount).to eq 20.00
378
+ expect(order.payments.first.source).to eq @default_credit_card
379
+ end
380
+
381
+ it "only generates payment if payment required" do
382
+ allow(order).to receive_messages(payment_required?: false)
383
+ order.next!
384
+ order.reload
385
+
386
+ expect(order.state).to eq 'complete'
387
+ expect(order.payments.count).to eq 0
388
+ end
389
+ end
390
+
391
+ context "from payment" do
392
+ before do
393
+ order.state = 'payment'
394
+ end
395
+
396
+ context "with confirmation required" do
397
+ before do
398
+ allow(order).to receive_messages :confirmation_required? => true
399
+ end
400
+
401
+ it "transitions to confirm" do
402
+ order.next!
403
+ assert_state_changed(order, 'payment', 'confirm')
404
+ expect(order.state).to eq("confirm")
405
+ end
406
+ end
407
+
408
+ context "without confirmation required" do
409
+ before do
410
+ order.email = "spree@example.com"
411
+ allow(order).to receive_messages :confirmation_required? => false
412
+ allow(order).to receive_messages :payment_required? => true
413
+ order.payments << FactoryGirl.create(:payment, state: payment_state, order: order)
414
+ end
415
+
416
+ context 'when there is at least one valid payment' do
417
+ let(:payment_state) { 'checkout' }
418
+
419
+ before do
420
+ expect(order).to receive(:process_payments!).once { true }
421
+ end
422
+
423
+ it "transitions to complete" do
424
+ order.next!
425
+ assert_state_changed(order, 'payment', 'complete')
426
+ expect(order.state).to eq('complete')
427
+ end
428
+ end
429
+
430
+ context 'when there is only an invalid payment' do
431
+ let(:payment_state) { 'failed' }
432
+
433
+ it "raises a StateMachine::InvalidTransition" do
434
+ expect {
435
+ order.next!
436
+ }.to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:no_payment_found)}/)
437
+
438
+ expect(order.errors[:base]).to include(Spree.t(:no_payment_found))
439
+ end
440
+ end
441
+ end
442
+
443
+ # Regression test for #2028
444
+ context "when payment is not required" do
445
+ before do
446
+ allow(order).to receive_messages :payment_required? => false
447
+ end
448
+
449
+ it "does not call process payments" do
450
+ expect(order).not_to receive(:process_payments!)
451
+ order.next!
452
+ assert_state_changed(order, 'payment', 'complete')
453
+ expect(order.state).to eq("complete")
454
+ end
455
+ end
456
+ end
457
+ end
458
+
459
+ context "to complete" do
460
+ before do
461
+ order.state = 'confirm'
462
+ order.save!
463
+ end
464
+
465
+ context "default credit card" do
466
+ before do
467
+ order.user = FactoryGirl.create(:user)
468
+ order.email = 'spree@example.org'
469
+ order.payments << FactoryGirl.create(:payment)
470
+
471
+ # make sure we will actually capture a payment
472
+ allow(order).to receive_messages(payment_required?: true)
473
+ order.line_items << FactoryGirl.create(:line_item)
474
+ Spree::OrderUpdater.new(order).update
475
+
476
+ order.save!
477
+ end
478
+
479
+ it "makes the current credit card a user's default credit card" do
480
+ order.next!
481
+ expect(order.state).to eq 'complete'
482
+ expect(order.user.reload.default_credit_card.try(:id)).to eq(order.credit_cards.first.id)
483
+ end
484
+
485
+ it "does not assign a default credit card if temporary_credit_card is set" do
486
+ order.temporary_credit_card = true
487
+ order.next!
488
+ expect(order.user.reload.default_credit_card).to be_nil
489
+ end
490
+ end
491
+ end
492
+
493
+ context "subclassed order" do
494
+ # This causes another test above to fail, but fixing this test should make
495
+ # the other test pass
496
+ class SubclassedOrder < Spree::Order
497
+ checkout_flow do
498
+ go_to_state :payment
499
+ go_to_state :complete
500
+ end
501
+ end
502
+
503
+ skip "should only call default transitions once when checkout_flow is redefined" do
504
+ order = SubclassedOrder.new
505
+ allow(order).to receive_messages :payment_required? => true
506
+ expect(order).to receive(:process_payments!).once
507
+ order.state = "payment"
508
+ order.next!
509
+ assert_state_changed(order, 'payment', 'complete')
510
+ expect(order.state).to eq("complete")
511
+ end
512
+ end
513
+
514
+ context "re-define checkout flow" do
515
+ before do
516
+ @old_checkout_flow = Spree::Order.checkout_flow
517
+ Spree::Order.class_eval do
518
+ checkout_flow do
519
+ go_to_state :payment
520
+ go_to_state :complete
521
+ end
522
+ end
523
+ end
524
+
525
+ after do
526
+ Spree::Order.checkout_flow(&@old_checkout_flow)
527
+ end
528
+
529
+ it "should not keep old event transitions when checkout_flow is redefined" do
530
+ expect(Spree::Order.next_event_transitions).to eq([{:cart=>:payment}, {:payment=>:complete}])
531
+ end
532
+
533
+ it "should not keep old events when checkout_flow is redefined" do
534
+ state_machine = Spree::Order.state_machine
535
+ expect(state_machine.states.any? { |s| s.name == :address }).to be false
536
+ known_states = state_machine.events[:next].branches.map(&:known_states).flatten
537
+ expect(known_states).not_to include(:address)
538
+ expect(known_states).not_to include(:delivery)
539
+ expect(known_states).not_to include(:confirm)
540
+ end
541
+ end
542
+
543
+ # Regression test for #3665
544
+ context "with only a complete step" do
545
+ before do
546
+ @old_checkout_flow = Spree::Order.checkout_flow
547
+ Spree::Order.class_eval do
548
+ checkout_flow do
549
+ go_to_state :complete
550
+ end
551
+ end
552
+ end
553
+
554
+ after do
555
+ Spree::Order.checkout_flow(&@old_checkout_flow)
556
+ end
557
+
558
+ it "does not attempt to process payments" do
559
+ allow(order).to receive_message_chain(:line_items, :present?) { true }
560
+ allow(order).to receive(:ensure_line_items_are_in_stock) { true }
561
+ allow(order).to receive(:ensure_line_item_variants_are_not_deleted) { true }
562
+ expect(order).not_to receive(:payment_required?)
563
+ expect(order).not_to receive(:process_payments!)
564
+ order.next!
565
+ assert_state_changed(order, 'cart', 'complete')
566
+ end
567
+
568
+ end
569
+
570
+ context "insert checkout step" do
571
+ before do
572
+ @old_checkout_flow = Spree::Order.checkout_flow
573
+ Spree::Order.class_eval do
574
+ insert_checkout_step :new_step, before: :address
575
+ end
576
+ end
577
+
578
+ after do
579
+ Spree::Order.checkout_flow(&@old_checkout_flow)
580
+ end
581
+
582
+ it "should maintain removed transitions" do
583
+ transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
584
+ expect(transition).to be_nil
585
+ end
586
+
587
+ context "before" do
588
+ before do
589
+ Spree::Order.class_eval do
590
+ insert_checkout_step :before_address, before: :address
591
+ end
592
+ end
593
+
594
+ specify do
595
+ order = Spree::Order.new
596
+ expect(order.checkout_steps).to eq(%w(new_step before_address address delivery complete))
597
+ end
598
+ end
599
+
600
+ context "after" do
601
+ before do
602
+ Spree::Order.class_eval do
603
+ insert_checkout_step :after_address, after: :address
604
+ end
605
+ end
606
+
607
+ specify do
608
+ order = Spree::Order.new
609
+ expect(order.checkout_steps).to eq(%w(new_step address after_address delivery complete))
610
+ end
611
+ end
612
+ end
613
+
614
+ context "remove checkout step" do
615
+ before do
616
+ @old_checkout_flow = Spree::Order.checkout_flow
617
+ Spree::Order.class_eval do
618
+ remove_checkout_step :address
619
+ end
620
+ end
621
+
622
+ after do
623
+ Spree::Order.checkout_flow(&@old_checkout_flow)
624
+ end
625
+
626
+ it "should maintain removed transitions" do
627
+ transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
628
+ expect(transition).to be_nil
629
+ end
630
+
631
+ specify do
632
+ order = Spree::Order.new
633
+ expect(order.checkout_steps).to eq(%w(delivery complete))
634
+ end
635
+ end
636
+
637
+ describe 'update_from_params' do
638
+ let(:permitted_params) { {} }
639
+ let(:params) { {} }
640
+
641
+ it 'calls update_atributes without order params' do
642
+ expect(order).to receive(:update_attributes).with({})
643
+ order.update_from_params( params, permitted_params)
644
+ end
645
+
646
+ it 'runs the callbacks' do
647
+ expect(order).to receive(:run_callbacks).with(:updating_from_params)
648
+ order.update_from_params( params, permitted_params)
649
+ end
650
+
651
+ context "passing a credit card" do
652
+ let(:permitted_params) do
653
+ Spree::PermittedAttributes.checkout_attributes +
654
+ [payments_attributes: Spree::PermittedAttributes.payment_attributes]
655
+ end
656
+
657
+ let(:credit_card) { create(:credit_card, user_id: order.user_id) }
658
+
659
+ let(:params) do
660
+ ActionController::Parameters.new(
661
+ order: { payments_attributes: [{payment_method_id: 1}], existing_card: credit_card.id },
662
+ cvc_confirm: "737",
663
+ payment_source: {
664
+ "1" => { name: "Luis Braga",
665
+ number: "4111 1111 1111 1111",
666
+ expiry: "06 / 2016",
667
+ verification_value: "737",
668
+ cc_type: "" }
669
+ }
670
+ )
671
+ end
672
+
673
+ before { order.user_id = 3 }
674
+
675
+ it "sets confirmation value when its available via :cvc_confirm" do
676
+ allow(Spree::CreditCard).to receive_messages find: credit_card
677
+ expect(credit_card).to receive(:verification_value=)
678
+ order.update_from_params(params, permitted_params)
679
+ end
680
+
681
+ it "sets existing card as source for new payment" do
682
+ expect {
683
+ order.update_from_params(params, permitted_params)
684
+ }.to change { Spree::Payment.count }.by(1)
685
+
686
+ expect(Spree::Payment.last.source).to eq credit_card
687
+ end
688
+
689
+ it "sets request_env on payment" do
690
+ request_env = { "USER_AGENT" => "Firefox" }
691
+
692
+ expected_hash = { "payments_attributes" => [hash_including("request_env" => request_env)] }
693
+ expect(order).to receive(:update_attributes).with expected_hash
694
+
695
+ order.update_from_params(params, permitted_params, request_env)
696
+ end
697
+
698
+ it "dont let users mess with others users cards" do
699
+ credit_card.update_column :user_id, 5
700
+
701
+ expect {
702
+ order.update_from_params(params, permitted_params)
703
+ }.to raise_error
704
+ end
705
+ end
706
+
707
+ context 'has params' do
708
+ let(:permitted_params) { [ :good_param ] }
709
+ let(:params) { ActionController::Parameters.new(order: { bad_param: 'okay' } ) }
710
+
711
+ it 'does not let through unpermitted attributes' do
712
+ expect(order).to receive(:update_attributes).with({})
713
+ order.update_from_params(params, permitted_params)
714
+ end
715
+
716
+ context 'has existing_card param' do
717
+ let(:permitted_params) do
718
+ Spree::PermittedAttributes.checkout_attributes +
719
+ [payments_attributes: Spree::PermittedAttributes.payment_attributes]
720
+ end
721
+ let(:credit_card) { create(:credit_card, user_id: order.user_id) }
722
+ let(:params) do
723
+ ActionController::Parameters.new(
724
+ order: { payments_attributes: [{payment_method_id: 1}], existing_card: credit_card.id }
725
+ )
726
+ end
727
+
728
+ before do
729
+ Dummy::Application.config.action_controller.action_on_unpermitted_parameters = :raise
730
+ order.user_id = 3
731
+ end
732
+
733
+ after do
734
+ Dummy::Application.config.action_controller.action_on_unpermitted_parameters = :log
735
+ end
736
+
737
+ it 'does not attempt to permit existing_card' do
738
+ expect {
739
+ order.update_from_params(params, permitted_params)
740
+ }.not_to raise_error
741
+ end
742
+ end
743
+
744
+ context 'has allowed params' do
745
+ let(:params) { ActionController::Parameters.new(order: { good_param: 'okay' } ) }
746
+
747
+ it 'accepts permitted attributes' do
748
+ expect(order).to receive(:update_attributes).with({"good_param" => 'okay'})
749
+ order.update_from_params(params, permitted_params)
750
+ end
751
+ end
752
+
753
+ context 'callbacks halt' do
754
+ before do
755
+ expect(order).to receive(:update_params_payment_source).and_return false
756
+ end
757
+ it 'does not let through unpermitted attributes' do
758
+ expect(order).not_to receive(:update_attributes).with({})
759
+ order.update_from_params(params, permitted_params)
760
+ end
761
+ end
762
+ end
763
+ end
764
+ end