solidus_core 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_core might be problematic. Click here for more details.

Files changed (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,1412 @@
1
+ require 'spec_helper'
2
+
3
+ class FakeCalculator < Spree::Calculator
4
+ def compute(computable)
5
+ 5
6
+ end
7
+ end
8
+
9
+ describe Spree::Order, :type => :model do
10
+ let(:user) { stub_model(Spree::LegacyUser, :email => "spree@example.com") }
11
+ let(:order) { stub_model(Spree::Order, :user => user) }
12
+
13
+ before do
14
+ allow(Spree::LegacyUser).to receive_messages(:current => mock_model(Spree::LegacyUser, :id => 123))
15
+ end
16
+
17
+ context "#canceled_by" do
18
+ let(:admin_user) { create :admin_user }
19
+ let(:order) { create :order }
20
+
21
+ before do
22
+ allow(order).to receive(:cancel!)
23
+ end
24
+
25
+ subject { order.canceled_by(admin_user) }
26
+
27
+ it 'should cancel the order' do
28
+ expect(order).to receive(:cancel!)
29
+ subject
30
+ end
31
+
32
+ it 'should save canceler_id' do
33
+ subject
34
+ expect(order.reload.canceler_id).to eq(admin_user.id)
35
+ end
36
+
37
+ it 'should save canceled_at' do
38
+ subject
39
+ expect(order.reload.canceled_at).to_not be_nil
40
+ end
41
+
42
+ it 'should have canceler' do
43
+ subject
44
+ expect(order.reload.canceler).to eq(admin_user)
45
+ end
46
+ end
47
+
48
+ context "#create" do
49
+ let(:order) { Spree::Order.create }
50
+
51
+ it "should assign an order number" do
52
+ expect(order.number).not_to be_nil
53
+ end
54
+
55
+ it 'should create a randomized 22 character token' do
56
+ expect(order.guest_token.size).to eq(22)
57
+ end
58
+ end
59
+
60
+ context "creates shipments cost" do
61
+ let(:shipment) { double }
62
+
63
+ before { allow(order).to receive_messages shipments: [shipment] }
64
+
65
+ it "update and persist totals" do
66
+ expect(shipment).to receive :update_amounts
67
+ expect(order.updater).to receive :update_shipment_total
68
+ expect(order.updater).to receive :persist_totals
69
+
70
+ order.set_shipments_cost
71
+ end
72
+ end
73
+
74
+ context "insufficient_stock_lines" do
75
+ let(:line_item) { mock_model Spree::LineItem, :insufficient_stock? => true }
76
+
77
+ before { allow(order).to receive_messages(:line_items => [line_item]) }
78
+
79
+ it "should return line_item that has insufficient stock on hand" do
80
+ expect(order.insufficient_stock_lines.size).to eq(1)
81
+ expect(order.insufficient_stock_lines.include?(line_item)).to be true
82
+ end
83
+ end
84
+
85
+ describe '#ensure_line_item_variants_are_not_deleted' do
86
+ subject { order.ensure_line_item_variants_are_not_deleted }
87
+
88
+ let(:order) { create :order_with_line_items }
89
+
90
+ context 'when variant is destroyed' do
91
+ before do
92
+ allow(order).to receive(:restart_checkout_flow)
93
+ order.line_items.first.variant.destroy
94
+ end
95
+
96
+ it 'should restart checkout flow' do
97
+ expect(order).to receive(:restart_checkout_flow).once
98
+ subject
99
+ end
100
+
101
+ it 'should have error message' do
102
+ subject
103
+ expect(order.errors[:base]).to include(Spree.t(:deleted_variants_present))
104
+ end
105
+
106
+ it 'should be false' do
107
+ expect(subject).to be_falsey
108
+ end
109
+ end
110
+
111
+ context 'when no variants are destroyed' do
112
+ it 'should not restart checkout' do
113
+ expect(order).to receive(:restart_checkout_flow).never
114
+ subject
115
+ end
116
+
117
+ it 'should be true' do
118
+ expect(subject).to be_truthy
119
+ end
120
+ end
121
+ end
122
+
123
+ context "empty!" do
124
+ let(:order) { stub_model(Spree::Order, item_count: 2) }
125
+
126
+ before do
127
+ allow(order).to receive_messages(:line_items => line_items = [1, 2])
128
+ allow(order).to receive_messages(:adjustments => adjustments = [])
129
+ end
130
+
131
+ it "clears out line items, adjustments and update totals" do
132
+ expect(order.line_items).to receive(:destroy_all)
133
+ expect(order.adjustments).to receive(:destroy_all)
134
+ expect(order.shipments).to receive(:destroy_all)
135
+ expect(order.updater).to receive(:update_totals)
136
+ expect(order.updater).to receive(:persist_totals)
137
+
138
+ order.empty!
139
+ expect(order.item_total).to eq 0
140
+ end
141
+ end
142
+
143
+ context "#display_outstanding_balance" do
144
+ it "returns the value as a spree money" do
145
+ allow(order).to receive(:outstanding_balance) { 10.55 }
146
+ expect(order.display_outstanding_balance).to eq(Spree::Money.new(10.55))
147
+ end
148
+ end
149
+
150
+ context "#display_item_total" do
151
+ it "returns the value as a spree money" do
152
+ allow(order).to receive(:item_total) { 10.55 }
153
+ expect(order.display_item_total).to eq(Spree::Money.new(10.55))
154
+ end
155
+ end
156
+
157
+ context "#display_adjustment_total" do
158
+ it "returns the value as a spree money" do
159
+ order.adjustment_total = 10.55
160
+ expect(order.display_adjustment_total).to eq(Spree::Money.new(10.55))
161
+ end
162
+ end
163
+
164
+ context "#display_total" do
165
+ it "returns the value as a spree money" do
166
+ order.total = 10.55
167
+ expect(order.display_total).to eq(Spree::Money.new(10.55))
168
+ end
169
+ end
170
+
171
+ context "#currency" do
172
+ context "when object currency is ABC" do
173
+ before { order.currency = "ABC" }
174
+
175
+ it "returns the currency from the object" do
176
+ expect(order.currency).to eq("ABC")
177
+ end
178
+ end
179
+
180
+ context "when object currency is nil" do
181
+ before { order.currency = nil }
182
+
183
+ it "returns the globally configured currency" do
184
+ expect(order.currency).to eq("USD")
185
+ end
186
+ end
187
+ end
188
+
189
+ # Regression tests for #2179
190
+ context "#merge!" do
191
+ let(:variant) { create(:variant) }
192
+ let(:order_1) { Spree::Order.create }
193
+ let(:order_2) { Spree::Order.create }
194
+
195
+ it "destroys the other order" do
196
+ order_1.merge!(order_2)
197
+ expect { order_2.reload }.to raise_error(ActiveRecord::RecordNotFound)
198
+ end
199
+
200
+ context "user is provided" do
201
+ it "assigns user to new order" do
202
+ order_1.merge!(order_2, user)
203
+ expect(order_1.user).to eq user
204
+ end
205
+ end
206
+
207
+ context "merging together two orders with line items for the same variant" do
208
+ before do
209
+ order_1.contents.add(variant, 1)
210
+ order_2.contents.add(variant, 1)
211
+ end
212
+
213
+ specify do
214
+ order_1.merge!(order_2)
215
+ expect(order_1.line_items.count).to eq(1)
216
+
217
+ line_item = order_1.line_items.first
218
+ expect(line_item.quantity).to eq(2)
219
+ expect(line_item.variant_id).to eq(variant.id)
220
+ end
221
+
222
+ end
223
+
224
+ context "merging using extension-specific line_item_comparison_hooks" do
225
+ before do
226
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
227
+ allow(Spree::Variant).to receive(:price_modifier_amount).and_return(0.00)
228
+ end
229
+
230
+ after do
231
+ # reset to avoid test pollution
232
+ Spree::Order.line_item_comparison_hooks = Set.new
233
+ end
234
+
235
+ context "2 equal line items" do
236
+ before do
237
+ @line_item_1 = order_1.contents.add(variant, 1, {foos: {}})
238
+ @line_item_2 = order_2.contents.add(variant, 1, {foos: {}})
239
+ end
240
+
241
+ specify do
242
+ expect(order_1).to receive(:foos_match).with(@line_item_1, kind_of(Hash)).and_return(true)
243
+ order_1.merge!(order_2)
244
+ expect(order_1.line_items.count).to eq(1)
245
+
246
+ line_item = order_1.line_items.first
247
+ expect(line_item.quantity).to eq(2)
248
+ expect(line_item.variant_id).to eq(variant.id)
249
+ end
250
+ end
251
+
252
+ context "2 different line items" do
253
+ before do
254
+ allow(order_1).to receive(:foos_match).and_return(false)
255
+
256
+ order_1.contents.add(variant, 1, {foos: {}})
257
+ order_2.contents.add(variant, 1, {foos: {bar: :zoo}})
258
+ end
259
+
260
+ specify do
261
+ order_1.merge!(order_2)
262
+ expect(order_1.line_items.count).to eq(2)
263
+
264
+ line_item = order_1.line_items.first
265
+ expect(line_item.quantity).to eq(1)
266
+ expect(line_item.variant_id).to eq(variant.id)
267
+
268
+ line_item = order_1.line_items.last
269
+ expect(line_item.quantity).to eq(1)
270
+ expect(line_item.variant_id).to eq(variant.id)
271
+ end
272
+ end
273
+ end
274
+
275
+ context "merging together two orders with different line items" do
276
+ let(:variant_2) { create(:variant) }
277
+
278
+ before do
279
+ order_1.contents.add(variant, 1)
280
+ order_2.contents.add(variant_2, 1)
281
+ end
282
+
283
+ specify do
284
+ order_1.merge!(order_2)
285
+ line_items = order_1.line_items.reload
286
+ expect(line_items.count).to eq(2)
287
+
288
+ expect(order_1.item_count).to eq 2
289
+ expect(order_1.item_total).to eq line_items.map(&:amount).sum
290
+
291
+ # No guarantee on ordering of line items, so we do this:
292
+ expect(line_items.pluck(:quantity)).to match_array([1, 1])
293
+ expect(line_items.pluck(:variant_id)).to match_array([variant.id, variant_2.id])
294
+ end
295
+ end
296
+ end
297
+
298
+ context "add_update_hook" do
299
+ before do
300
+ Spree::Order.class_eval do
301
+ register_update_hook :add_awesome_sauce
302
+ end
303
+ end
304
+
305
+ after do
306
+ Spree::Order.update_hooks = Set.new
307
+ end
308
+
309
+ it "calls hook during update" do
310
+ order = create(:order)
311
+ expect(order).to receive(:add_awesome_sauce)
312
+ order.update!
313
+ end
314
+
315
+ it "calls hook during finalize" do
316
+ order = create(:order)
317
+ expect(order).to receive(:add_awesome_sauce)
318
+ order.finalize!
319
+ end
320
+ end
321
+
322
+ context "ensure shipments will be updated" do
323
+ before do
324
+ Spree::Shipment.create!(order: order)
325
+ end
326
+
327
+ ['payment', 'confirm'].each do |order_state|
328
+ context "when ther order is in the #{order_state} state" do
329
+ before do
330
+ order.state = order_state
331
+ order.shipments.create!
332
+ end
333
+
334
+ it "destroys current shipments" do
335
+ order.ensure_updated_shipments
336
+ expect(order.shipments).to be_empty
337
+ end
338
+
339
+ it "puts order back in address state" do
340
+ order.ensure_updated_shipments
341
+ expect(order.state).to eql "cart"
342
+ end
343
+
344
+ it "resets shipment_total" do
345
+ order.update_column(:shipment_total, 5)
346
+ order.ensure_updated_shipments
347
+ expect(order.shipment_total).to eq(0)
348
+ end
349
+
350
+ it "does nothing if any shipments are ready" do
351
+ shipment = create(:shipment, order: subject, state: "ready")
352
+ expect { subject.ensure_updated_shipments }.not_to change { subject.reload.shipments }
353
+ expect { shipment.reload }.not_to raise_error
354
+ end
355
+
356
+ it "does nothing if any shipments are shipped" do
357
+ shipment = create(:shipment, order: subject, state: "shipped")
358
+ expect { subject.ensure_updated_shipments }.not_to change { subject.reload.shipments }
359
+ expect { shipment.reload }.not_to raise_error
360
+ end
361
+ end
362
+
363
+ end
364
+
365
+ context 'when the order is in address state' do
366
+ before do
367
+ order.state = 'address'
368
+ order.shipments.create!
369
+ end
370
+
371
+ it "destroys current shipments" do
372
+ order.ensure_updated_shipments
373
+ expect(order.shipments).to be_empty
374
+ end
375
+
376
+ it "resets shipment_total" do
377
+ order.update_column(:shipment_total, 5)
378
+ order.ensure_updated_shipments
379
+ expect(order.shipment_total).to eq(0)
380
+ end
381
+
382
+ it "puts the order in the cart state" do
383
+ order.ensure_updated_shipments
384
+ expect(order.state).to eq "cart"
385
+ end
386
+ end
387
+
388
+ context 'when the order is completed' do
389
+ before do
390
+ order.state = 'complete'
391
+ order.completed_at = Time.now
392
+ order.update_column(:shipment_total, 5)
393
+ order.shipments.create!
394
+ end
395
+
396
+ it "does not destroy the current shipments" do
397
+ expect {
398
+ order.ensure_updated_shipments
399
+ }.not_to change { order.shipments }
400
+ end
401
+
402
+ it "does not reset the shipment total" do
403
+ expect {
404
+ order.ensure_updated_shipments
405
+ }.not_to change { order.shipment_total }
406
+ end
407
+
408
+ it "does not put the order back in the address state" do
409
+ expect {
410
+ order.ensure_updated_shipments
411
+ }.not_to change { order.state }
412
+ end
413
+ end
414
+
415
+ context "except when order is completed, that's OrderInventory job" do
416
+ it "doesn't touch anything" do
417
+ allow(order).to receive_messages completed?: true
418
+ order.update_column(:shipment_total, 5)
419
+ order.shipments.create!
420
+
421
+ expect {
422
+ order.ensure_updated_shipments
423
+ }.not_to change { order.shipment_total }
424
+
425
+ expect {
426
+ order.ensure_updated_shipments
427
+ }.not_to change { order.shipments }
428
+
429
+ expect {
430
+ order.ensure_updated_shipments
431
+ }.not_to change { order.state }
432
+ end
433
+ end
434
+
435
+ end
436
+
437
+ describe "#tax_address" do
438
+ before { Spree::Config[:tax_using_ship_address] = tax_using_ship_address }
439
+ subject { order.tax_address }
440
+
441
+ context "when tax_using_ship_address is true" do
442
+ let(:tax_using_ship_address) { true }
443
+
444
+ it 'returns ship_address' do
445
+ expect(subject).to eq(order.ship_address)
446
+ end
447
+ end
448
+
449
+ context "when tax_using_ship_address is not true" do
450
+ let(:tax_using_ship_address) { false }
451
+
452
+ it "returns bill_address" do
453
+ expect(subject).to eq(order.bill_address)
454
+ end
455
+ end
456
+ end
457
+
458
+ describe "#restart_checkout_flow" do
459
+ context "when in cart state" do
460
+ let(:order) { create(:order_with_totals, state: "cart") }
461
+
462
+ it "remains in cart state" do
463
+ expect { order.restart_checkout_flow }.not_to change { order.state }
464
+ end
465
+ end
466
+ it "updates the state column to the first checkout_steps value" do
467
+ order = create(:order_with_totals, state: "delivery")
468
+ expect(order.checkout_steps).to eql ["address", "delivery", "confirm", "complete"]
469
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("address")
470
+ end
471
+
472
+ context "without line items" do
473
+ it "updates the state column to cart" do
474
+ order = create(:order, state: "delivery")
475
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("cart")
476
+ end
477
+ end
478
+ end
479
+
480
+ # Regression tests for #4072
481
+ context "#state_changed" do
482
+ let(:order) { FactoryGirl.create(:order) }
483
+
484
+ it "logs state changes" do
485
+ order.update_column(:payment_state, 'balance_due')
486
+ order.payment_state = 'paid'
487
+ expect(order.state_changes).to be_empty
488
+ order.state_changed('payment')
489
+ state_change = order.state_changes.find_by(:name => 'payment')
490
+ expect(state_change.previous_state).to eq('balance_due')
491
+ expect(state_change.next_state).to eq('paid')
492
+ end
493
+
494
+ it "does not do anything if state does not change" do
495
+ order.update_column(:payment_state, 'balance_due')
496
+ expect(order.state_changes).to be_empty
497
+ order.state_changed('payment')
498
+ expect(order.state_changes).to be_empty
499
+ end
500
+ end
501
+
502
+ # Regression test for #4199
503
+ context "#available_payment_methods" do
504
+ it "includes frontend payment methods" do
505
+ payment_method = Spree::PaymentMethod.create!({
506
+ :name => "Fake",
507
+ :active => true,
508
+ :display_on => "front_end",
509
+ :environment => Rails.env
510
+ })
511
+ expect(order.available_payment_methods).to include(payment_method)
512
+ end
513
+
514
+ it "includes 'both' payment methods" do
515
+ payment_method = Spree::PaymentMethod.create!({
516
+ :name => "Fake",
517
+ :active => true,
518
+ :display_on => "both",
519
+ :environment => Rails.env
520
+ })
521
+ expect(order.available_payment_methods).to include(payment_method)
522
+ end
523
+
524
+ it "does not include a payment method twice if display_on is blank" do
525
+ payment_method = Spree::PaymentMethod.create!({
526
+ :name => "Fake",
527
+ :active => true,
528
+ :display_on => "both",
529
+ :environment => Rails.env
530
+ })
531
+ expect(order.available_payment_methods.count).to eq(1)
532
+ expect(order.available_payment_methods).to include(payment_method)
533
+ end
534
+ end
535
+
536
+ context "#apply_free_shipping_promotions" do
537
+ it "calls out to the FreeShipping promotion handler" do
538
+ shipment = double('Shipment')
539
+ allow(order).to receive_messages :shipments => [shipment]
540
+ expect(Spree::PromotionHandler::FreeShipping).to receive(:new).and_return(handler = double)
541
+ expect(handler).to receive(:activate)
542
+
543
+ expect(Spree::ItemAdjustments).to receive(:new).with(shipment).and_return(adjuster = double)
544
+ expect(adjuster).to receive(:update)
545
+
546
+ expect(order.updater).to receive(:update_shipment_total)
547
+ expect(order.updater).to receive(:persist_totals)
548
+ order.apply_free_shipping_promotions
549
+ end
550
+ end
551
+
552
+
553
+ context "#products" do
554
+ before :each do
555
+ @variant1 = mock_model(Spree::Variant, :product => "product1")
556
+ @variant2 = mock_model(Spree::Variant, :product => "product2")
557
+ @line_items = [mock_model(Spree::LineItem, :product => "product1", :variant => @variant1, :variant_id => @variant1.id, :quantity => 1),
558
+ mock_model(Spree::LineItem, :product => "product2", :variant => @variant2, :variant_id => @variant2.id, :quantity => 2)]
559
+ allow(order).to receive_messages(:line_items => @line_items)
560
+ end
561
+
562
+ it "contains?" do
563
+ expect(order.contains?(@variant1)).to be true
564
+ end
565
+
566
+ it "gets the quantity of a given variant" do
567
+ expect(order.quantity_of(@variant1)).to eq(1)
568
+
569
+ @variant3 = mock_model(Spree::Variant, :product => "product3")
570
+ expect(order.quantity_of(@variant3)).to eq(0)
571
+ end
572
+
573
+ it "can find a line item matching a given variant" do
574
+ expect(order.find_line_item_by_variant(@variant1)).not_to be_nil
575
+ expect(order.find_line_item_by_variant(mock_model(Spree::Variant))).to be_nil
576
+ end
577
+
578
+ context "match line item with options" do
579
+ before do
580
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
581
+ end
582
+
583
+ after do
584
+ # reset to avoid test pollution
585
+ Spree::Order.line_item_comparison_hooks = Set.new
586
+ end
587
+
588
+ it "matches line item when options match" do
589
+ allow(order).to receive(:foos_match).and_return(true)
590
+ expect(order.line_item_options_match(@line_items.first, {foos: {bar: :zoo}})).to be true
591
+ end
592
+
593
+ it "does not match line item without options" do
594
+ allow(order).to receive(:foos_match).and_return(false)
595
+ expect(order.line_item_options_match(@line_items.first, {})).to be false
596
+ end
597
+ end
598
+ end
599
+
600
+ context "#generate_order_number" do
601
+ context "when no configure" do
602
+ let(:default_length) { Spree::Order::ORDER_NUMBER_LENGTH + Spree::Order::ORDER_NUMBER_PREFIX.length }
603
+ subject(:order_number) { order.generate_order_number }
604
+
605
+ describe '#class' do
606
+ subject { super().class }
607
+ it { is_expected.to eq String }
608
+ end
609
+
610
+ describe '#length' do
611
+ subject { super().length }
612
+ it { is_expected.to eq default_length }
613
+ end
614
+ it { is_expected.to match /^#{Spree::Order::ORDER_NUMBER_PREFIX}/ }
615
+ end
616
+
617
+ context "when length option is 5" do
618
+ let(:option_length) { 5 + Spree::Order::ORDER_NUMBER_PREFIX.length }
619
+ it "should be option length for order number" do
620
+ expect(order.generate_order_number(length: 5).length).to eq option_length
621
+ end
622
+ end
623
+
624
+ context "when letters option is true" do
625
+ it "generates order number include letter" do
626
+ expect(order.generate_order_number(length: 100, letters: true)).to match /[A-Z]/
627
+ end
628
+ end
629
+
630
+ context "when prefix option is 'P'" do
631
+ it "generates order number and it prefix is 'P'" do
632
+ expect(order.generate_order_number(prefix: 'P')).to match /^P/
633
+ end
634
+ end
635
+ end
636
+
637
+ context "#associate_user!" do
638
+ let!(:user) { FactoryGirl.create(:user) }
639
+
640
+ it "should associate a user with a persisted order" do
641
+ order = FactoryGirl.create(:order_with_line_items, created_by: nil)
642
+ order.user = nil
643
+ order.email = nil
644
+ order.associate_user!(user)
645
+ expect(order.user).to eq(user)
646
+ expect(order.email).to eq(user.email)
647
+ expect(order.created_by).to eq(user)
648
+
649
+ # verify that the changes we made were persisted
650
+ order.reload
651
+ expect(order.user).to eq(user)
652
+ expect(order.email).to eq(user.email)
653
+ expect(order.created_by).to eq(user)
654
+ end
655
+
656
+ it "should not overwrite the created_by if it already is set" do
657
+ creator = create(:user)
658
+ order = FactoryGirl.create(:order_with_line_items, created_by: creator)
659
+
660
+ order.user = nil
661
+ order.email = nil
662
+ order.associate_user!(user)
663
+ expect(order.user).to eq(user)
664
+ expect(order.email).to eq(user.email)
665
+ expect(order.created_by).to eq(creator)
666
+
667
+ # verify that the changes we made were persisted
668
+ order.reload
669
+ expect(order.user).to eq(user)
670
+ expect(order.email).to eq(user.email)
671
+ expect(order.created_by).to eq(creator)
672
+ end
673
+
674
+ it "should associate a user with a non-persisted order" do
675
+ order = Spree::Order.new
676
+
677
+ expect do
678
+ order.associate_user!(user)
679
+ end.to change { [order.user, order.email] }.from([nil, nil]).to([user, user.email])
680
+ end
681
+
682
+ it "should not persist an invalid address" do
683
+ address = Spree::Address.new
684
+ order.user = nil
685
+ order.email = nil
686
+ order.ship_address = address
687
+ expect do
688
+ order.associate_user!(user)
689
+ end.not_to change { address.persisted? }.from(false)
690
+ end
691
+ end
692
+
693
+ context "#can_ship?" do
694
+ let(:order) { Spree::Order.create }
695
+
696
+ it "should be true for order in the 'complete' state" do
697
+ allow(order).to receive_messages(:complete? => true)
698
+ expect(order.can_ship?).to be true
699
+ end
700
+
701
+ it "should be true for order in the 'resumed' state" do
702
+ allow(order).to receive_messages(:resumed? => true)
703
+ expect(order.can_ship?).to be true
704
+ end
705
+
706
+ it "should be true for an order in the 'awaiting return' state" do
707
+ allow(order).to receive_messages(:awaiting_return? => true)
708
+ expect(order.can_ship?).to be true
709
+ end
710
+
711
+ it "should be true for an order in the 'returned' state" do
712
+ allow(order).to receive_messages(:returned? => true)
713
+ expect(order.can_ship?).to be true
714
+ end
715
+
716
+ it "should be false if the order is neither in the 'complete' nor 'resumed' state" do
717
+ allow(order).to receive_messages(:resumed? => false, :complete? => false)
718
+ expect(order.can_ship?).to be false
719
+ end
720
+ end
721
+
722
+ context "#completed?" do
723
+ it "should indicate if order is completed" do
724
+ order.completed_at = nil
725
+ expect(order.completed?).to be false
726
+
727
+ order.completed_at = Time.now
728
+ expect(order.completed?).to be true
729
+ end
730
+ end
731
+
732
+ context "#allow_checkout?" do
733
+ it "should be true if there are line_items in the order" do
734
+ allow(order).to receive_message_chain(:line_items, :count => 1)
735
+ expect(order.checkout_allowed?).to be true
736
+ end
737
+ it "should be false if there are no line_items in the order" do
738
+ allow(order).to receive_message_chain(:line_items, :count => 0)
739
+ expect(order.checkout_allowed?).to be false
740
+ end
741
+ end
742
+
743
+ context "#amount" do
744
+ before do
745
+ @order = create(:order, :user => user)
746
+ @order.line_items = [create(:line_item, :price => 1.0, :quantity => 2),
747
+ create(:line_item, :price => 1.0, :quantity => 1)]
748
+ end
749
+ it "should return the correct lum sum of items" do
750
+ expect(@order.amount).to eq(3.0)
751
+ end
752
+ end
753
+
754
+ context "#backordered?" do
755
+ it 'is backordered if one of the shipments is backordered' do
756
+ allow(order).to receive_messages(:shipments => [mock_model(Spree::Shipment, :backordered? => false),
757
+ mock_model(Spree::Shipment, :backordered? => true)])
758
+ expect(order).to be_backordered
759
+ end
760
+ end
761
+
762
+ context "#can_cancel?" do
763
+ it "should be false for completed order in the canceled state" do
764
+ order.state = 'canceled'
765
+ order.shipment_state = 'ready'
766
+ order.completed_at = Time.now
767
+ expect(order.can_cancel?).to be false
768
+ end
769
+
770
+ it "should be true for completed order with no shipment" do
771
+ order.state = 'complete'
772
+ order.shipment_state = nil
773
+ order.completed_at = Time.now
774
+ expect(order.can_cancel?).to be true
775
+ end
776
+ end
777
+
778
+ context "#tax_total" do
779
+ it "adds included tax and additional tax" do
780
+ allow(order).to receive_messages(:additional_tax_total => 10, :included_tax_total => 20)
781
+
782
+ expect(order.tax_total).to eq 30
783
+ end
784
+ end
785
+
786
+ # Regression test for #4923
787
+ context "locking" do
788
+ let(:order) { Spree::Order.create } # need a persisted in order to test locking
789
+
790
+ it 'can lock' do
791
+ expect { order.with_lock {} }.to_not raise_error
792
+ end
793
+ end
794
+
795
+ describe "#pre_tax_item_amount" do
796
+ it "sums all of the line items' pre tax amounts" do
797
+ subject.line_items = [
798
+ Spree::LineItem.new(price: 10, quantity: 2, pre_tax_amount: 5.0),
799
+ Spree::LineItem.new(price: 30, quantity: 1, pre_tax_amount: 14.0),
800
+ ]
801
+
802
+ expect(subject.pre_tax_item_amount).to eq 19.0
803
+ end
804
+ end
805
+
806
+ describe '#quantity' do
807
+ # Uses a persisted record, as the quantity is retrieved via a DB count
808
+ let(:order) { create :order_with_line_items, line_items_count: 3 }
809
+
810
+ it 'sums the quantity of all line items' do
811
+ expect(order.quantity).to eq 3
812
+ end
813
+ end
814
+
815
+ describe '#has_non_reimbursement_related_refunds?' do
816
+ subject do
817
+ order.has_non_reimbursement_related_refunds?
818
+ end
819
+
820
+ context 'no refunds exist' do
821
+ it { is_expected.to eq false }
822
+ end
823
+
824
+ context 'a non-reimbursement related refund exists' do
825
+ let(:order) { refund.payment.order }
826
+ let(:refund) { create(:refund, reimbursement_id: nil, amount: 5) }
827
+
828
+ it { is_expected.to eq true }
829
+ end
830
+
831
+ context 'an old-style refund exists' do
832
+ let(:order) { create(:order_ready_to_ship) }
833
+ let(:payment) { order.payments.first.tap { |p| allow(p).to receive_messages(profiles_supported: false) } }
834
+ let!(:refund_payment) {
835
+ build(:payment, amount: -1, order: order, state: 'completed', source: payment).tap do |p|
836
+ allow(p).to receive_messages(profiles_supported?: false)
837
+ p.save!
838
+ end
839
+ }
840
+
841
+ it { is_expected.to eq true }
842
+ end
843
+
844
+ context 'a reimbursement related refund exists' do
845
+ let(:order) { refund.payment.order }
846
+ let(:refund) { create(:refund, reimbursement_id: 123, amount: 5)}
847
+
848
+ it { is_expected.to eq false }
849
+ end
850
+ end
851
+
852
+ describe "#create_proposed_shipments" do
853
+ it "assigns the coordinator returned shipments to its shipments" do
854
+ shipment = build(:shipment)
855
+ allow_any_instance_of(Spree::Stock::Coordinator).to receive(:shipments).and_return([shipment])
856
+ subject.create_proposed_shipments
857
+ expect(subject.shipments).to eq [shipment]
858
+ end
859
+
860
+ it "raises an error if any shipments are ready" do
861
+ shipment = create(:shipment, order: subject, state: "ready")
862
+ expect {
863
+ expect {
864
+ subject.create_proposed_shipments
865
+ }.to raise_error(Spree::Order::CannotRebuildShipments)
866
+ }.not_to change { subject.reload.shipments }
867
+
868
+ expect { shipment.reload }.not_to raise_error
869
+ end
870
+
871
+ it "raises an error if any shipments are shipped" do
872
+ shipment = create(:shipment, order: subject, state: "shipped")
873
+ expect {
874
+ expect {
875
+ subject.create_proposed_shipments
876
+ }.to raise_error(Spree::Order::CannotRebuildShipments)
877
+ }.not_to change { subject.reload.shipments }
878
+
879
+ expect { shipment.reload }.not_to raise_error
880
+ end
881
+ end
882
+
883
+ describe "#all_inventory_units_returned?" do
884
+ let(:order) { create(:order_with_line_items, line_items_count: 3) }
885
+
886
+ subject { order.all_inventory_units_returned? }
887
+
888
+ context "all inventory units are returned" do
889
+ before { order.inventory_units.update_all(state: 'returned') }
890
+
891
+ it "is true" do
892
+ expect(subject).to eq true
893
+ end
894
+ end
895
+
896
+ context "some inventory units are returned" do
897
+ before do
898
+ order.inventory_units.first.update_attribute(:state, 'returned')
899
+ end
900
+
901
+ it "is false" do
902
+ expect(subject).to eq false
903
+ end
904
+ end
905
+
906
+ context "no inventory units are returned" do
907
+ it "is false" do
908
+ expect(subject).to eq false
909
+ end
910
+ end
911
+ end
912
+
913
+ describe "#unreturned_exchange?" do
914
+ let(:order) { create(:order_with_line_items) }
915
+ subject { order.reload.unreturned_exchange? }
916
+
917
+ context "the order does not have a shipment" do
918
+ before { order.shipments.destroy_all }
919
+
920
+ it { is_expected.to be false }
921
+ end
922
+
923
+ context "shipment created after order" do
924
+ it { is_expected.to be false }
925
+ end
926
+
927
+ context "shipment created before order" do
928
+ before do
929
+ order.shipments.first.update_attributes!(created_at: order.created_at - 1.day)
930
+ end
931
+
932
+ it { is_expected.to be true }
933
+ end
934
+ end
935
+
936
+ describe '.unreturned_exchange' do
937
+ let(:order) { create(:order_with_line_items) }
938
+ subject { described_class.unreturned_exchange }
939
+
940
+ it 'includes orders that have a shipment created prior to the order' do
941
+ order.shipments.first.update_attributes!(created_at: order.created_at - 1.day)
942
+ expect(subject).to include order
943
+ end
944
+
945
+ it 'excludes orders that were created prior to their shipment' do
946
+ expect(subject).not_to include order
947
+ end
948
+
949
+ it 'excludes orders with no shipment' do
950
+ order.shipments.destroy_all
951
+ expect(subject).not_to include order
952
+ end
953
+ end
954
+
955
+ describe "#fully_discounted?" do
956
+ let(:line_item) { Spree::LineItem.new(price: 10, quantity: 1) }
957
+ let(:shipment) { Spree::Shipment.new(cost: 10) }
958
+ let(:payment) { Spree::Payment.new(amount: 10) }
959
+
960
+ before do
961
+ allow(order).to receive(:line_items) { [line_item] }
962
+ allow(order).to receive(:shipments) { [shipment] }
963
+ allow(order).to receive(:payments) { [payment] }
964
+ end
965
+
966
+ context "the order had no inventory-related cost" do
967
+ before do
968
+ # discount the cost of the line items
969
+ allow(order).to receive(:adjustment_total) { -5 }
970
+ allow(line_item).to receive(:adjustment_total) { -5 }
971
+
972
+ # but leave some shipment payment amount
973
+ allow(shipment).to receive(:adjustment_total) { 0 }
974
+ end
975
+
976
+ it { expect(order.fully_discounted?).to eq true }
977
+
978
+ end
979
+
980
+ context "the order had inventory-related cost" do
981
+ before do
982
+ # partially discount the cost of the line item
983
+ allow(order).to receive(:adjustment_total) { 0 }
984
+ allow(line_item).to receive(:adjustment_total) { -5 }
985
+
986
+ # and partially discount the cost of the shipment so the total
987
+ # discount matches the item total for test completeness
988
+ allow(shipment).to receive(:adjustment_total) { -5 }
989
+ end
990
+
991
+ it { expect(order.fully_discounted?).to eq false }
992
+
993
+ end
994
+ end
995
+
996
+ context "store credit" do
997
+ shared_examples "check total store credit from payments" do
998
+ context "with valid payments" do
999
+ let(:order) { payment.order }
1000
+ let!(:payment) { create(:store_credit_payment) }
1001
+ let!(:second_payment) { create(:store_credit_payment, order: order) }
1002
+
1003
+ subject { order }
1004
+
1005
+ it "returns the sum of the payment amounts" do
1006
+ expect(subject.total_applicable_store_credit).to eq (payment.amount + second_payment.amount)
1007
+ end
1008
+ end
1009
+
1010
+ context "without valid payments" do
1011
+ let(:order) { create(:order) }
1012
+
1013
+ subject { order }
1014
+
1015
+ it "returns 0" do
1016
+ expect(subject.total_applicable_store_credit).to be_zero
1017
+ end
1018
+ end
1019
+ end
1020
+
1021
+ describe "#add_store_credit_payments" do
1022
+ let(:order_total) { 500.00 }
1023
+
1024
+ before { create(:store_credit_payment_method) }
1025
+
1026
+ subject { order.add_store_credit_payments }
1027
+
1028
+ context "there is no store credit" do
1029
+ let(:order) { create(:order, total: order_total) }
1030
+
1031
+ context "there is a credit card payment" do
1032
+ let!(:cc_payment) { create(:payment, order: order, amount: order_total) }
1033
+
1034
+ before do
1035
+ # callbacks recalculate total based on line items
1036
+ # this ensures the total is what we expect
1037
+ order.update_column(:total, order_total)
1038
+ subject
1039
+ order.reload
1040
+ end
1041
+
1042
+ it "charges the outstanding balance to the credit card" do
1043
+ expect(order.errors.messages).to be_empty
1044
+ expect(order.payments.count).to eq 1
1045
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1046
+ expect(order.payments.first.amount).to eq order_total
1047
+ end
1048
+ end
1049
+
1050
+ context "there are no other payments" do
1051
+ it "adds an error to the model" do
1052
+ expect(subject).to be false
1053
+ expect(order.errors.full_messages).to include(Spree.t("store_credit.errors.unable_to_fund"))
1054
+ end
1055
+ end
1056
+ end
1057
+
1058
+ context "there is enough store credit to pay for the entire order" do
1059
+ let(:store_credit) { create(:store_credit, amount: order_total) }
1060
+ let(:order) { create(:order_with_totals, user: store_credit.user, line_items_price: order_total).tap(&:update!) }
1061
+
1062
+ context "there are no other payments" do
1063
+ before do
1064
+ subject
1065
+ order.reload
1066
+ end
1067
+
1068
+ it "creates a store credit payment for the full amount" do
1069
+ expect(order.errors.messages).to be_empty
1070
+ expect(order.payments.count).to eq 1
1071
+ expect(order.payments.first).to be_store_credit
1072
+ expect(order.payments.first.amount).to eq order_total
1073
+ end
1074
+ end
1075
+
1076
+ context "there is a credit card payment" do
1077
+ it "invalidates the credit card payment" do
1078
+ cc_payment = create(:payment, order: order)
1079
+ expect { subject }.to change { cc_payment.reload.state }.to 'invalid'
1080
+ end
1081
+ end
1082
+ end
1083
+
1084
+ context "the available store credit is not enough to pay for the entire order" do
1085
+ let(:order_total) { 500 }
1086
+ let(:store_credit_total) { order_total - 100 }
1087
+ let(:store_credit) { create(:store_credit, amount: store_credit_total) }
1088
+ let(:order) { create(:order_with_totals, user: store_credit.user, line_items_price: order_total).tap(&:update!) }
1089
+
1090
+ context "there are no other payments" do
1091
+ it "adds an error to the model" do
1092
+ expect(subject).to be false
1093
+ expect(order.errors.full_messages).to include(Spree.t("store_credit.errors.unable_to_fund"))
1094
+ end
1095
+ end
1096
+
1097
+ context "there is a credit card payment" do
1098
+ let!(:cc_payment) { create(:payment, order: order, state: "checkout") }
1099
+
1100
+ before do
1101
+ subject
1102
+ end
1103
+
1104
+ it "charges the outstanding balance to the credit card" do
1105
+ expect(order.errors.messages).to be_empty
1106
+ expect(order.payments.count).to eq 2
1107
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1108
+ expect(order.payments.first.amount).to eq 100
1109
+ end
1110
+
1111
+ # see associated comment in order_decorator#add_store_credit_payments
1112
+ context "the store credit is already in the pending state" do
1113
+ before do
1114
+ order.payments.store_credits.last.authorize!
1115
+ order.add_store_credit_payments
1116
+ end
1117
+
1118
+ it "charges the outstanding balance to the credit card" do
1119
+ expect(order.errors.messages).to be_empty
1120
+ expect(order.payments.count).to eq 2
1121
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1122
+ expect(order.payments.first.amount).to eq 100
1123
+ end
1124
+ end
1125
+ end
1126
+ end
1127
+
1128
+ context "there are multiple store credits" do
1129
+ context "they have different credit type priorities" do
1130
+ let(:amount_difference) { 100 }
1131
+ let!(:primary_store_credit) { create(:store_credit, amount: (order_total - amount_difference)) }
1132
+ let!(:secondary_store_credit) { create(:store_credit, amount: order_total, user: primary_store_credit.user, credit_type: create(:secondary_credit_type)) }
1133
+ let(:order) { create(:order_with_totals, user: primary_store_credit.user, line_items_price: order_total).tap(&:update!) }
1134
+
1135
+ before do
1136
+ subject
1137
+ order.reload
1138
+ end
1139
+
1140
+ it "uses the primary store credit type over the secondary" do
1141
+ primary_payment = order.payments.detect{|x| x.source == primary_store_credit }
1142
+ secondary_payment = order.payments.detect{|x| x.source == secondary_store_credit }
1143
+
1144
+ expect(order.payments.size).to eq 2
1145
+ expect(primary_payment.source).to eq primary_store_credit
1146
+ expect(secondary_payment.source).to eq secondary_store_credit
1147
+ expect(primary_payment.amount).to eq(order_total - amount_difference)
1148
+ expect(secondary_payment.amount).to eq(amount_difference)
1149
+ end
1150
+ end
1151
+ end
1152
+ end
1153
+
1154
+ describe "#covered_by_store_credit" do
1155
+ context "order doesn't have an associated user" do
1156
+ subject { create(:order, user: nil) }
1157
+
1158
+ it "returns false" do
1159
+ expect(subject.covered_by_store_credit).to be false
1160
+ end
1161
+ end
1162
+
1163
+ context "order has an associated user" do
1164
+ let(:user) { create(:user) }
1165
+
1166
+ subject { create(:order, user: user) }
1167
+
1168
+ context "user has enough store credit to pay for the order" do
1169
+ before do
1170
+ allow(user).to receive_messages(total_available_store_credit: 10.0)
1171
+ allow(subject).to receive_messages(total: 5.0)
1172
+ end
1173
+
1174
+ it "returns true" do
1175
+ expect(subject.covered_by_store_credit).to be true
1176
+ end
1177
+ end
1178
+
1179
+ context "user does not have enough store credit to pay for the order" do
1180
+ before do
1181
+ allow(user).to receive_messages(total_available_store_credit: 0.0)
1182
+ allow(subject).to receive_messages(total: 5.0)
1183
+ end
1184
+
1185
+ it "returns false" do
1186
+ expect(subject.covered_by_store_credit).to be false
1187
+ end
1188
+ end
1189
+ end
1190
+ end
1191
+
1192
+ describe "#total_available_store_credit" do
1193
+ context "order does not have an associated user" do
1194
+ subject { create(:order, user: nil) }
1195
+
1196
+ it "returns 0" do
1197
+ expect(subject.total_available_store_credit).to be_zero
1198
+ end
1199
+ end
1200
+
1201
+ context "order has an associated user" do
1202
+ let(:user) { create(:user) }
1203
+ let(:available_store_credit) { 25.0 }
1204
+
1205
+ subject { create(:order, user: user) }
1206
+
1207
+ before do
1208
+ allow(user).to receive_messages(total_available_store_credit: available_store_credit)
1209
+ end
1210
+
1211
+ it "returns the user's available store credit" do
1212
+ expect(subject.total_available_store_credit).to eq available_store_credit
1213
+ end
1214
+ end
1215
+ end
1216
+
1217
+ describe "#order_total_after_store_credit" do
1218
+ let(:order_total) { 100.0 }
1219
+
1220
+ subject { create(:order, total: order_total) }
1221
+
1222
+ before do
1223
+ allow(subject).to receive_messages(total_applicable_store_credit: applicable_store_credit)
1224
+ end
1225
+
1226
+ context "order's user has store credits" do
1227
+ let(:applicable_store_credit) { 10.0 }
1228
+
1229
+ it "deducts the applicable store credit" do
1230
+ expect(subject.order_total_after_store_credit).to eq (order_total - applicable_store_credit)
1231
+ end
1232
+ end
1233
+
1234
+ context "order's user does not have any store credits" do
1235
+ let(:applicable_store_credit) { 0.0 }
1236
+
1237
+ it "returns the order total" do
1238
+ expect(subject.order_total_after_store_credit).to eq order_total
1239
+ end
1240
+ end
1241
+ end
1242
+
1243
+ describe "#total_applicable_store_credit" do
1244
+ context "order is in the confirm state" do
1245
+ before { order.update_attributes(state: 'confirm') }
1246
+ include_examples "check total store credit from payments"
1247
+ end
1248
+
1249
+ context "order is completed" do
1250
+ before { order.update_attributes(state: 'complete') }
1251
+ include_examples "check total store credit from payments"
1252
+ end
1253
+
1254
+ context "order is in any state other than confirm or complete" do
1255
+ context "the associated user has store credits" do
1256
+ let(:store_credit) { create(:store_credit) }
1257
+ let(:order) { create(:order, user: store_credit.user) }
1258
+
1259
+ subject { order }
1260
+
1261
+ context "the store credit is more than the order total" do
1262
+ let(:order_total) { store_credit.amount - 1 }
1263
+
1264
+ before { order.update_attributes(total: order_total) }
1265
+
1266
+ it "returns the order total" do
1267
+ expect(subject.total_applicable_store_credit).to eq order_total
1268
+ end
1269
+ end
1270
+
1271
+ context "the store credit is less than the order total" do
1272
+ let(:order_total) { store_credit.amount * 10 }
1273
+
1274
+ before { order.update_attributes(total: order_total) }
1275
+
1276
+ it "returns the store credit amount" do
1277
+ expect(subject.total_applicable_store_credit).to eq store_credit.amount
1278
+ end
1279
+ end
1280
+ end
1281
+
1282
+ context "the associated user does not have store credits" do
1283
+ let(:order) { create(:order) }
1284
+
1285
+ subject { order }
1286
+
1287
+ it "returns 0" do
1288
+ expect(subject.total_applicable_store_credit).to be_zero
1289
+ end
1290
+ end
1291
+
1292
+ context "the order does not have an associated user" do
1293
+ subject { create(:order, user: nil) }
1294
+
1295
+ it "returns 0" do
1296
+ expect(subject.total_applicable_store_credit).to be_zero
1297
+ end
1298
+ end
1299
+ end
1300
+ end
1301
+
1302
+ describe "#display_total_applicable_store_credit" do
1303
+ let(:total_applicable_store_credit) { 10.00 }
1304
+
1305
+ subject { create(:order) }
1306
+
1307
+ before { allow(subject).to receive_messages(total_applicable_store_credit: total_applicable_store_credit) }
1308
+
1309
+ it "returns a money instance" do
1310
+ expect(subject.display_total_applicable_store_credit).to be_a(Spree::Money)
1311
+ end
1312
+
1313
+ it "returns a negative amount" do
1314
+ expect(subject.display_total_applicable_store_credit.money.cents).to eq (total_applicable_store_credit * -100.0)
1315
+ end
1316
+ end
1317
+
1318
+ describe "#display_order_total_after_store_credit" do
1319
+ let(:order_total_after_store_credit) { 10.00 }
1320
+
1321
+ subject { create(:order) }
1322
+
1323
+ before { allow(subject).to receive_messages(order_total_after_store_credit: order_total_after_store_credit) }
1324
+
1325
+ it "returns a money instance" do
1326
+ expect(subject.display_order_total_after_store_credit).to be_a(Spree::Money)
1327
+ end
1328
+
1329
+ it "returns the order_total_after_store_credit amount" do
1330
+ expect(subject.display_order_total_after_store_credit.money.cents).to eq (order_total_after_store_credit * 100.0)
1331
+ end
1332
+ end
1333
+
1334
+ describe "#display_total_available_store_credit" do
1335
+ let(:total_available_store_credit) { 10.00 }
1336
+
1337
+ subject { create(:order) }
1338
+
1339
+ before { allow(subject).to receive_messages(total_available_store_credit: total_available_store_credit) }
1340
+
1341
+ it "returns a money instance" do
1342
+ expect(subject.display_total_available_store_credit).to be_a(Spree::Money)
1343
+ end
1344
+
1345
+ it "returns the total_available_store_credit amount" do
1346
+ expect(subject.display_total_available_store_credit.money.cents).to eq (total_available_store_credit * 100.0)
1347
+ end
1348
+ end
1349
+
1350
+ describe "#display_store_credit_remaining_after_capture" do
1351
+ let(:total_available_store_credit) { 10.00 }
1352
+ let(:total_applicable_store_credit) { 5.00 }
1353
+
1354
+ subject { create(:order) }
1355
+
1356
+ before do
1357
+ allow(subject).to receive_messages(total_available_store_credit: total_available_store_credit,
1358
+ total_applicable_store_credit: total_applicable_store_credit)
1359
+ end
1360
+
1361
+ it "returns a money instance" do
1362
+ expect(subject.display_store_credit_remaining_after_capture).to be_a(Spree::Money)
1363
+ end
1364
+
1365
+ it "returns all of the user's available store credit minus what's applied to the order amount" do
1366
+ amount_remaining = total_available_store_credit - total_applicable_store_credit
1367
+ expect(subject.display_store_credit_remaining_after_capture.money.cents).to eq (amount_remaining * 100.0)
1368
+ end
1369
+ end
1370
+
1371
+ context 'when not capturing at order completion' do
1372
+ let!(:store_credit_payment_method) do
1373
+ create(
1374
+ :store_credit_payment_method,
1375
+ auto_capture: false, # not capturing at completion time
1376
+ )
1377
+ end
1378
+
1379
+ describe '#after_cancel' do
1380
+ let(:user) { create(:user) }
1381
+ let!(:store_credit) do
1382
+ create(:store_credit, amount: 100, user: user)
1383
+ end
1384
+ let(:order) do
1385
+ create(
1386
+ :order_with_line_items,
1387
+ user: user,
1388
+ line_items_count: 1,
1389
+ # order will be $20 total:
1390
+ line_items_price: 10,
1391
+ shipment_cost: 10,
1392
+ )
1393
+ end
1394
+
1395
+ before do
1396
+ order.contents.advance
1397
+ order.complete!
1398
+ end
1399
+
1400
+ it 'releases the pending store credit authorization' do
1401
+ expect {
1402
+ order.cancel!
1403
+ }.to change {
1404
+ store_credit.reload.amount_authorized
1405
+ }.from(20).to(0)
1406
+
1407
+ expect(store_credit.amount_remaining).to eq 100
1408
+ end
1409
+ end
1410
+ end
1411
+ end
1412
+ end