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,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