solidus_core 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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