solidus_core 1.0.2 → 1.0.3

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