solidus_core 1.1.0 → 1.1.1

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Rakefile +16 -0
  4. data/script/rails +9 -0
  5. data/solidus_core.gemspec +48 -0
  6. data/spec/fixtures/thinking-cat.jpg +0 -0
  7. data/spec/helpers/base_helper_spec.rb +173 -0
  8. data/spec/helpers/order_helper_spec.rb +12 -0
  9. data/spec/helpers/products_helper_spec.rb +208 -0
  10. data/spec/helpers/taxons_helper_spec.rb +17 -0
  11. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  12. data/spec/lib/i18n_spec.rb +106 -0
  13. data/spec/lib/search/base_spec.rb +86 -0
  14. data/spec/lib/search/variant_spec.rb +112 -0
  15. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  16. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  17. data/spec/lib/spree/core/controller_helpers/payment_parameters_spec.rb +80 -0
  18. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  19. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  20. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  21. data/spec/lib/spree/core/current_store_spec.rb +36 -0
  22. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +24 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +156 -0
  25. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +130 -0
  26. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  27. data/spec/lib/spree/localized_number_spec.rb +38 -0
  28. data/spec/lib/spree/migrations_spec.rb +36 -0
  29. data/spec/lib/spree/money_spec.rb +127 -0
  30. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  31. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  32. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  33. data/spec/mailers/carton_mailer_spec.rb +55 -0
  34. data/spec/mailers/order_mailer_spec.rb +135 -0
  35. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  36. data/spec/mailers/test_mailer_spec.rb +15 -0
  37. data/spec/models/spree/ability_spec.rb +276 -0
  38. data/spec/models/spree/address_spec.rb +376 -0
  39. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  40. data/spec/models/spree/adjustment_spec.rb +169 -0
  41. data/spec/models/spree/app_configuration_spec.rb +24 -0
  42. data/spec/models/spree/asset_spec.rb +24 -0
  43. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  44. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  45. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  46. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  47. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  48. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  49. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +60 -0
  50. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  51. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  52. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  53. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  54. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  55. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  56. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  57. data/spec/models/spree/calculator_spec.rb +36 -0
  58. data/spec/models/spree/carton_spec.rb +133 -0
  59. data/spec/models/spree/classification_spec.rb +93 -0
  60. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  61. data/spec/models/spree/concerns/ordered_property_value_list_spec.rb +25 -0
  62. data/spec/models/spree/concerns/user_address_book_spec.rb +332 -0
  63. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  64. data/spec/models/spree/credit_card_spec.rb +341 -0
  65. data/spec/models/spree/customer_return_spec.rb +276 -0
  66. data/spec/models/spree/exchange_spec.rb +79 -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 +104 -0
  70. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  71. data/spec/models/spree/item_adjustments_spec.rb +275 -0
  72. data/spec/models/spree/line_item_spec.rb +199 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +45 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +27 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +884 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +110 -0
  81. data/spec/models/spree/order/payment_spec.rb +243 -0
  82. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  83. data/spec/models/spree/order/state_machine_spec.rb +209 -0
  84. data/spec/models/spree/order/tax_spec.rb +84 -0
  85. data/spec/models/spree/order/totals_spec.rb +24 -0
  86. data/spec/models/spree/order/updating_spec.rb +18 -0
  87. data/spec/models/spree/order/validations_spec.rb +15 -0
  88. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  89. data/spec/models/spree/order_capturing_spec.rb +150 -0
  90. data/spec/models/spree/order_contents_spec.rb +307 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_mutex_spec.rb +85 -0
  93. data/spec/models/spree/order_promotion_spec.rb +31 -0
  94. data/spec/models/spree/order_shipping_spec.rb +241 -0
  95. data/spec/models/spree/order_spec.rb +1482 -0
  96. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  97. data/spec/models/spree/order_updater_spec.rb +283 -0
  98. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  99. data/spec/models/spree/payment_method_spec.rb +147 -0
  100. data/spec/models/spree/payment_spec.rb +1087 -0
  101. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  102. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  103. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  104. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  105. data/spec/models/spree/permission_sets/order_display_spec.rb +55 -0
  106. data/spec/models/spree/permission_sets/order_management_spec.rb +42 -0
  107. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  108. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  109. data/spec/models/spree/permission_sets/promotion_display_spec.rb +40 -0
  110. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/restricted_stock_display_spec.rb +41 -0
  113. data/spec/models/spree/permission_sets/restricted_stock_management_spec.rb +41 -0
  114. data/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +50 -0
  115. data/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +160 -0
  116. data/spec/models/spree/permission_sets/stock_display_spec.rb +24 -0
  117. data/spec/models/spree/permission_sets/stock_management_spec.rb +22 -0
  118. data/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +24 -0
  119. data/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +25 -0
  120. data/spec/models/spree/permission_sets/user_display_spec.rb +38 -0
  121. data/spec/models/spree/permission_sets/user_management_spec.rb +48 -0
  122. data/spec/models/spree/preference_spec.rb +80 -0
  123. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  124. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  125. data/spec/models/spree/preferences/scoped_store_spec.rb +60 -0
  126. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  127. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  128. data/spec/models/spree/preferences/store_spec.rb +39 -0
  129. data/spec/models/spree/price_spec.rb +42 -0
  130. data/spec/models/spree/product/scopes_spec.rb +116 -0
  131. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  132. data/spec/models/spree/product_filter_spec.rb +26 -0
  133. data/spec/models/spree/product_property_spec.rb +18 -0
  134. data/spec/models/spree/product_spec.rb +504 -0
  135. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  136. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  137. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  138. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  139. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  140. data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +69 -0
  141. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  142. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  143. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  144. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  145. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  146. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  147. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  148. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  149. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  150. data/spec/models/spree/promotion_category_spec.rb +17 -0
  151. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  152. data/spec/models/spree/promotion_code_spec.rb +187 -0
  153. data/spec/models/spree/promotion_handler/cart_spec.rb +130 -0
  154. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  155. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  156. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  157. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  158. data/spec/models/spree/promotion_spec.rb +776 -0
  159. data/spec/models/spree/refund_spec.rb +192 -0
  160. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  161. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  162. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  163. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  164. data/spec/models/spree/reimbursement_spec.rb +231 -0
  165. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  166. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  167. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  168. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  169. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  170. data/spec/models/spree/return_authorization_spec.rb +290 -0
  171. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  172. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  173. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  174. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  175. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  176. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  177. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  178. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  179. data/spec/models/spree/return_item_spec.rb +776 -0
  180. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  181. data/spec/models/spree/shipment_spec.rb +753 -0
  182. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  183. data/spec/models/spree/shipping_manifest_spec.rb +94 -0
  184. data/spec/models/spree/shipping_method_spec.rb +88 -0
  185. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  186. data/spec/models/spree/state_spec.rb +14 -0
  187. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  188. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  189. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  190. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  191. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  192. data/spec/models/spree/stock/package_spec.rb +163 -0
  193. data/spec/models/spree/stock/packer_spec.rb +91 -0
  194. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  195. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  196. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  197. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  198. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  199. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  200. data/spec/models/spree/stock_item_spec.rb +444 -0
  201. data/spec/models/spree/stock_location_spec.rb +279 -0
  202. data/spec/models/spree/stock_movement_spec.rb +56 -0
  203. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  204. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  205. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  206. data/spec/models/spree/store_credit_spec.rb +876 -0
  207. data/spec/models/spree/store_spec.rb +55 -0
  208. data/spec/models/spree/tax_category_spec.rb +27 -0
  209. data/spec/models/spree/tax_rate_spec.rb +378 -0
  210. data/spec/models/spree/taxon_spec.rb +74 -0
  211. data/spec/models/spree/taxonomy_spec.rb +18 -0
  212. data/spec/models/spree/tracker_spec.rb +21 -0
  213. data/spec/models/spree/transfer_item_spec.rb +264 -0
  214. data/spec/models/spree/unit_cancel_spec.rb +149 -0
  215. data/spec/models/spree/user_spec.rb +246 -0
  216. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  217. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  218. data/spec/models/spree/variant_property_rule_condition_spec.rb +15 -0
  219. data/spec/models/spree/variant_property_rule_spec.rb +83 -0
  220. data/spec/models/spree/variant_property_rule_value_spec.rb +18 -0
  221. data/spec/models/spree/variant_spec.rb +601 -0
  222. data/spec/models/spree/zone_spec.rb +305 -0
  223. data/spec/spec_helper.rb +80 -0
  224. data/spec/support/big_decimal.rb +5 -0
  225. data/spec/support/concerns/default_price.rb +34 -0
  226. data/spec/support/dummy_ability.rb +4 -0
  227. data/spec/support/test_gateway.rb +2 -0
  228. metadata +242 -2
