spree_core 3.0.5 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,228 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderInventory, :type => :model do
4
+ let(:order) { create :completed_order_with_totals }
5
+ let(:line_item) { order.line_items.first }
6
+
7
+ subject { described_class.new(order, line_item) }
8
+
9
+ context "when order is missing inventory units" do
10
+ before { line_item.update_column(:quantity, 2) }
11
+
12
+ it 'creates the proper number of inventory units' do
13
+ subject.verify
14
+ expect(subject.inventory_units.count).to eq 2
15
+ end
16
+ end
17
+
18
+ context "#add_to_shipment" do
19
+ let(:shipment) { order.shipments.first }
20
+
21
+ context "order is not completed" do
22
+ before { allow(order).to receive_messages completed?: false }
23
+
24
+ it "doesn't unstock items" do
25
+ expect(shipment.stock_location).not_to receive(:unstock)
26
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
27
+ end
28
+ end
29
+
30
+ context "inventory units state" do
31
+ before { shipment.inventory_units.destroy_all }
32
+
33
+ it 'sets inventory_units state as per stock location availability' do
34
+ expect(shipment.stock_location).to receive(:fill_status).with(subject.variant, 5).and_return([3, 2])
35
+
36
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
37
+
38
+ units = shipment.inventory_units_for(subject.variant).group_by(&:state)
39
+ expect(units['backordered'].size).to eq(2)
40
+ expect(units['on_hand'].size).to eq(3)
41
+ end
42
+ end
43
+
44
+ context "store doesnt track inventory" do
45
+ let(:variant) { create(:variant) }
46
+
47
+ before { Spree::Config.track_inventory_levels = false }
48
+
49
+ it "creates only on hand inventory units" do
50
+ variant.stock_items.destroy_all
51
+
52
+ # The before_save callback in LineItem would verify inventory
53
+ line_item = order.contents.add variant, 1, shipment: shipment
54
+
55
+ units = shipment.inventory_units_for(line_item.variant)
56
+ expect(units.count).to eq 1
57
+ expect(units.first).to be_on_hand
58
+ end
59
+ end
60
+
61
+ context "variant doesnt track inventory" do
62
+ let(:variant) { create(:variant) }
63
+ before { variant.track_inventory = false }
64
+
65
+ it "creates only on hand inventory units" do
66
+ variant.stock_items.destroy_all
67
+
68
+ line_item = order.contents.add variant, 1
69
+ subject.verify(shipment)
70
+
71
+ units = shipment.inventory_units_for(line_item.variant)
72
+ expect(units.count).to eq 1
73
+ expect(units.first).to be_on_hand
74
+ end
75
+ end
76
+
77
+ it 'should create stock_movement' do
78
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
79
+
80
+ stock_item = shipment.stock_location.stock_item(subject.variant)
81
+ movement = stock_item.stock_movements.last
82
+ # movement.originator.should == shipment
83
+ expect(movement.quantity).to eq(-5)
84
+ end
85
+ end
86
+
87
+ context "#determine_target_shipment" do
88
+ let(:stock_location) { create :stock_location }
89
+ let(:variant) { line_item.variant }
90
+
91
+ before do
92
+ subject.verify
93
+
94
+ order.shipments.create(:stock_location_id => stock_location.id, :cost => 5)
95
+
96
+ shipped = order.shipments.create(:stock_location_id => order.shipments.first.stock_location.id, :cost => 10)
97
+ shipped.update_column(:state, 'shipped')
98
+ end
99
+
100
+ it 'should select first non-shipped shipment that already contains given variant' do
101
+ shipment = subject.send(:determine_target_shipment)
102
+ expect(shipment.shipped?).to be false
103
+ expect(shipment.inventory_units_for(variant)).not_to be_empty
104
+
105
+ expect(variant.stock_location_ids.include?(shipment.stock_location_id)).to be true
106
+ end
107
+
108
+ context "when no shipments already contain this varint" do
109
+ before do
110
+ subject.line_item.reload
111
+ subject.inventory_units.destroy_all
112
+ end
113
+
114
+ it 'selects first non-shipped shipment that leaves from same stock_location' do
115
+ shipment = subject.send(:determine_target_shipment)
116
+ shipment.reload
117
+ expect(shipment.shipped?).to be false
118
+ expect(shipment.inventory_units_for(variant)).to be_empty
119
+ expect(variant.stock_location_ids.include?(shipment.stock_location_id)).to be true
120
+ end
121
+ end
122
+ end
123
+
124
+ context 'when order has too many inventory units' do
125
+ before do
126
+ line_item.quantity = 3
127
+ line_item.save!
128
+
129
+ line_item.update_column(:quantity, 2)
130
+ subject.line_item.reload
131
+ end
132
+
133
+ it 'should be a messed up order' do
134
+ expect(order.shipments.first.inventory_units_for(line_item.variant).size).to eq(3)
135
+ expect(line_item.quantity).to eq(2)
136
+ end
137
+
138
+ it 'should decrease the number of inventory units' do
139
+ subject.verify
140
+ expect(subject.inventory_units.count).to eq 2
141
+ end
142
+
143
+ context '#remove_from_shipment' do
144
+ let(:shipment) { order.shipments.first }
145
+ let(:variant) { subject.variant }
146
+
147
+ context "order is not completed" do
148
+ before { allow(order).to receive_messages completed?: false }
149
+
150
+ it "doesn't restock items" do
151
+ expect(shipment.stock_location).not_to receive(:restock)
152
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
153
+ end
154
+ end
155
+
156
+ it 'should create stock_movement' do
157
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
158
+
159
+ stock_item = shipment.stock_location.stock_item(variant)
160
+ movement = stock_item.stock_movements.last
161
+ # movement.originator.should == shipment
162
+ expect(movement.quantity).to eq(1)
163
+ end
164
+
165
+ it 'should destroy backordered units first' do
166
+ allow(shipment).to receive_messages(inventory_units_for_item: [
167
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered'),
168
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand'),
169
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered')
170
+ ])
171
+
172
+ expect(shipment.inventory_units_for_item[0]).to receive(:destroy)
173
+ expect(shipment.inventory_units_for_item[1]).not_to receive(:destroy)
174
+ expect(shipment.inventory_units_for_item[2]).to receive(:destroy)
175
+
176
+ expect(subject.send(:remove_from_shipment, shipment, 2)).to eq(2)
177
+ end
178
+
179
+ it 'should destroy unshipped units first' do
180
+ allow(shipment).to receive_messages(inventory_units_for_item: [
181
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
182
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand')
183
+ ])
184
+
185
+ expect(shipment.inventory_units_for_item[0]).not_to receive(:destroy)
186
+ expect(shipment.inventory_units_for_item[1]).to receive(:destroy)
187
+
188
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
189
+ end
190
+
191
+ it 'only attempts to destroy as many units as are eligible, and return amount destroyed' do
192
+ allow(shipment).to receive_messages(inventory_units_for_item: [
193
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
194
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand')
195
+ ])
196
+
197
+ expect(shipment.inventory_units_for_item[0]).not_to receive(:destroy)
198
+ expect(shipment.inventory_units_for_item[1]).to receive(:destroy)
199
+
200
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
201
+ end
202
+
203
+ it 'should destroy self if not inventory units remain' do
204
+ allow(shipment.inventory_units).to receive_messages(:count => 0)
205
+ expect(shipment).to receive(:destroy)
206
+
207
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
208
+ end
209
+
210
+ context "inventory unit line item and variant points to different products" do
211
+ let(:different_line_item) { create(:line_item) }
212
+
213
+ let!(:different_inventory) do
214
+ shipment.set_up_inventory("on_hand", variant, order, different_line_item)
215
+ end
216
+
217
+ context "completed order" do
218
+ before { order.touch :completed_at }
219
+
220
+ it "removes only units that match both line item and variant" do
221
+ subject.send(:remove_from_shipment, shipment, shipment.inventory_units.count)
222
+ expect(different_inventory.reload).to be_persisted
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ # Regression tests for #2179
4
+ module Spree
5
+ describe OrderMerger, type: :model do
6
+ let(:variant) { create(:variant) }
7
+ let(:order_1) { Spree::Order.create }
8
+ let(:order_2) { Spree::Order.create }
9
+ let(:user) { stub_model(Spree::LegacyUser, email: "spree@example.com") }
10
+ let(:subject) { Spree::OrderMerger.new(order_1) }
11
+
12
+ it "destroys the other order" do
13
+ subject.merge!(order_2)
14
+ expect { order_2.reload }.to raise_error(ActiveRecord::RecordNotFound)
15
+ end
16
+
17
+ it "persist the merge" do
18
+ expect(subject).to receive(:persist_merge)
19
+ subject.merge!(order_2)
20
+ end
21
+
22
+ context "user is provided" do
23
+ it "assigns user to new order" do
24
+ subject.merge!(order_2, user)
25
+ expect(order_1.user).to eq user
26
+ end
27
+ end
28
+
29
+ context "merging together two orders with line items for the same variant" do
30
+ before do
31
+ order_1.contents.add(variant, 1)
32
+ order_2.contents.add(variant, 1)
33
+ end
34
+
35
+ specify do
36
+ subject.merge!(order_2, user)
37
+ expect(order_1.line_items.count).to eq(1)
38
+
39
+ line_item = order_1.line_items.first
40
+ expect(line_item.quantity).to eq(2)
41
+ expect(line_item.variant_id).to eq(variant.id)
42
+ end
43
+ end
44
+
45
+ context "merging using extension-specific line_item_comparison_hooks" do
46
+ before do
47
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
48
+ allow(Spree::Variant).to receive(:price_modifier_amount).and_return(0.00)
49
+ end
50
+
51
+ after do
52
+ # reset to avoid test pollution
53
+ Spree::Order.line_item_comparison_hooks = Set.new
54
+ end
55
+
56
+ context "2 equal line items" do
57
+ before do
58
+ @line_item_1 = order_1.contents.add(variant, 1, foos: {})
59
+ @line_item_2 = order_2.contents.add(variant, 1, foos: {})
60
+ end
61
+
62
+ specify do
63
+ expect(order_1).to receive(:foos_match).with(@line_item_1, kind_of(Hash)).and_return(true)
64
+ subject.merge!(order_2)
65
+ expect(order_1.line_items.count).to eq(1)
66
+
67
+ line_item = order_1.line_items.first
68
+ expect(line_item.quantity).to eq(2)
69
+ expect(line_item.variant_id).to eq(variant.id)
70
+ end
71
+ end
72
+
73
+ context "2 different line items" do
74
+ before do
75
+ allow(order_1).to receive(:foos_match).and_return(false)
76
+
77
+ order_1.contents.add(variant, 1, foos: {})
78
+ order_2.contents.add(variant, 1, foos: { bar: :zoo })
79
+ end
80
+
81
+ specify do
82
+ subject.merge!(order_2)
83
+ expect(order_1.line_items.count).to eq(2)
84
+
85
+ line_item = order_1.line_items.first
86
+ expect(line_item.quantity).to eq(1)
87
+ expect(line_item.variant_id).to eq(variant.id)
88
+
89
+ line_item = order_1.line_items.last
90
+ expect(line_item.quantity).to eq(1)
91
+ expect(line_item.variant_id).to eq(variant.id)
92
+ end
93
+ end
94
+ end
95
+
96
+ context "merging together two orders with different line items" do
97
+ let(:variant_2) { create(:variant) }
98
+
99
+ before do
100
+ order_1.contents.add(variant, 1)
101
+ order_2.contents.add(variant_2, 1)
102
+ end
103
+
104
+ specify do
105
+ subject.merge!(order_2)
106
+ line_items = order_1.line_items.reload
107
+ expect(line_items.count).to eq(2)
108
+
109
+ expect(order_1.item_count).to eq 2
110
+ expect(order_1.item_total).to eq line_items.map(&:amount).sum
111
+
112
+ # No guarantee on ordering of line items, so we do this:
113
+ expect(line_items.pluck(:quantity)).to match_array([1, 1])
114
+ expect(line_items.pluck(:variant_id)).to match_array([variant.id, variant_2.id])
115
+ end
116
+ end
117
+
118
+ context "merging together orders with invalid line items" do
119
+ let(:variant_2) { create(:variant) }
120
+
121
+ before do
122
+ order_1.contents.add(variant, 1)
123
+ order_2.contents.add(variant_2, 1)
124
+ end
125
+
126
+ it "should create errors with invalid line items" do
127
+ variant_2.destroy
128
+ subject.merge!(order_2)
129
+ expect(order_1.errors.full_messages).not_to be_empty
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,954 @@
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
+ create(:store)
15
+ allow(Spree::LegacyUser).to receive_messages(:current => mock_model(Spree::LegacyUser, :id => 123))
16
+ end
17
+
18
+ context "#cancel" do
19
+ let(:order) { create(:completed_order_with_totals) }
20
+ let!(:payment) do
21
+ create(
22
+ :payment,
23
+ order: order,
24
+ amount: order.total,
25
+ state: "completed"
26
+ )
27
+ end
28
+ let(:payment_method) { double }
29
+
30
+ it "should mark the payments as void" do
31
+ allow_any_instance_of(Spree::Shipment).to receive(:refresh_rates).and_return(true)
32
+ order.cancel
33
+ order.reload
34
+
35
+ expect(order.payments.first).to be_void
36
+ end
37
+ end
38
+
39
+ context "#canceled_by" do
40
+ let(:admin_user) { create :admin_user }
41
+ let(:order) { create :order }
42
+
43
+ before do
44
+ allow(order).to receive(:cancel!)
45
+ end
46
+
47
+ subject { order.canceled_by(admin_user) }
48
+
49
+ it 'should cancel the order' do
50
+ expect(order).to receive(:cancel!)
51
+ subject
52
+ end
53
+
54
+ it 'should save canceler_id' do
55
+ subject
56
+ expect(order.reload.canceler_id).to eq(admin_user.id)
57
+ end
58
+
59
+ it 'should save canceled_at' do
60
+ subject
61
+ expect(order.reload.canceled_at).to_not be_nil
62
+ end
63
+
64
+ it 'should have canceler' do
65
+ subject
66
+ expect(order.reload.canceler).to eq(admin_user)
67
+ end
68
+ end
69
+
70
+ context "#create" do
71
+ let(:order) { Spree::Order.create }
72
+
73
+ it "should assign an order number" do
74
+ expect(order.number).not_to be_nil
75
+ end
76
+
77
+ it 'should create a randomized 22 character token' do
78
+ expect(order.guest_token.size).to eq(22)
79
+ end
80
+ end
81
+
82
+ context "creates shipments cost" do
83
+ let(:shipment) { double }
84
+
85
+ before { allow(order).to receive_messages shipments: [shipment] }
86
+
87
+ it "update and persist totals" do
88
+ expect(shipment).to receive :update_amounts
89
+ expect(order.updater).to receive :update_shipment_total
90
+ expect(order.updater).to receive :persist_totals
91
+
92
+ order.set_shipments_cost
93
+ end
94
+ end
95
+
96
+ context "#finalize!" do
97
+ let(:order) { Spree::Order.create(email: 'test@example.com') }
98
+
99
+ before do
100
+ order.update_column :state, 'complete'
101
+ end
102
+
103
+ it "should set completed_at" do
104
+ expect(order).to receive(:touch).with(:completed_at)
105
+ order.finalize!
106
+ end
107
+
108
+ it "should sell inventory units" do
109
+ order.shipments.each do |shipment|
110
+ expect(shipment).to receive(:update!)
111
+ expect(shipment).to receive(:finalize!)
112
+ end
113
+ order.finalize!
114
+ end
115
+
116
+ it "should decrease the stock for each variant in the shipment" do
117
+ order.shipments.each do |shipment|
118
+ expect(shipment.stock_location).to receive(:decrease_stock_for_variant)
119
+ end
120
+ order.finalize!
121
+ end
122
+
123
+ it "should change the shipment state to ready if order is paid" do
124
+ Spree::Shipment.create(order: order, stock_location: create(:stock_location))
125
+ order.shipments.reload
126
+
127
+ allow(order).to receive_messages(paid?: true, complete?: true)
128
+ order.finalize!
129
+ order.reload # reload so we're sure the changes are persisted
130
+ expect(order.shipment_state).to eq('ready')
131
+ end
132
+
133
+ after { Spree::Config.set track_inventory_levels: true }
134
+ it "should not sell inventory units if track_inventory_levels is false" do
135
+ Spree::Config.set track_inventory_levels: false
136
+ expect(Spree::InventoryUnit).not_to receive(:sell_units)
137
+ order.finalize!
138
+ end
139
+
140
+ it "should send an order confirmation email" do
141
+ mail_message = double "Mail::Message"
142
+ expect(Spree::OrderMailer).to receive(:confirm_email).with(order.id).and_return mail_message
143
+ expect(mail_message).to receive :deliver_later
144
+ order.finalize!
145
+ end
146
+
147
+ it "sets confirmation delivered when finalizing" do
148
+ expect(order.confirmation_delivered?).to be false
149
+ order.finalize!
150
+ expect(order.confirmation_delivered?).to be true
151
+ end
152
+
153
+ it "should not send duplicate confirmation emails" do
154
+ allow(order).to receive_messages(:confirmation_delivered? => true)
155
+ expect(Spree::OrderMailer).not_to receive(:confirm_email)
156
+ order.finalize!
157
+ end
158
+
159
+ it "should freeze all adjustments" do
160
+ # Stub this method as it's called due to a callback
161
+ # and it's irrelevant to this test
162
+ allow(order).to receive :has_available_shipment
163
+ allow(Spree::OrderMailer).to receive_message_chain :confirm_email, :deliver_later
164
+ adjustments = [double]
165
+ expect(order).to receive(:all_adjustments).and_return(adjustments)
166
+ adjustments.each do |adj|
167
+ expect(adj).to receive(:close)
168
+ end
169
+ order.finalize!
170
+ end
171
+
172
+ context "order is considered risky" do
173
+ before do
174
+ allow(order).to receive_messages :is_risky? => true
175
+ end
176
+
177
+ it "should change state to risky" do
178
+ expect(order).to receive(:considered_risky!)
179
+ order.finalize!
180
+ end
181
+
182
+ context "and order is approved" do
183
+ before do
184
+ allow(order).to receive_messages :approved? => true
185
+ end
186
+
187
+ it "should leave order in complete state" do
188
+ order.finalize!
189
+ expect(order.state).to eq 'complete'
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ context "insufficient_stock_lines" do
196
+ let(:line_item) { mock_model Spree::LineItem, :insufficient_stock? => true }
197
+
198
+ before { allow(order).to receive_messages(:line_items => [line_item]) }
199
+
200
+ it "should return line_item that has insufficient stock on hand" do
201
+ expect(order.insufficient_stock_lines.size).to eq(1)
202
+ expect(order.insufficient_stock_lines.include?(line_item)).to be true
203
+ end
204
+ end
205
+
206
+ describe '#ensure_line_item_variants_are_not_deleted' do
207
+ subject { order.ensure_line_item_variants_are_not_deleted }
208
+
209
+ let(:order) { create :order_with_line_items }
210
+
211
+ context 'when variant is destroyed' do
212
+ before do
213
+ allow(order).to receive(:restart_checkout_flow)
214
+ order.line_items.first.variant.destroy
215
+ end
216
+
217
+ it 'should restart checkout flow' do
218
+ expect(order).to receive(:restart_checkout_flow).once
219
+ subject
220
+ end
221
+
222
+ it 'should have error message' do
223
+ subject
224
+ expect(order.errors[:base]).to include(Spree.t(:deleted_variants_present))
225
+ end
226
+
227
+ it 'should be false' do
228
+ expect(subject).to be_falsey
229
+ end
230
+ end
231
+
232
+ context 'when no variants are destroyed' do
233
+ it 'should not restart checkout' do
234
+ expect(order).to receive(:restart_checkout_flow).never
235
+ subject
236
+ end
237
+
238
+ it 'should be true' do
239
+ expect(subject).to be_truthy
240
+ end
241
+ end
242
+ end
243
+
244
+ describe '#ensure_line_items_are_in_stock' do
245
+ subject { order.ensure_line_items_are_in_stock }
246
+
247
+ let(:line_item) { mock_model Spree::LineItem, :insufficient_stock? => true }
248
+
249
+ before do
250
+ allow(order).to receive(:restart_checkout_flow)
251
+ allow(order).to receive_messages(:line_items => [line_item])
252
+ end
253
+
254
+ it 'should restart checkout flow' do
255
+ expect(order).to receive(:restart_checkout_flow).once
256
+ subject
257
+ end
258
+
259
+ it 'should have error message' do
260
+ subject
261
+ expect(order.errors[:base]).to include(Spree.t(:insufficient_stock_lines_present))
262
+ end
263
+
264
+ it 'should be false' do
265
+ expect(subject).to be_falsey
266
+ end
267
+ end
268
+
269
+ context "empty!" do
270
+ let(:order) { stub_model(Spree::Order, item_count: 2) }
271
+
272
+ before do
273
+ allow(order).to receive_messages(line_items: [1, 2])
274
+ allow(order).to receive_messages(adjustments: [])
275
+ allow(order).to receive_message_chain(:line_items, sum: 0)
276
+ end
277
+
278
+ it "clears out line items, adjustments and update totals" do
279
+ expect(order.line_items).to receive(:destroy_all)
280
+ expect(order.adjustments).to receive(:destroy_all)
281
+ expect(order.shipments).to receive(:destroy_all)
282
+ expect(order.updater).to receive(:update_totals)
283
+ expect(order.updater).to receive(:persist_totals)
284
+
285
+ order.empty!
286
+ expect(order.item_total).to eq 0
287
+ end
288
+ end
289
+
290
+ context "#display_outstanding_balance" do
291
+ it "returns the value as a spree money" do
292
+ allow(order).to receive(:outstanding_balance) { 10.55 }
293
+ expect(order.display_outstanding_balance).to eq(Spree::Money.new(10.55))
294
+ end
295
+ end
296
+
297
+ context "#display_item_total" do
298
+ it "returns the value as a spree money" do
299
+ allow(order).to receive(:item_total) { 10.55 }
300
+ expect(order.display_item_total).to eq(Spree::Money.new(10.55))
301
+ end
302
+ end
303
+
304
+ context "#display_adjustment_total" do
305
+ it "returns the value as a spree money" do
306
+ order.adjustment_total = 10.55
307
+ expect(order.display_adjustment_total).to eq(Spree::Money.new(10.55))
308
+ end
309
+ end
310
+
311
+ context "#display_promo_total" do
312
+ it "returns the value as a spree money" do
313
+ order.promo_total = 10.55
314
+ expect(order.display_promo_total).to eq(Spree::Money.new(10.55))
315
+ end
316
+ end
317
+
318
+ context "#display_total" do
319
+ it "returns the value as a spree money" do
320
+ order.total = 10.55
321
+ expect(order.display_total).to eq(Spree::Money.new(10.55))
322
+ end
323
+ end
324
+
325
+ context "#currency" do
326
+ context "when object currency is ABC" do
327
+ before { order.currency = "ABC" }
328
+
329
+ it "returns the currency from the object" do
330
+ expect(order.currency).to eq("ABC")
331
+ end
332
+ end
333
+
334
+ context "when object currency is nil" do
335
+ before { order.currency = nil }
336
+
337
+ it "returns the globally configured currency" do
338
+ expect(order.currency).to eq("USD")
339
+ end
340
+ end
341
+ end
342
+
343
+ context "#confirmation_required?" do
344
+
345
+ # Regression test for #4117
346
+ it "is required if the state is currently 'confirm'" do
347
+ order = Spree::Order.new
348
+ assert !order.confirmation_required?
349
+ order.state = 'confirm'
350
+ assert order.confirmation_required?
351
+ end
352
+
353
+ context 'Spree::Config[:always_include_confirm_step] == true' do
354
+
355
+ before do
356
+ Spree::Config[:always_include_confirm_step] = true
357
+ end
358
+
359
+ it "returns true if payments empty" do
360
+ order = Spree::Order.new
361
+ assert order.confirmation_required?
362
+ end
363
+ end
364
+
365
+ context 'Spree::Config[:always_include_confirm_step] == false' do
366
+
367
+ it "returns false if payments empty and Spree::Config[:always_include_confirm_step] == false" do
368
+ order = Spree::Order.new
369
+ assert !order.confirmation_required?
370
+ end
371
+
372
+ it "does not bomb out when an order has an unpersisted payment" do
373
+ order = Spree::Order.new
374
+ order.payments.build
375
+ assert !order.confirmation_required?
376
+ end
377
+ end
378
+ end
379
+
380
+
381
+ context "add_update_hook" do
382
+ before do
383
+ Spree::Order.class_eval do
384
+ register_update_hook :add_awesome_sauce
385
+ end
386
+ end
387
+
388
+ after do
389
+ Spree::Order.update_hooks = Set.new
390
+ end
391
+
392
+ it "calls hook during update" do
393
+ order = create(:order)
394
+ expect(order).to receive(:add_awesome_sauce)
395
+ order.update!
396
+ end
397
+
398
+ it "calls hook during finalize" do
399
+ order = create(:order)
400
+ expect(order).to receive(:add_awesome_sauce)
401
+ order.finalize!
402
+ end
403
+ end
404
+
405
+ describe "#tax_address" do
406
+ before { Spree::Config[:tax_using_ship_address] = tax_using_ship_address }
407
+ subject { order.tax_address }
408
+
409
+ context "when tax_using_ship_address is true" do
410
+ let(:tax_using_ship_address) { true }
411
+
412
+ it 'returns ship_address' do
413
+ expect(subject).to eq(order.ship_address)
414
+ end
415
+ end
416
+
417
+ context "when tax_using_ship_address is not true" do
418
+ let(:tax_using_ship_address) { false }
419
+
420
+ it "returns bill_address" do
421
+ expect(subject).to eq(order.bill_address)
422
+ end
423
+ end
424
+ end
425
+
426
+ describe "#restart_checkout_flow" do
427
+ it "updates the state column to the first checkout_steps value" do
428
+ order = create(:order_with_totals, state: "delivery")
429
+ expect(order.checkout_steps).to eql ["address", "delivery", "complete"]
430
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("address")
431
+ end
432
+
433
+ context "without line items" do
434
+ it "updates the state column to cart" do
435
+ order = create(:order, state: "delivery")
436
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("cart")
437
+ end
438
+ end
439
+ end
440
+
441
+ # Regression tests for #4072
442
+ context "#state_changed" do
443
+ let(:order) { FactoryGirl.create(:order) }
444
+
445
+ it "logs state changes" do
446
+ order.update_column(:payment_state, 'balance_due')
447
+ order.payment_state = 'paid'
448
+ expect(order.state_changes).to be_empty
449
+ order.state_changed('payment')
450
+ state_change = order.state_changes.find_by(:name => 'payment')
451
+ expect(state_change.previous_state).to eq('balance_due')
452
+ expect(state_change.next_state).to eq('paid')
453
+ end
454
+
455
+ it "does not do anything if state does not change" do
456
+ order.update_column(:payment_state, 'balance_due')
457
+ expect(order.state_changes).to be_empty
458
+ order.state_changed('payment')
459
+ expect(order.state_changes).to be_empty
460
+ end
461
+ end
462
+
463
+ # Regression test for #4199
464
+ context "#available_payment_methods" do
465
+ it "includes frontend payment methods" do
466
+ payment_method = Spree::PaymentMethod.create!({
467
+ :name => "Fake",
468
+ :active => true,
469
+ :display_on => "front_end",
470
+ })
471
+ expect(order.available_payment_methods).to include(payment_method)
472
+ end
473
+
474
+ it "includes 'both' payment methods" do
475
+ payment_method = Spree::PaymentMethod.create!({
476
+ :name => "Fake",
477
+ :active => true,
478
+ :display_on => "both",
479
+ })
480
+ expect(order.available_payment_methods).to include(payment_method)
481
+ end
482
+
483
+ it "does not include a payment method twice if display_on is blank" do
484
+ payment_method = Spree::PaymentMethod.create!({
485
+ :name => "Fake",
486
+ :active => true,
487
+ :display_on => "both",
488
+ })
489
+ expect(order.available_payment_methods.count).to eq(1)
490
+ expect(order.available_payment_methods).to include(payment_method)
491
+ end
492
+ end
493
+
494
+ context "#apply_free_shipping_promotions" do
495
+ it "calls out to the FreeShipping promotion handler" do
496
+ shipment = double('Shipment')
497
+ allow(order).to receive_messages :shipments => [shipment]
498
+ expect(Spree::PromotionHandler::FreeShipping).to receive(:new).and_return(handler = double)
499
+ expect(handler).to receive(:activate)
500
+
501
+ expect(Spree::Adjustable::AdjustmentsUpdater).to receive(:update).with(shipment)
502
+
503
+ expect(order.updater).to receive(:update_shipment_total)
504
+ expect(order.updater).to receive(:persist_totals)
505
+ order.apply_free_shipping_promotions
506
+ end
507
+ end
508
+
509
+
510
+ context "#products" do
511
+ before :each do
512
+ @variant1 = mock_model(Spree::Variant, :product => "product1")
513
+ @variant2 = mock_model(Spree::Variant, :product => "product2")
514
+ @line_items = [mock_model(Spree::LineItem, :product => "product1", :variant => @variant1, :variant_id => @variant1.id, :quantity => 1),
515
+ mock_model(Spree::LineItem, :product => "product2", :variant => @variant2, :variant_id => @variant2.id, :quantity => 2)]
516
+ allow(order).to receive_messages(:line_items => @line_items)
517
+ end
518
+
519
+ it "gets the quantity of a given variant" do
520
+ expect(order.quantity_of(@variant1)).to eq(1)
521
+
522
+ @variant3 = mock_model(Spree::Variant, :product => "product3")
523
+ expect(order.quantity_of(@variant3)).to eq(0)
524
+ end
525
+
526
+ it "can find a line item matching a given variant" do
527
+ expect(order.find_line_item_by_variant(@variant1)).not_to be_nil
528
+ expect(order.find_line_item_by_variant(mock_model(Spree::Variant))).to be_nil
529
+ end
530
+
531
+ context "match line item with options" do
532
+ before do
533
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
534
+ end
535
+
536
+ after do
537
+ # reset to avoid test pollution
538
+ Spree::Order.line_item_comparison_hooks = Set.new
539
+ end
540
+
541
+ it "matches line item when options match" do
542
+ allow(order).to receive(:foos_match).and_return(true)
543
+ expect(order.line_item_options_match(@line_items.first, {foos: {bar: :zoo}})).to be true
544
+ end
545
+
546
+ it "does not match line item without options" do
547
+ allow(order).to receive(:foos_match).and_return(false)
548
+ expect(order.line_item_options_match(@line_items.first, {})).to be false
549
+ end
550
+ end
551
+ end
552
+
553
+ context "#generate_order_number" do
554
+ context "when no configure" do
555
+ let(:default_length) { 9 + 'R'.length }
556
+ subject(:order_number) { order.generate_number }
557
+ its(:class) { should eq String }
558
+ its(:length) { should eq default_length }
559
+ it { should match /^R/ }
560
+ end
561
+
562
+ context "when length option is 5" do
563
+ let(:option_length) { 5 + 'R'.length }
564
+ it "should be option length for order number" do
565
+ expect(order.generate_number(length: 5).length).to eq option_length
566
+ end
567
+ end
568
+
569
+ context "when letters option is true" do
570
+ it "generates order number include letter" do
571
+ expect(order.generate_number(length: 100, letters: true)).to match /[A-Z]/
572
+ end
573
+ end
574
+
575
+ context "when prefix option is 'P'" do
576
+ it "generates order number and it prefix is 'P'" do
577
+ expect(order.generate_number(prefix: 'P')).to match /^P/
578
+ end
579
+ end
580
+ end
581
+
582
+ describe "#associate_user!" do
583
+ let(:user) { FactoryGirl.create(:user_with_addreses) }
584
+ let(:email) { user.email }
585
+ let(:created_by) { user }
586
+ let(:bill_address) { user.bill_address }
587
+ let(:ship_address) { user.ship_address }
588
+ let(:override_email) { true }
589
+
590
+ let(:order) { FactoryGirl.build(:order, order_attributes) }
591
+
592
+ let(:order_attributes) do
593
+ {
594
+ user: nil,
595
+ email: nil,
596
+ created_by: nil,
597
+ bill_address: nil,
598
+ ship_address: nil
599
+ }
600
+ end
601
+
602
+ def assert_expected_order_state
603
+ expect(order.user).to eql(user)
604
+ expect(order.user_id).to eql(user.id)
605
+
606
+ expect(order.email).to eql(email)
607
+
608
+ expect(order.created_by).to eql(created_by)
609
+ expect(order.created_by_id).to eql(created_by.id)
610
+
611
+ expect(order.bill_address).to eql(bill_address)
612
+ expect(order.bill_address_id).to eql(bill_address.id)
613
+
614
+ expect(order.ship_address).to eql(ship_address)
615
+ expect(order.ship_address_id).to eql(ship_address.id)
616
+ end
617
+
618
+ shared_examples_for "#associate_user!" do |persisted = false|
619
+ it "associates a user to an order" do
620
+ order.associate_user!(user, override_email)
621
+ assert_expected_order_state
622
+ end
623
+
624
+ unless persisted
625
+ it "does not persist the order" do
626
+ expect { order.associate_user!(user) }
627
+ .to_not change(order, :persisted?)
628
+ .from(false)
629
+ end
630
+ end
631
+ end
632
+
633
+ context "when email is set" do
634
+ let(:order_attributes) { super().merge(email: 'test@example.com') }
635
+
636
+ context "when email should be overridden" do
637
+ it_should_behave_like "#associate_user!"
638
+ end
639
+
640
+ context "when email should not be overridden" do
641
+ let(:override_email) { false }
642
+ let(:email) { 'test@example.com' }
643
+
644
+ it_should_behave_like "#associate_user!"
645
+ end
646
+ end
647
+
648
+ context "when created_by is set" do
649
+ let(:order_attributes) { super().merge(created_by: created_by) }
650
+ let(:created_by) { create(:user_with_addreses) }
651
+
652
+ it_should_behave_like "#associate_user!"
653
+ end
654
+
655
+ context "when bill_address is set" do
656
+ let(:order_attributes) { super().merge(bill_address: bill_address) }
657
+ let(:bill_address) { FactoryGirl.build(:address) }
658
+
659
+ it_should_behave_like "#associate_user!"
660
+ end
661
+
662
+ context "when ship_address is set" do
663
+ let(:order_attributes) { super().merge(ship_address: ship_address) }
664
+ let(:ship_address) { FactoryGirl.build(:address) }
665
+
666
+ it_should_behave_like "#associate_user!"
667
+ end
668
+
669
+ context "when the user is not persisted" do
670
+ let(:user) { FactoryGirl.build(:user_with_addreses) }
671
+
672
+ it "does not persist the user" do
673
+ expect { order.associate_user!(user) }
674
+ .to_not change(user, :persisted?)
675
+ .from(false)
676
+ end
677
+
678
+ it_should_behave_like "#associate_user!"
679
+ end
680
+
681
+ context "when the order is persisted" do
682
+ let(:order) { FactoryGirl.create(:order, order_attributes) }
683
+
684
+ it "associates a user to a persisted order" do
685
+ order.associate_user!(user)
686
+ order.reload
687
+ assert_expected_order_state
688
+ end
689
+
690
+ it "does not persist other changes to the order" do
691
+ order.state = 'complete'
692
+ order.associate_user!(user)
693
+ order.reload
694
+ expect(order.state).to eql('cart')
695
+ end
696
+
697
+ it "does not change any other orders" do
698
+ other = FactoryGirl.create(:order)
699
+ order.associate_user!(user)
700
+ expect(other.reload.user).to_not eql(user)
701
+ end
702
+
703
+ it "is not affected by scoping" do
704
+ order.class.where.not(id: order).scoping do
705
+ order.associate_user!(user)
706
+ end
707
+ order.reload
708
+ assert_expected_order_state
709
+ end
710
+
711
+ it_should_behave_like "#associate_user!", true
712
+ end
713
+ end
714
+
715
+ context "#can_ship?" do
716
+ let(:order) { Spree::Order.create }
717
+
718
+ it "should be true for order in the 'complete' state" do
719
+ allow(order).to receive_messages(:complete? => true)
720
+ expect(order.can_ship?).to be true
721
+ end
722
+
723
+ it "should be true for order in the 'resumed' state" do
724
+ allow(order).to receive_messages(:resumed? => true)
725
+ expect(order.can_ship?).to be true
726
+ end
727
+
728
+ it "should be true for an order in the 'awaiting return' state" do
729
+ allow(order).to receive_messages(:awaiting_return? => true)
730
+ expect(order.can_ship?).to be true
731
+ end
732
+
733
+ it "should be true for an order in the 'returned' state" do
734
+ allow(order).to receive_messages(:returned? => true)
735
+ expect(order.can_ship?).to be true
736
+ end
737
+
738
+ it "should be false if the order is neither in the 'complete' nor 'resumed' state" do
739
+ allow(order).to receive_messages(:resumed? => false, :complete? => false)
740
+ expect(order.can_ship?).to be false
741
+ end
742
+ end
743
+
744
+ context "#completed?" do
745
+ it "should indicate if order is completed" do
746
+ order.completed_at = nil
747
+ expect(order.completed?).to be false
748
+
749
+ order.completed_at = Time.now
750
+ expect(order.completed?).to be true
751
+ end
752
+ end
753
+
754
+ context "#allow_checkout?" do
755
+ it "should be true if there are line_items in the order" do
756
+ allow(order).to receive_message_chain(:line_items, :count => 1)
757
+ expect(order.checkout_allowed?).to be true
758
+ end
759
+ it "should be false if there are no line_items in the order" do
760
+ allow(order).to receive_message_chain(:line_items, :count => 0)
761
+ expect(order.checkout_allowed?).to be false
762
+ end
763
+ end
764
+
765
+ context "#amount" do
766
+ before do
767
+ @order = create(:order, :user => user)
768
+ @order.line_items = [create(:line_item, :price => 1.0, :quantity => 2),
769
+ create(:line_item, :price => 1.0, :quantity => 1)]
770
+ end
771
+ it "should return the correct lum sum of items" do
772
+ expect(@order.amount).to eq(3.0)
773
+ end
774
+ end
775
+
776
+ context "#backordered?" do
777
+ it 'is backordered if one of the shipments is backordered' do
778
+ allow(order).to receive_messages(:shipments => [mock_model(Spree::Shipment, :backordered? => false),
779
+ mock_model(Spree::Shipment, :backordered? => true)])
780
+ expect(order).to be_backordered
781
+ end
782
+ end
783
+
784
+ context "#can_cancel?" do
785
+ it "should be false for completed order in the canceled state" do
786
+ order.state = 'canceled'
787
+ order.shipment_state = 'ready'
788
+ order.completed_at = Time.now
789
+ expect(order.can_cancel?).to be false
790
+ end
791
+
792
+ it "should be true for completed order with no shipment" do
793
+ order.state = 'complete'
794
+ order.shipment_state = nil
795
+ order.completed_at = Time.now
796
+ expect(order.can_cancel?).to be true
797
+ end
798
+ end
799
+
800
+ context "#tax_total" do
801
+ it "adds included tax and additional tax" do
802
+ allow(order).to receive_messages(:additional_tax_total => 10, :included_tax_total => 20)
803
+
804
+ expect(order.tax_total).to eq 30
805
+ end
806
+ end
807
+
808
+ # Regression test for #4923
809
+ context "locking" do
810
+ let(:order) { Spree::Order.create } # need a persisted in order to test locking
811
+
812
+ it 'can lock' do
813
+ expect { order.with_lock {} }.to_not raise_error
814
+ end
815
+ end
816
+
817
+ describe "#pre_tax_item_amount" do
818
+ it "sums all of the line items' pre tax amounts" do
819
+ subject.line_items = [
820
+ Spree::LineItem.new(price: 10, quantity: 2, pre_tax_amount: 5.0),
821
+ Spree::LineItem.new(price: 30, quantity: 1, pre_tax_amount: 14.0),
822
+ ]
823
+
824
+ expect(subject.pre_tax_item_amount).to eq 19.0
825
+ end
826
+ end
827
+
828
+ describe '#quantity' do
829
+ # Uses a persisted record, as the quantity is retrieved via a DB count
830
+ let(:order) { create :order_with_line_items, line_items_count: 3 }
831
+
832
+ it 'sums the quantity of all line items' do
833
+ expect(order.quantity).to eq 3
834
+ end
835
+ end
836
+
837
+ describe '#has_non_reimbursement_related_refunds?' do
838
+ subject do
839
+ order.has_non_reimbursement_related_refunds?
840
+ end
841
+
842
+ context 'no refunds exist' do
843
+ it { is_expected.to eq false }
844
+ end
845
+
846
+ context 'a non-reimbursement related refund exists' do
847
+ let(:order) { refund.payment.order }
848
+ let(:refund) { create(:refund, reimbursement_id: nil, amount: 5) }
849
+
850
+ it { is_expected.to eq true }
851
+ end
852
+
853
+ context 'an old-style refund exists' do
854
+ let(:order) { create(:order_ready_to_ship) }
855
+ let(:payment) { order.payments.first.tap { |p| allow(p).to receive_messages(profiles_supported: false) } }
856
+ let!(:refund_payment) {
857
+ build(:payment, amount: -1, order: order, state: 'completed', source: payment).tap do |p|
858
+ allow(p).to receive_messages(profiles_supported?: false)
859
+ p.save!
860
+ end
861
+ }
862
+
863
+ it { is_expected.to eq true }
864
+ end
865
+
866
+ context 'a reimbursement related refund exists' do
867
+ let(:order) { refund.payment.order }
868
+ let(:refund) { create(:refund, reimbursement_id: 123, amount: 5)}
869
+
870
+ it { is_expected.to eq false }
871
+ end
872
+ end
873
+
874
+ describe "#create_proposed_shipments" do
875
+ it "assigns the coordinator returned shipments to its shipments" do
876
+ shipment = build(:shipment)
877
+ allow_any_instance_of(Spree::Stock::Coordinator).to receive(:shipments).and_return([shipment])
878
+ subject.create_proposed_shipments
879
+ expect(subject.shipments).to eq [shipment]
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 "#fully_discounted?" do
914
+ let(:line_item) { Spree::LineItem.new(price: 10, quantity: 1) }
915
+ let(:shipment) { Spree::Shipment.new(cost: 10) }
916
+ let(:payment) { Spree::Payment.new(amount: 10) }
917
+
918
+ before do
919
+ allow(order).to receive(:line_items) { [line_item] }
920
+ allow(order).to receive(:shipments) { [shipment] }
921
+ allow(order).to receive(:payments) { [payment] }
922
+ end
923
+
924
+ context "the order had no inventory-related cost" do
925
+ before do
926
+ # discount the cost of the line items
927
+ allow(order).to receive(:adjustment_total) { -5 }
928
+ allow(line_item).to receive(:adjustment_total) { -5 }
929
+
930
+ # but leave some shipment payment amount
931
+ allow(shipment).to receive(:adjustment_total) { 0 }
932
+ end
933
+
934
+ it { expect(order.fully_discounted?).to eq true }
935
+
936
+ end
937
+
938
+ context "the order had inventory-related cost" do
939
+ before do
940
+ # partially discount the cost of the line item
941
+ allow(order).to receive(:adjustment_total) { 0 }
942
+ allow(line_item).to receive(:adjustment_total) { -5 }
943
+
944
+ # and partially discount the cost of the shipment so the total
945
+ # discount matches the item total for test completeness
946
+ allow(shipment).to receive(:adjustment_total) { -5 }
947
+ end
948
+
949
+ it { expect(order.fully_discounted?).to eq false }
950
+
951
+ end
952
+ end
953
+
954
+ end