@@ -0,0 +1,199 @@
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
+ context '#destroy' do
8
+ it "fetches deleted products" do
9
+ line_item.product.destroy
10
+ expect(line_item.reload.product).to be_a Spree::Product
11
+ end
12
+
13
+ it "fetches deleted variants" do
14
+ line_item.variant.destroy
15
+ expect(line_item.reload.variant).to be_a Spree::Variant
16
+ end
17
+
18
+ it "returns inventory when a line item is destroyed" do
19
+ expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
20
+ line_item.destroy
21
+ end
22
+
23
+ it "deletes inventory units" do
24
+ expect { line_item.destroy }.to change { line_item.inventory_units.count }.from(1).to(0)
25
+ end
26
+ end
27
+
28
+ context "#save" do
29
+ context "line item changes" do
30
+ before do
31
+ line_item.quantity = line_item.quantity + 1
32
+ end
33
+
34
+ it "triggers adjustment total recalculation" do
35
+ expect(line_item).to receive(:update_tax_charge) # Regression test for https://github.com/spree/spree/issues/4671
36
+ expect(line_item).to receive(:recalculate_adjustments)
37
+ line_item.save
38
+ end
39
+ end
40
+
41
+ context "line item does not change" do
42
+ it "does not trigger adjustment total recalculation" do
43
+ expect(line_item).not_to receive(:recalculate_adjustments)
44
+ line_item.save
45
+ end
46
+ end
47
+
48
+ context "target_shipment is provided" do
49
+ it "verifies inventory" do
50
+ line_item.target_shipment = Spree::Shipment.new
51
+ expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
52
+ line_item.save
53
+ end
54
+ end
55
+ end
56
+
57
+ context "#create" do
58
+ let(:variant) { create(:variant) }
59
+
60
+ before do
61
+ create(:tax_rate, :zone => order.tax_zone, :tax_category => variant.tax_category)
62
+ end
63
+
64
+ context "when order has a tax zone" do
65
+ before do
66
+ expect(order.tax_zone).to be_present
67
+ end
68
+
69
+ it "creates a tax adjustment" do
70
+ order.contents.add(variant)
71
+ line_item = order.find_line_item_by_variant(variant)
72
+ expect(line_item.adjustments.tax.count).to eq(1)
73
+ end
74
+ end
75
+
76
+ context "when order does not have a tax zone" do
77
+ before do
78
+ order.bill_address = nil
79
+ order.ship_address = nil
80
+ order.save
81
+ expect(order.reload.tax_zone).to be_nil
82
+ end
83
+
84
+ it "does not create a tax adjustment" do
85
+ order.contents.add(variant)
86
+ line_item = order.find_line_item_by_variant(variant)
87
+ expect(line_item.adjustments.tax.count).to eq(0)
88
+ end
89
+ end
90
+ end
91
+
92
+ # Test for #3391
93
+ context '#copy_price' do
94
+ it "copies over a variant's prices" do
95
+ line_item.price = nil
96
+ line_item.cost_price = nil
97
+ line_item.currency = nil
98
+ line_item.copy_price
99
+ variant = line_item.variant
100
+ expect(line_item.price).to eq(variant.price)
101
+ expect(line_item.cost_price).to eq(variant.cost_price)
102
+ expect(line_item.currency).to eq(variant.currency)
103
+ end
104
+ end
105
+
106
+ # Test for #3481
107
+ context '#copy_tax_category' do
108
+ it "copies over a variant's tax category" do
109
+ line_item.tax_category = nil
110
+ line_item.copy_tax_category
111
+ expect(line_item.tax_category).to eq(line_item.variant.tax_category)
112
+ end
113
+ end
114
+
115
+ describe '.discounted_amount' do
116
+ it "returns the amount minus any discounts" do
117
+ line_item.price = 10
118
+ line_item.quantity = 2
119
+ line_item.promo_total = -5
120
+ expect(line_item.discounted_amount).to eq(15)
121
+ end
122
+ end
123
+
124
+ describe "#discounted_money" do
125
+ it "should return a money object with the discounted amount" do
126
+ expect(line_item.discounted_money.to_s).to eq "$10.00"
127
+ end
128
+ end
129
+
130
+ describe '.currency' do
131
+ it 'returns the globally configured currency' do
132
+ line_item.currency == 'USD'
133
+ end
134
+ end
135
+
136
+ describe ".money" do
137
+ before do
138
+ line_item.price = 3.50
139
+ line_item.quantity = 2
140
+ end
141
+
142
+ it "returns a Spree::Money representing the total for this line item" do
143
+ expect(line_item.money.to_s).to eq("$7.00")
144
+ end
145
+ end
146
+
147
+ describe '.single_money' do
148
+ before { line_item.price = 3.50 }
149
+ it "returns a Spree::Money representing the price for one variant" do
150
+ expect(line_item.single_money.to_s).to eq("$3.50")
151
+ end
152
+ end
153
+
154
+ context "currency same as order.currency" do
155
+ it "is a valid line item" do
156
+ line_item = order.line_items.first
157
+ line_item.currency = order.currency
158
+ line_item.valid?
159
+
160
+ expect(line_item.error_on(:currency).size).to eq(0)
161
+ end
162
+ end
163
+
164
+ context "currency different than order.currency" do
165
+ it "is not a valid line item" do
166
+ line_item = order.line_items.first
167
+ line_item.currency = "no currency"
168
+ line_item.valid?
169
+
170
+ expect(line_item.error_on(:currency).size).to eq(1)
171
+ end
172
+ end
173
+
174
+ describe "#options=" do
175
+ it "can handle updating a blank line item with no order" do
176
+ line_item.options = { price: 123 }
177
+ end
178
+
179
+ it "updates the data provided in the options" do
180
+ line_item.options = { price: 123 }
181
+ expect(line_item.price).to eq 123
182
+ end
183
+
184
+ it "updates the price based on the options provided" do
185
+ expect(line_item).to receive(:gift_wrap=).with(true)
186
+ expect(line_item.variant).to receive(:gift_wrap_price_modifier_amount_in).with("USD", true).and_return 1.99
187
+ line_item.options = { gift_wrap: true }
188
+ expect(line_item.price).to eq 21.98
189
+ end
190
+ end
191
+
192
+ describe "precision of pre_tax_amount" do
193
+ let!(:line_item) { create :line_item, pre_tax_amount: 4.2051 }
194
+
195
+ it "keeps four digits of precision even when reloading" do
196
+ expect(line_item.reload.pre_tax_amount).to eq(4.2051)
197
+ end
198
+ end
199
+ 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,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OptionValue, :type => :model do
4
+ context "touching" do
5
+ let!(:variant) do
6
+ Timecop.freeze(1.day.ago) do
7
+ create(:variant)
8
+ end
9
+ end
10
+ let(:option_value) { variant.option_values.first }
11
+
12
+ it "should touch a variant" do
13
+ Timecop.freeze do
14
+ option_value.touch
15
+ expect(variant.reload.updated_at).to be_within(1.second).of(Time.now)
16
+ end
17
+ end
18
+
19
+ context "from the after_save hook" do
20
+ it "should not touch the variant if there are no changes" do
21
+ Timecop.freeze do
22
+ option_value.save!
23
+ expect(variant.reload.updated_at).to be <= 1.day.ago
24
+ end
25
+ end
26
+
27
+ it "should touch the variant if there are changes" do
28
+ Timecop.freeze do
29
+ option_value.name += "--1"
30
+ option_value.save!
31
+ expect(variant.reload.updated_at).to be_within(1.second).of(Time.now)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#presentation_with_option_type" do
38
+ let(:option_value) { build(:option_value) }
39
+ subject { option_value.presentation_with_option_type }
40
+
41
+ it "returns a string in the correct form" do
42
+ expect(subject).to eq "Size - S"
43
+ end
44
+ end
45
+ 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,27 @@
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
+ persisted_order.line_items << line_item
16
+ create(:adjustment, amount: -line_item.amount, label: "Promotion", adjustable: line_item, order: persisted_order)
17
+ persisted_order.state = 'delivery'
18
+ persisted_order.save # To ensure new state_change event
19
+ end
20
+
21
+ it "transitions from delivery to payment" do
22
+ allow(persisted_order).to receive_messages(payment_required?: true)
23
+ persisted_order.next!
24
+ expect(persisted_order.state).to eq("payment")
25
+ end
26
+ end
27
+ 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,884 @@
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
+ def assert_state_changed(order, from, to)
8
+ state_change_exists = order.state_changes.where(:previous_state => from, :next_state => to).exists?
9
+ assert state_change_exists, "Expected order to transition from #{from} to #{to}, but didn't."
10
+ end
11
+
12
+ context "with default state machine" do
13
+ transitions = [
14
+ { :address => :delivery },
15
+ { :delivery => :payment },
16
+ { :payment => :confirm },
17
+ { :delivery => :confirm },
18
+ ]
19
+
20
+ transitions.each do |transition|
21
+ it "transitions from #{transition.keys.first} to #{transition.values.first}" do
22
+ transition = Spree::Order.find_transition(:from => transition.keys.first, :to => transition.values.first)
23
+ expect(transition).not_to be_nil
24
+ end
25
+ end
26
+
27
+ it '.find_transition when contract was broken' do
28
+ expect(Spree::Order.find_transition({foo: :bar, baz: :dog})).to be_falsey
29
+ end
30
+
31
+ describe "remove_transition" do
32
+ after do
33
+ Spree::Order.checkout_flow(&@old_checkout_flow)
34
+ end
35
+
36
+ it '.remove_transition' do
37
+ options = {:from => transitions.first.keys.first, :to => transitions.first.values.first}
38
+ allow(Spree::Order).to receive(:next_event_transition).and_return([options])
39
+ expect(Spree::Order.remove_transition(options)).to be_truthy
40
+ end
41
+
42
+ it '.remove_transition when contract was broken' do
43
+ expect(Spree::Order.remove_transition(nil)).to be_falsey
44
+ end
45
+ end
46
+
47
+ it "always return integer on checkout_step_index" do
48
+ expect(order.checkout_step_index("imnotthere")).to be_a Integer
49
+ expect(order.checkout_step_index("delivery")).to be > 0
50
+ end
51
+
52
+ it "passes delivery state when transitioning from address over delivery to payment" do
53
+ allow(order).to receive_messages :payment_required? => true
54
+ order.state = "address"
55
+ expect(order.passed_checkout_step?("delivery")).to be false
56
+ order.state = "delivery"
57
+ expect(order.passed_checkout_step?("delivery")).to be false
58
+ order.state = "payment"
59
+ expect(order.passed_checkout_step?("delivery")).to be true
60
+ end
61
+
62
+ context "#checkout_steps" do
63
+ context "when confirmation not required" do
64
+ before do
65
+ allow(order).to receive_messages :payment_required? => true
66
+ end
67
+
68
+ specify do
69
+ expect(order.checkout_steps).to eq(%w(address delivery payment confirm complete))
70
+ end
71
+ end
72
+
73
+ context "when confirmation required" do
74
+ before do
75
+ allow(order).to receive_messages :payment_required? => true
76
+ end
77
+
78
+ specify do
79
+ expect(order.checkout_steps).to eq(%w(address delivery payment confirm complete))
80
+ end
81
+ end
82
+
83
+ context "when payment not required" do
84
+ before { allow(order).to receive_messages :payment_required? => false }
85
+ specify do
86
+ expect(order.checkout_steps).to eq(%w(address delivery confirm complete))
87
+ end
88
+ end
89
+
90
+ context "when payment required" do
91
+ before { allow(order).to receive_messages :payment_required? => true }
92
+ specify do
93
+ expect(order.checkout_steps).to eq(%w(address delivery payment confirm complete))
94
+ end
95
+ end
96
+ end
97
+
98
+ it "starts out at cart" do
99
+ expect(order.state).to eq("cart")
100
+ end
101
+
102
+ context "to address" do
103
+ before do
104
+ order.email = "user@example.com"
105
+ order.save!
106
+ end
107
+
108
+ context "with a line item" do
109
+ before do
110
+ order.line_items << FactoryGirl.create(:line_item)
111
+ end
112
+
113
+ it "transitions to address" do
114
+ order.next!
115
+ assert_state_changed(order, 'cart', 'address')
116
+ expect(order.state).to eq("address")
117
+ end
118
+
119
+ it "doesn't raise an error if the default address is invalid" do
120
+ order.user = mock_model(Spree::LegacyUser, ship_address: Spree::Address.new, bill_address: Spree::Address.new)
121
+ expect { order.next! }.to_not raise_error
122
+ end
123
+
124
+ context "with default addresses" do
125
+ let(:default_address) { FactoryGirl.create(:address) }
126
+
127
+ shared_examples "it references the user's the default address" do
128
+ it do
129
+ default_attributes = default_address.reload.value_attributes
130
+ order_attributes = Spree::Address.value_attributes(order.send("#{address_kind}_address".to_sym).try(:attributes))
131
+
132
+ expect(order_attributes).to eq(default_attributes)
133
+ end
134
+ end
135
+
136
+ it_behaves_like "it references the user's the default address" do
137
+ let(:address_kind) { :ship }
138
+ before do
139
+ order.user = FactoryGirl.create(:user)
140
+ order.user.default_address = default_address
141
+ order.next!
142
+ order.reload
143
+ end
144
+ end
145
+
146
+ it_behaves_like "it references the user's the default address" do
147
+ let(:address_kind) { :bill }
148
+ before do
149
+ order.user = FactoryGirl.create(:user, bill_address: default_address)
150
+ order.next!
151
+ order.reload
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ it "cannot transition to address without any line items" do
158
+ expect(order.line_items).to be_blank
159
+ expect { order.next! }.to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:there_are_no_items_for_this_order)}/)
160
+ end
161
+ end
162
+
163
+ context "from address" do
164
+ let(:ship_address) { FactoryGirl.create(:ship_address) }
165
+
166
+ before do
167
+ order.state = 'address'
168
+ order.ship_address = ship_address
169
+ shipment = FactoryGirl.create(:shipment, :order => order, :cost => 10)
170
+ order.email = "user@example.com"
171
+ order.save!
172
+ end
173
+
174
+ context "no shipping address" do
175
+ let(:ship_address) { nil }
176
+
177
+ it "does not transition without a ship address" do
178
+ expect { order.next! }.to raise_error StateMachines::InvalidTransition
179
+ end
180
+ end
181
+
182
+ it "updates totals" do
183
+ line_item = FactoryGirl.create(:line_item, :price => 10, :adjustment_total => 10)
184
+ order.line_items << line_item
185
+ tax_rate = create(:tax_rate, :tax_category => line_item.tax_category, :amount => 0.05)
186
+ allow(Spree::TaxRate).to receive_messages :match => [tax_rate]
187
+ FactoryGirl.create(:tax_adjustment, :adjustable => line_item, :source => tax_rate, order: order)
188
+ order.email = "user@example.com"
189
+ order.next!
190
+ expect(order.adjustment_total).to eq(0.5)
191
+ expect(order.additional_tax_total).to eq(0.5)
192
+ expect(order.included_tax_total).to eq(0)
193
+ expect(order.total).to eq(20.5)
194
+ end
195
+
196
+ it "transitions to delivery" do
197
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
198
+ order.next!
199
+ assert_state_changed(order, 'address', 'delivery')
200
+ expect(order.state).to eq("delivery")
201
+ end
202
+
203
+ it "does not call persist_order_address if there is no address on the order" do
204
+ # otherwise, it will crash
205
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
206
+
207
+ order.user = FactoryGirl.create(:user)
208
+ order.save!
209
+
210
+ expect(order.user).to_not receive(:persist_order_address).with(order)
211
+ order.next!
212
+ end
213
+
214
+ it "calls persist_order_address on the order's user" do
215
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
216
+
217
+ order.user = FactoryGirl.create(:user)
218
+ order.ship_address = FactoryGirl.create(:address)
219
+ order.bill_address = FactoryGirl.create(:address)
220
+ order.save!
221
+
222
+ expect(order.user).to receive(:persist_order_address).with(order)
223
+ order.next!
224
+ end
225
+
226
+ it "does not call persist_order_address on the order's user for a temporary address" do
227
+ allow(order).to receive_messages(:ensure_available_shipping_rates => true)
228
+
229
+ order.user = FactoryGirl.create(:user)
230
+ order.temporary_address = true
231
+ order.save!
232
+
233
+ expect(order.user).to_not receive(:persist_order_address)
234
+ order.next!
235
+ end
236
+ end
237
+
238
+ context "to delivery" do
239
+ let(:ship_address) { FactoryGirl.create(:ship_address) }
240
+
241
+ before do
242
+ order.ship_address = ship_address
243
+ end
244
+
245
+ context 'when order has default selected_shipping_rate_id' do
246
+ let(:shipment) { create(:shipment, order: order) }
247
+ let(:shipping_method) { create(:shipping_method) }
248
+ let(:shipping_rate) { [
249
+ Spree::ShippingRate.create!(shipping_method: shipping_method, cost: 10.00, shipment: shipment)
250
+ ] }
251
+
252
+ before do
253
+ order.state = 'address'
254
+ shipment.selected_shipping_rate_id = shipping_rate.first.id
255
+ order.email = "user@example.com"
256
+ order.save!
257
+
258
+ allow(order).to receive(:create_proposed_shipments)
259
+ allow(order).to receive(:ensure_available_shipping_rates) { true }
260
+ end
261
+
262
+ it 'should invoke set_shipment_cost' do
263
+ expect(order).to receive(:set_shipments_cost)
264
+ order.next!
265
+ end
266
+
267
+ it 'should update shipment_total' do
268
+ expect { order.next! }.to change{ order.shipment_total }.by(10.00)
269
+ end
270
+ end
271
+
272
+ context "cannot transition to delivery" do
273
+ context "if there are no shipping rates for any shipment" do
274
+ let!(:line_item){ create :line_item, order: order }
275
+ before do
276
+ order.state = 'address'
277
+ order.email = 'user@example.com'
278
+ end
279
+ specify do
280
+ transition = lambda { order.next! }
281
+ expect(transition).to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:items_cannot_be_shipped)}/)
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ context "from delivery" do
288
+ let(:ship_address) { FactoryGirl.create(:ship_address) }
289
+
290
+ before do
291
+ order.ship_address = ship_address
292
+ order.state = 'delivery'
293
+ allow(order).to receive(:apply_free_shipping_promotions)
294
+ allow(order).to receive(:ensure_available_shipping_rates) { true }
295
+ end
296
+
297
+ it "attempts to apply free shipping promotions" do
298
+ expect(order).to receive(:apply_free_shipping_promotions)
299
+ order.next!
300
+ end
301
+
302
+ context "with payment required" do
303
+ before do
304
+ allow(order).to receive_messages :payment_required? => true
305
+ end
306
+
307
+ it "transitions to payment" do
308
+ expect(order).to receive(:set_shipments_cost)
309
+ order.next!
310
+ assert_state_changed(order, 'delivery', 'payment')
311
+ expect(order.state).to eq('payment')
312
+ end
313
+ end
314
+
315
+ context "without payment required" do
316
+ before do
317
+ allow(order).to receive_messages :payment_required? => false
318
+ end
319
+
320
+ it "transitions to complete" do
321
+ order.next!
322
+ expect(order.state).to eq("confirm")
323
+ end
324
+ end
325
+
326
+ context "correctly determining payment required based on shipping information" do
327
+ let(:shipment) do
328
+ FactoryGirl.create(:shipment)
329
+ end
330
+
331
+ before do
332
+ # Needs to be set here because we're working with a persisted order object
333
+ order.email = "test@example.com"
334
+ order.save!
335
+ order.shipments << shipment
336
+ end
337
+
338
+ context "with a shipment that has a price" do
339
+ before do
340
+ shipment.shipping_rates.first.update_column(:cost, 10)
341
+ order.set_shipments_cost
342
+ end
343
+
344
+ it "transitions to payment" do
345
+ order.next!
346
+ expect(order.state).to eq("payment")
347
+ end
348
+ end
349
+
350
+ context "with a shipment that is free" do
351
+ before do
352
+ shipment.shipping_rates.first.update_column(:cost, 0)
353
+ order.set_shipments_cost
354
+ end
355
+
356
+ it "skips payment, transitions to confirm" do
357
+ order.next!
358
+ expect(order.state).to eq("confirm")
359
+ end
360
+ end
361
+ end
362
+ end
363
+
364
+ context "to payment" do
365
+ let(:user_bill_address) { nil }
366
+ let(:order_bill_address) { nil }
367
+ let(:default_credit_card) { create(:credit_card) }
368
+
369
+ before do
370
+ user = Spree::LegacyUser.new(email: 'spree@example.org', bill_address: user_bill_address)
371
+ allow(user).to receive(:default_credit_card) { default_credit_card }
372
+ order.user = user
373
+
374
+ allow(order).to receive_messages(payment_required?: true)
375
+ order.state = 'delivery'
376
+ order.bill_address = order_bill_address
377
+ order.save!
378
+ order.next!
379
+ order.reload
380
+ end
381
+
382
+ it "assigns the user's default credit card" do
383
+ expect(order.state).to eq 'payment'
384
+ expect(order.payments.count).to eq 1
385
+ expect(order.payments.first.source).to eq default_credit_card
386
+ end
387
+
388
+ context "order already has a billing address" do
389
+ let(:order_bill_address) { create(:address) }
390
+
391
+ it "keeps the order's billing address" do
392
+ expect(order.bill_address).to eq order_bill_address
393
+ end
394
+ end
395
+
396
+ context "order doesn't have a billing address" do
397
+ it "assigns the user's default_credit_card's address to the order" do
398
+ expect(order.bill_address).to eq default_credit_card.address
399
+ end
400
+ end
401
+ end
402
+
403
+ context "from payment" do
404
+ before do
405
+ order.state = 'payment'
406
+ allow(order).to receive(:ensure_available_shipping_rates) { true }
407
+ end
408
+
409
+ context "with confirmation required" do
410
+ before do
411
+ end
412
+
413
+ it "transitions to confirm" do
414
+ order.next!
415
+ assert_state_changed(order, 'payment', 'confirm')
416
+ expect(order.state).to eq("confirm")
417
+ end
418
+ end
419
+
420
+ # Regression test for #2028
421
+ context "when payment is not required" do
422
+ before do
423
+ allow(order).to receive_messages :payment_required? => false
424
+ end
425
+
426
+ it "does not call process payments" do
427
+ expect(order).not_to receive(:process_payments!)
428
+ order.next!
429
+ assert_state_changed(order, 'payment', 'confirm')
430
+ expect(order.state).to eq("confirm")
431
+ end
432
+ end
433
+ end
434
+ end
435
+
436
+ context "from confirm" do
437
+ before do
438
+ order.state = 'confirm'
439
+ order.save!
440
+ end
441
+
442
+ it "returns false on next" do
443
+ expect(order.next).to be_falsy
444
+ end
445
+
446
+ it "is unable to next" do
447
+ expect(order).not_to be_can_next
448
+ end
449
+ end
450
+
451
+ context "to complete" do
452
+ before do
453
+ order.state = 'confirm'
454
+ order.save!
455
+ end
456
+
457
+ context "out of stock" do
458
+ before do
459
+ order.user = FactoryGirl.create(:user)
460
+ order.email = 'spree@example.org'
461
+ order.payments << FactoryGirl.create(:payment)
462
+ allow(order).to receive_messages(payment_required?: true)
463
+ order.line_items << FactoryGirl.create(:line_item)
464
+ order.line_items.first.variant.stock_items.each do |si|
465
+ si.set_count_on_hand(0)
466
+ si.update_attributes(:backorderable => false)
467
+ end
468
+
469
+ Spree::OrderUpdater.new(order).update
470
+ order.save!
471
+ end
472
+
473
+ it "does not allow the order to complete" do
474
+ expect {
475
+ order.complete!
476
+ }.to raise_error Spree::Order::InsufficientStock
477
+
478
+ expect(order.state).to eq 'confirm'
479
+ expect(order.line_items.first.errors[:quantity]).to be_present
480
+ expect(order.payments.first.state).to eq('checkout')
481
+ end
482
+ end
483
+
484
+ context "no inventory units" do
485
+ before do
486
+ order.user = FactoryGirl.create(:user)
487
+ order.email = 'spree@example.com'
488
+ order.payments << FactoryGirl.create(:payment)
489
+ allow(order).to receive_messages(payment_required?: true)
490
+ allow(order).to receive(:ensure_available_shipping_rates) { true }
491
+ order.line_items << FactoryGirl.create(:line_item)
492
+
493
+ Spree::OrderUpdater.new(order).update
494
+ order.save!
495
+ end
496
+
497
+ it "does not allow order to complete" do
498
+ expect { order.complete! }.to raise_error Spree::Order::InsufficientStock
499
+
500
+ expect(order.state).to eq 'confirm'
501
+ expect(order.line_items.first.errors[:inventory]).to be_present
502
+ expect(order.payments.first.state).to eq('checkout')
503
+ end
504
+ end
505
+
506
+ context "exchange order completion" do
507
+ before do
508
+ order.email = 'spree@example.org'
509
+ order.payments << FactoryGirl.create(:payment)
510
+ order.shipments.create!
511
+ allow(order).to receive_messages(payment_required?: true)
512
+ allow(order).to receive(:ensure_available_shipping_rates).and_return(true)
513
+ end
514
+
515
+ context 'when the line items are not available' do
516
+ before do
517
+ order.line_items << FactoryGirl.create(:line_item)
518
+ order.store = FactoryGirl.build(:store)
519
+ Spree::OrderUpdater.new(order).update
520
+
521
+ order.save!
522
+ end
523
+
524
+ context 'when the exchange is for an unreturned item' do
525
+ before do
526
+ order.shipments.first.update_attributes!(created_at: order.created_at - 1.day)
527
+ expect(order.unreturned_exchange?).to eq true
528
+ end
529
+
530
+ it 'allows the order to complete' do
531
+ order.complete!
532
+
533
+ expect(order).to be_complete
534
+ end
535
+ end
536
+
537
+ context 'when the exchange is not for an unreturned item' do
538
+ it 'does not allow the order to completed' do
539
+ expect { order.complete! }.to raise_error Spree::Order::InsufficientStock
540
+ expect(order.payments.first.state).to eq('checkout')
541
+ end
542
+ end
543
+ end
544
+ end
545
+
546
+ context "default credit card" do
547
+ before do
548
+ order.user = FactoryGirl.create(:user)
549
+ order.store = FactoryGirl.create(:store)
550
+ order.email = 'spree@example.org'
551
+ order.payments << FactoryGirl.create(:payment)
552
+
553
+ # make sure we will actually capture a payment
554
+ allow(order).to receive_messages(payment_required?: true)
555
+ allow(order).to receive_messages(ensure_available_shipping_rates: true)
556
+ allow(order).to receive_messages(validate_line_item_availability: true)
557
+ order.line_items << FactoryGirl.create(:line_item)
558
+ order.create_proposed_shipments
559
+ Spree::OrderUpdater.new(order).update
560
+
561
+ order.save!
562
+ end
563
+
564
+ it "makes the current credit card a user's default credit card" do
565
+ order.complete!
566
+ expect(order.state).to eq 'complete'
567
+ expect(order.user.reload.default_credit_card.try(:id)).to eq(order.credit_cards.first.id)
568
+ end
569
+
570
+ it "does not assign a default credit card if temporary_credit_card is set" do
571
+ order.temporary_credit_card = true
572
+ order.complete!
573
+ expect(order.user.reload.default_credit_card).to be_nil
574
+ end
575
+ end
576
+
577
+ context "a payment fails during processing" do
578
+ before do
579
+ order.user = FactoryGirl.create(:user)
580
+ order.email = 'spree@example.org'
581
+ payment = FactoryGirl.create(:payment)
582
+ allow(payment).to receive(:process!).and_raise(Spree::Core::GatewayError.new('processing failed'))
583
+ order.line_items.each { |li| li.inventory_units.create! }
584
+ order.payments << payment
585
+
586
+ # make sure we will actually capture a payment
587
+ allow(order).to receive_messages(payment_required?: true)
588
+ allow(order).to receive_messages(ensure_available_shipping_rates: true)
589
+ allow(order).to receive_messages(validate_line_item_availability: true)
590
+ order.line_items << FactoryGirl.create(:line_item)
591
+ order.create_proposed_shipments
592
+ Spree::OrderUpdater.new(order).update
593
+ end
594
+
595
+ it "transitions to the payment state" do
596
+ expect { order.complete! }.to raise_error StateMachines::InvalidTransition
597
+ expect(order.reload.state).to eq 'payment'
598
+ end
599
+ end
600
+
601
+ context 'a shipment has no shipping rates' do
602
+ let(:order) { create(:order_with_line_items, state: 'confirm') }
603
+ let(:shipment) { order.shipments.first }
604
+
605
+ before do
606
+ shipment.shipping_rates.destroy_all
607
+ end
608
+
609
+ it 'clears the shipments and fails the transition' do
610
+ expect(order.complete).to eq(false)
611
+ expect(order.errors[:base]).to include(Spree.t(:items_cannot_be_shipped))
612
+ expect(order.shipments.count).to eq(0)
613
+ expect(Spree::InventoryUnit.where(shipment_id: shipment.id).count).to eq(0)
614
+ end
615
+ end
616
+
617
+ context 'the order is already paid' do
618
+ let(:order) { create(:order_with_line_items) }
619
+
620
+ it 'can complete the order' do
621
+ payment = create(:payment, state: 'completed', order: order, amount: order.total)
622
+ order.update!
623
+ expect(order.complete).to eq(true)
624
+ end
625
+ end
626
+ end
627
+
628
+ context "subclassed order" do
629
+ # This causes another test above to fail, but fixing this test should make
630
+ # the other test pass
631
+ class SubclassedOrder < Spree::Order
632
+ checkout_flow do
633
+ go_to_state :payment
634
+ go_to_state :complete
635
+ end
636
+ end
637
+
638
+ skip "should only call default transitions once when checkout_flow is redefined" do
639
+ order = SubclassedOrder.new
640
+ allow(order).to receive_messages :payment_required? => true
641
+ expect(order).to receive(:process_payments!).once
642
+ order.state = "payment"
643
+ order.next!
644
+ assert_state_changed(order, 'payment', 'complete')
645
+ expect(order.state).to eq("complete")
646
+ end
647
+ end
648
+
649
+ context "re-define checkout flow" do
650
+ before do
651
+ @old_checkout_flow = Spree::Order.checkout_flow
652
+ Spree::Order.class_eval do
653
+ checkout_flow do
654
+ go_to_state :payment
655
+ go_to_state :complete
656
+ end
657
+ end
658
+ end
659
+
660
+ after do
661
+ Spree::Order.checkout_flow(&@old_checkout_flow)
662
+ end
663
+
664
+ it "should not keep old event transitions when checkout_flow is redefined" do
665
+ expect(Spree::Order.next_event_transitions).to eq([{:cart=>:payment}, {:payment=>:complete}])
666
+ end
667
+
668
+ it "should not keep old events when checkout_flow is redefined" do
669
+ state_machine = Spree::Order.state_machine
670
+ expect(state_machine.states.any? { |s| s.name == :address }).to be false
671
+ known_states = state_machine.events[:next].branches.map(&:known_states).flatten
672
+ expect(known_states).not_to include(:address)
673
+ expect(known_states).not_to include(:delivery)
674
+ expect(known_states).not_to include(:confirm)
675
+ end
676
+ end
677
+
678
+ # Regression test for #3665
679
+ context "with only a complete step" do
680
+ let!(:line_item){ create :line_item, order: order }
681
+
682
+ before do
683
+ @old_checkout_flow = Spree::Order.checkout_flow
684
+ Spree::Order.class_eval do
685
+ checkout_flow do
686
+ go_to_state :complete
687
+ end
688
+ end
689
+ end
690
+
691
+ after do
692
+ Spree::Order.checkout_flow(&@old_checkout_flow)
693
+ end
694
+
695
+ it "does not attempt to process payments" do
696
+ order.email = 'user@example.com'
697
+ order.store = FactoryGirl.build(:store)
698
+ allow(order).to receive(:ensure_available_shipping_rates).and_return(true)
699
+ allow(order).to receive(:ensure_promotions_eligible).and_return(true)
700
+ allow(order).to receive(:ensure_line_item_variants_are_not_deleted).and_return(true)
701
+ allow(order).to receive_message_chain(:line_items, :present?).and_return(true)
702
+ allow(order).to receive_messages(validate_line_item_availability: true)
703
+ expect(order).not_to receive(:payment_required?)
704
+ expect(order).not_to receive(:process_payments!)
705
+ order.next!
706
+ assert_state_changed(order, 'cart', 'complete')
707
+ end
708
+
709
+ end
710
+
711
+ context "insert checkout step" do
712
+ before do
713
+ @old_checkout_flow = Spree::Order.checkout_flow
714
+ Spree::Order.class_eval do
715
+ remove_transition from: :delivery, to: :confirm
716
+ end
717
+ Spree::Order.class_eval do
718
+ insert_checkout_step :new_step, before: :address
719
+ end
720
+ end
721
+
722
+ after do
723
+ Spree::Order.checkout_flow(&@old_checkout_flow)
724
+ end
725
+
726
+ it "should maintain removed transitions" do
727
+ transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
728
+ expect(transition).to be_nil
729
+ end
730
+
731
+ context "before" do
732
+ before do
733
+ Spree::Order.class_eval do
734
+ insert_checkout_step :before_address, before: :address
735
+ end
736
+ end
737
+
738
+ specify do
739
+ order = Spree::Order.new
740
+ expect(order.checkout_steps).to eq(%w(new_step before_address address delivery confirm complete))
741
+ end
742
+ end
743
+
744
+ context "after" do
745
+ before do
746
+ Spree::Order.class_eval do
747
+ insert_checkout_step :after_address, after: :address
748
+ end
749
+ end
750
+
751
+ specify do
752
+ order = Spree::Order.new
753
+ expect(order.checkout_steps).to eq(%w(new_step address after_address delivery confirm complete))
754
+ end
755
+ end
756
+ end
757
+
758
+ context "remove checkout step" do
759
+ before do
760
+ @old_checkout_flow = Spree::Order.checkout_flow
761
+ Spree::Order.class_eval do
762
+ remove_transition from: :delivery, to: :confirm
763
+ end
764
+ Spree::Order.class_eval do
765
+ remove_checkout_step :address
766
+ end
767
+ end
768
+
769
+ after do
770
+ Spree::Order.checkout_flow(&@old_checkout_flow)
771
+ end
772
+
773
+ it "should maintain removed transitions" do
774
+ transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
775
+ expect(transition).to be_nil
776
+ end
777
+
778
+ specify do
779
+ order = Spree::Order.new
780
+ expect(order.checkout_steps).to eq(%w(delivery confirm complete))
781
+ end
782
+ end
783
+
784
+ describe 'update_from_params' do
785
+ let(:permitted_params) { {} }
786
+ let(:params) { {} }
787
+
788
+ it 'calls update_atributes without order params' do
789
+ expect(order).to receive(:update_attributes).with({})
790
+ order.update_from_params( params, permitted_params)
791
+ end
792
+
793
+ it 'runs the callbacks' do
794
+ expect(order).to receive(:run_callbacks).with(:updating_from_params)
795
+ order.update_from_params( params, permitted_params)
796
+ end
797
+
798
+ context "passing a credit card" do
799
+ let(:permitted_params) do
800
+ Spree::PermittedAttributes.checkout_attributes +
801
+ [payments_attributes: Spree::PermittedAttributes.payment_attributes]
802
+ end
803
+
804
+ let(:credit_card) { create(:credit_card, user_id: order.user_id) }
805
+
806
+ let(:params) do
807
+ ActionController::Parameters.new(
808
+ order: {
809
+ payments_attributes: [
810
+ {
811
+ payment_method_id: 1,
812
+ source_attributes: attributes_for(:credit_card),
813
+ },
814
+ ],
815
+ existing_card: credit_card.id,
816
+ },
817
+ cvc_confirm: "737",
818
+ )
819
+ end
820
+
821
+ before { order.user_id = 3 }
822
+
823
+ it "sets confirmation value when its available via :cvc_confirm" do
824
+ allow(Spree::CreditCard).to receive_messages find: credit_card
825
+ expect(credit_card).to receive(:verification_value=)
826
+ order.update_from_params(params, permitted_params)
827
+ end
828
+
829
+ it "sets existing card as source for new payment" do
830
+ expect {
831
+ order.update_from_params(params, permitted_params)
832
+ }.to change { Spree::Payment.count }.by(1)
833
+
834
+ expect(Spree::Payment.last.source).to eq credit_card
835
+ end
836
+
837
+ it "sets request_env on payment" do
838
+ request_env = { "USER_AGENT" => "Firefox" }
839
+
840
+ expected_hash = { "payments_attributes" => [hash_including("request_env" => request_env)] }
841
+ expect(order).to receive(:update_attributes).with expected_hash
842
+
843
+ order.update_from_params(params, permitted_params, request_env)
844
+ end
845
+
846
+ it "dont let users mess with others users cards" do
847
+ credit_card.update_column :user_id, 5
848
+
849
+ expect {
850
+ order.update_from_params(params, permitted_params)
851
+ }.to raise_error Spree::Core::GatewayError
852
+ end
853
+ end
854
+
855
+ context 'has params' do
856
+ let(:permitted_params) { [ :good_param ] }
857
+ let(:params) { ActionController::Parameters.new(order: { bad_param: 'okay' } ) }
858
+
859
+ it 'does not let through unpermitted attributes' do
860
+ expect(order).to receive(:update_attributes).with({})
861
+ order.update_from_params(params, permitted_params)
862
+ end
863
+
864
+ context 'has allowed params' do
865
+ let(:params) { ActionController::Parameters.new(order: { good_param: 'okay' } ) }
866
+
867
+ it 'accepts permitted attributes' do
868
+ expect(order).to receive(:update_attributes).with({"good_param" => 'okay'})
869
+ order.update_from_params(params, permitted_params)
870
+ end
871
+ end
872
+
873
+ context 'callbacks halt' do
874
+ before do
875
+ expect(order).to receive(:update_params_payment_source).and_return false
876
+ end
877
+ it 'does not let through unpermitted attributes' do
878
+ expect(order).not_to receive(:update_attributes).with({})
879
+ order.update_from_params(params, permitted_params)
880
+ end
881
+ end
882
+ end
883
+ end
884
+ end