spree-point-of-sale 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +16 -0
  2. data/Gemfile +20 -0
  3. data/LICENSE +23 -0
  4. data/README.md +71 -0
  5. data/Rakefile +29 -0
  6. data/Versionfile +11 -0
  7. data/app/assets/images/admin/pos/customer.png +0 -0
  8. data/app/assets/images/admin/pos/del_16.png +0 -0
  9. data/app/assets/images/admin/pos/plus_16.png +0 -0
  10. data/app/assets/images/admin/pos/select.jpg +0 -0
  11. data/app/assets/javascripts/admin/spree_pos.js +20 -0
  12. data/app/assets/stylesheets/admin/html-label.css +20 -0
  13. data/app/assets/stylesheets/admin/spree_pos.css +25 -0
  14. data/app/controllers/spree/admin/barcode_controller.rb +49 -0
  15. data/app/controllers/spree/admin/checkout_controller_decorator.rb +7 -0
  16. data/app/controllers/spree/admin/pos_controller.rb +205 -0
  17. data/app/controllers/spree/admin/stock_locations_controller_decorator.rb +13 -0
  18. data/app/helpers/admin/barcode_helper.rb +31 -0
  19. data/app/models/spree/order_decorator.rb +38 -0
  20. data/app/models/spree/payment_decorator.rb +10 -0
  21. data/app/models/spree/payment_method/point_of_sale.rb +30 -0
  22. data/app/models/spree/shipment_decorator.rb +29 -0
  23. data/app/models/spree/stock/coordinator_decorator.rb +10 -0
  24. data/app/models/spree/stock_location_decorator.rb +18 -0
  25. data/app/models/spree/user_decorator.rb +10 -0
  26. data/app/models/spree/variant_decorator.rb +3 -0
  27. data/app/overrides/add_barcode_link_for_products_and_variants.rb +21 -0
  28. data/app/overrides/add_is_pos_filter_to_admin_orders.rb +11 -0
  29. data/app/overrides/add_pos_button.rb +5 -0
  30. data/app/overrides/add_store_to_spree_stock_locations.rb +11 -0
  31. data/app/overrides/admin_adds_pos_config.rb +7 -0
  32. data/app/overrides/codes.rb +10 -0
  33. data/app/overrides/pos_tab.rb +6 -0
  34. data/app/views/spree/admin/barcode/basic.html.erb +28 -0
  35. data/app/views/spree/admin/invoice/_line_items_invoice.html.erb +34 -0
  36. data/app/views/spree/admin/invoice/_receipt_header.html.erb +13 -0
  37. data/app/views/spree/admin/invoice/_totals_receipt.html.erb +25 -0
  38. data/app/views/spree/admin/invoice/receipt.html.erb +26 -0
  39. data/app/views/spree/admin/orders/_admin_pos_config.html.erb +5 -0
  40. data/app/views/spree/admin/orders/_pos_button.html.erb +1 -0
  41. data/app/views/spree/admin/pos/find.html.erb +81 -0
  42. data/app/views/spree/admin/pos/show.html.erb +137 -0
  43. data/app/views/spree/admin/pos/update_stock_location.js.erb +5 -0
  44. data/app/views/spree/admin/products/_barcode_product_link.html.erb +3 -0
  45. data/app/views/spree/admin/products/_barcode_variant_link.html.erb +3 -0
  46. data/config/application.rb +23 -0
  47. data/config/boot.rb +5 -0
  48. data/config/initializers/constants.rb +4 -0
  49. data/config/locales/codes-fi.yml +3 -0
  50. data/config/locales/en.yml +16 -0
  51. data/config/locales/fi.yml +8 -0
  52. data/config/routes.rb +21 -0
  53. data/db/migrate/20130723140316_add_delivered_at_and_canceled_at_to_spree_shipments.rb +6 -0
  54. data/db/migrate/20130730102503_add_store_and_address_id_in_spree_stock_locations.rb +8 -0
  55. data/db/migrate/20131014053417_add_is_pos_to_spree_orders.rb +6 -0
  56. data/db/migrate/20131025110309_add_card_name_to_spree_payments.rb +5 -0
  57. data/lib/generators/spree_pos/install/install_generator.rb +27 -0
  58. data/lib/spree_pos.rb +2 -0
  59. data/lib/spree_pos/configuration.rb +7 -0
  60. data/lib/spree_pos/engine.rb +29 -0
  61. data/spec/constants_spec.rb +8 -0
  62. data/spec/controllers/spree/admin/barcode_controller_spec.rb +86 -0
  63. data/spec/controllers/spree/admin/pos_controller_spec.rb +849 -0
  64. data/spec/models/spree/order_decorator_spec.rb +178 -0
  65. data/spec/models/spree/payment_decorator_spec.rb +115 -0
  66. data/spec/models/spree/payment_method/point_of_sale_spec.rb +25 -0
  67. data/spec/models/spree/shipment_decorator_spec.rb +172 -0
  68. data/spec/models/spree/stock/coordinator_spec.rb +31 -0
  69. data/spec/models/spree/stock_location_decorator_spec.rb +43 -0
  70. data/spec/models/spree/user_decorator_spec.rb +24 -0
  71. data/spec/models/spree/varaint_decorator_spec.rb +31 -0
  72. data/spec/spec_helper.rb +67 -0
  73. data/spree-point-of-sale.gemspec +32 -0
  74. metadata +183 -0
@@ -0,0 +1,849 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Admin::PosController do
4
+ let(:user) { mock_model(Spree::User) }
5
+ let(:order) { mock_model(Spree::Order, :number => 'R123456') }
6
+ let(:line_item) { mock_model(Spree::LineItem) }
7
+ let(:product) { mock_model(Spree::Product, :name => 'test-product') }
8
+ let(:variant) { mock_model(Spree::Variant, :name => 'test-variant', :price => 20) }
9
+ let(:payment) { mock_model(Spree::Payment) }
10
+ let(:role) { mock_model(Spree::Role) }
11
+ let(:roles) { [role] }
12
+ let(:address) { mock_model(Spree::Address) }
13
+ let(:line_item_error_object) { ActiveModel::Errors.new(Spree::LineItem) }
14
+ let(:shipment_error_object) { ActiveModel::Errors.new(Spree::Shipment) }
15
+
16
+ before do
17
+ controller.stub(:spree_current_user).and_return(user)
18
+ controller.stub(:authorize_admin).and_return(true)
19
+ controller.stub(:authorize!).and_return(true)
20
+ user.stub(:generate_spree_api_key!).and_return(true)
21
+ user.stub(:roles).and_return(roles)
22
+ user.stub(:unpaid_pos_orders).and_return([order])
23
+ roles.stub(:includes).and_return(roles)
24
+ role.stub(:ability).and_return(true)
25
+ variant.stub(:product).and_return(product)
26
+ product.stub(:save).and_return(true)
27
+ order.stub(:is_pos?).and_return(true)
28
+ order.stub(:paid?).and_return(false)
29
+ order.stub(:reload).and_return(order)
30
+ end
31
+
32
+ context 'before filters' do
33
+ before do
34
+ @orders = [order]
35
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
36
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
37
+ end
38
+
39
+ describe 'ensure order is pos and unpaid' do
40
+ def send_request(params = {})
41
+ get :show, params.merge({:use_route => 'spree'})
42
+ end
43
+
44
+ context 'order does not exist' do
45
+ before do
46
+ @orders = []
47
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
48
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
49
+ end
50
+
51
+ it { expect { send_request(:number => order.number) }.to raise_error "No order found for -#{order.number}-" }
52
+ end
53
+
54
+ context 'paid' do
55
+ before { order.stub(:paid?).and_return(true) }
56
+
57
+ describe 'loads and checks order' do
58
+ # it { Spree::Order.should_receive(:where).with(:number => order.number).and_return([order]) }
59
+ it { order.should_receive(:paid?).and_return(true) }
60
+ it { controller.should_not_receive(:show) }
61
+
62
+ after { send_request({ :number => order.number }) }
63
+ end
64
+
65
+ describe 'response' do
66
+ before { send_request({ :number => order.number }) }
67
+
68
+ it { flash[:error].should eq('This order is already completed. Please use a new one.') }
69
+ it { response.should render_template('show') }
70
+ end
71
+ end
72
+
73
+ context 'not paid but not pos' do
74
+ before { order.stub(:is_pos?).and_return(false) }
75
+
76
+ describe 'loads and checks order' do
77
+ it { order.should_receive(:is_pos?).and_return(false) }
78
+ it { controller.should_not_receive(:show) }
79
+
80
+ after { send_request({ :number => order.number }) }
81
+ end
82
+
83
+ describe 'response' do
84
+ before { send_request({ :number => order.number }) }
85
+
86
+ it { flash[:error].should eq('This is not a pos order') }
87
+ it { response.should render_template('show') }
88
+ end
89
+ end
90
+
91
+ context 'not paid and pos order' do
92
+ before { order.stub(:paid?).and_return(false) }
93
+
94
+ describe 'loads and checks order' do
95
+ it { order.should_receive(:paid?).and_return(false) }
96
+
97
+ after { send_request({ :number => order.number, :line_item_id => 1 }) }
98
+ end
99
+
100
+ describe 'response' do
101
+ before { send_request({ :number => order.number }) }
102
+
103
+ it { flash[:error].should be_nil }
104
+ it { response.should render_template('show') }
105
+ end
106
+ end
107
+ end
108
+
109
+ describe 'ensure_pos_shipping_method' do
110
+ before do
111
+ @shipping_method = mock_model(Spree::ShippingMethod, :name => 'pos-shipping')
112
+ SpreePos::Config[:pos_shipping] = @shipping_method.name
113
+ end
114
+
115
+ def send_request(params = {})
116
+ get :new, params.merge!(:use_route => 'spree')
117
+ end
118
+
119
+ context 'pos_shipping_method exists' do
120
+ before do
121
+ Spree::ShippingMethod.stub(:where).with(:name => @shipping_method.name).and_return([@shipping_method])
122
+ end
123
+
124
+ it 'checks for the configured shipping method' do
125
+ Spree::ShippingMethod.should_receive(:where).with(:name => @shipping_method.name).and_return([@shipping_method])
126
+ send_request
127
+ end
128
+
129
+ context 'response' do
130
+ before { send_request }
131
+
132
+ it { flash[:error].should eq("You have an unpaid/empty order. Please either complete it or update items in the same order.") }
133
+ it { response.should_not redirect_to('/') }
134
+ end
135
+ end
136
+
137
+ context 'pos_shipping_method does not exist' do
138
+ before do
139
+ Spree::ShippingMethod.stub(:where).with(:name => @shipping_method.name).and_return([])
140
+ end
141
+
142
+ it 'checks for the configured shipping method' do
143
+ Spree::ShippingMethod.should_receive(:where).with(:name => @shipping_method.name).and_return([])
144
+ send_request
145
+ end
146
+
147
+ context 'response' do
148
+ before { send_request }
149
+
150
+ it { flash[:error].should eq("No shipping method available for POS orders. Please assign one.") }
151
+ it { response.should redirect_to('/') }
152
+ end
153
+ end
154
+ end
155
+
156
+ describe 'load_variant' do
157
+ before do
158
+ controller.stub(:add_variant).with(variant).and_return(line_item)
159
+ end
160
+
161
+ def send_request(params = {})
162
+ post :add, params.merge!(:use_route => 'spree')
163
+ end
164
+
165
+ context 'variant present' do
166
+ before do
167
+ Spree::Variant.stub(:where).with(:id => variant.id.to_s).and_return([variant])
168
+ end
169
+
170
+ it 'checks for the variant' do
171
+ Spree::Variant.should_receive(:where).with(:id => variant.id.to_s).and_return([variant])
172
+ send_request(:item => variant.id, :number => order.number)
173
+ end
174
+
175
+ it 'proceeds further to add' do
176
+ controller.should_receive(:add_variant).with(variant).and_return(line_item)
177
+ send_request(:item => variant.id, :number => order.number)
178
+ end
179
+
180
+ it 'sets no flash error' do
181
+ send_request(:item => variant.id, :number => order.number)
182
+ flash[:error].should be_nil
183
+ end
184
+ end
185
+
186
+ context 'no variant with the id passed' do
187
+ before { Spree::Variant.stub(:where).with(:id => variant.id.to_s).and_return([]) }
188
+
189
+ it 'checks for the variant' do
190
+ Spree::Variant.should_receive(:where).with(:id => variant.id.to_s).and_return([])
191
+ send_request(:item => variant.id, :number => order.number)
192
+ end
193
+
194
+ it 'renders show' do
195
+ send_request(:item => variant.id, :number => order.number)
196
+ response.should render_template :show
197
+ end
198
+
199
+ it 'sets flash error' do
200
+ send_request(:item => variant.id, :number => order.number)
201
+ flash[:error].should eq('No variant')
202
+ end
203
+ end
204
+ end
205
+
206
+ describe 'ensure_payment_method' do
207
+ before do
208
+ @payment_method = mock_model(Spree::PaymentMethod)
209
+ controller.stub(:update_line_item_quantity).and_return(true)
210
+ end
211
+
212
+ def send_request(params = {})
213
+ post :update_payment, params.merge!({ :use_route => 'spree'})
214
+ end
215
+
216
+ context 'payment method exists' do
217
+ before do
218
+ Spree::PaymentMethod.stub(:where).with(:id => @payment_method.id.to_s).and_return([@payment_method])
219
+ order.stub(:save_payment_for_pos).with(@payment_method.id.to_s, 'Credit Card').and_return(payment)
220
+ order.stub(:complete_via_pos).and_return(true)
221
+ end
222
+
223
+ describe 'response' do
224
+ before { send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card') }
225
+
226
+ it { flash[:error].should be_nil }
227
+ end
228
+
229
+ it 'completes the order' do
230
+ order.should_receive(:save_payment_for_pos).with(@payment_method.id.to_s, 'Credit Card').and_return(payment)
231
+ order.should_receive(:complete_via_pos).and_return(true)
232
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
233
+ end
234
+ end
235
+
236
+ context 'payment method does not exist' do
237
+ before { Spree::PaymentMethod.stub(:where).with(:id => @payment_method.id.to_s).and_return([]) }
238
+
239
+ describe 'response' do
240
+ before { send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card') }
241
+
242
+ it { flash[:error].should eq('Please select a payment method') }
243
+ end
244
+
245
+ it 'does not complete the order' do
246
+ order.should_not_receive(:save_payment_for_pos)
247
+ order.should_not_receive(:complete_via_pos)
248
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
249
+ end
250
+
251
+ it 'redirects' do
252
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
253
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
254
+ end
255
+ end
256
+ end
257
+
258
+ describe 'ensure existing user' do
259
+ def send_request(params = {})
260
+ post :associate_user, params.merge!({:use_route => 'spree'})
261
+ end
262
+
263
+ context 'to be associated old user does not exist' do
264
+ before do
265
+ send_request(:number => order.number, :email => 'non-exist@website.com')
266
+ end
267
+
268
+ it { response.should redirect_to(admin_pos_show_order_path(:number => order.number)) }
269
+ it { flash[:error].should eq("No user with email non-exist@website.com") }
270
+ end
271
+
272
+ context 'to be added a new user already exists' do
273
+ before do
274
+ @existing_user = Spree::User.create!(:email => 'existing@website.com', :password => 'iexist')
275
+ send_request(:number => order.number, :new_email => @existing_user.email)
276
+ end
277
+
278
+ it { response.should redirect_to(admin_pos_show_order_path(:number => order.number)) }
279
+ it { flash[:error].should eq("User Already exists for the email #{@existing_user.email}") }
280
+ end
281
+ end
282
+ end
283
+
284
+ context 'actions' do
285
+ before do
286
+ controller.stub(:ensure_pos_shipping_method).and_return(true)
287
+ controller.stub(:ensure_payment_method).and_return(true)
288
+ Spree::StockLocation.stub_chain(:active,:stores,:first,:address).and_return(address)
289
+ controller.instance_variable_set(:@order,order)
290
+ controller.stub(:check_valid_order).and_return(true)
291
+ end
292
+
293
+ describe 'new' do
294
+ before do
295
+ @current_time = Time.current
296
+ Time.stub(:current).and_return(@current_time)
297
+ @new_order = Spree::Order.create :is_pos => true
298
+ Spree::Order.stub(:new).and_return(@new_order)
299
+ @new_order.stub(:assign_shipment_for_pos).and_return(true)
300
+ @new_order.stub(:associate_user!).and_return(true)
301
+ @new_order.stub(:save!).and_return(true)
302
+ end
303
+
304
+ def send_request(params = {})
305
+ get :new, params.merge!(:use_route => 'spree')
306
+ end
307
+
308
+ context 'before filters' do
309
+ it { controller.should_receive(:ensure_pos_shipping_method).and_return(true) }
310
+ it { controller.should_not_receive(:ensure_payment_method) }
311
+ it { controller.should_not_receive(:check_valid_order) }
312
+ after { send_request }
313
+ end
314
+
315
+ it 'checks for pending orders' do
316
+ user.should_receive(:unpaid_pos_orders).and_return([order])
317
+ send_request
318
+ end
319
+
320
+ context 'pending pos order present' do
321
+ it 'adds error' do
322
+ controller.should_receive(:add_error).with("You have an unpaid/empty order. Please either complete it or update items in the same order.").and_return(true)
323
+ send_request
324
+ end
325
+
326
+ it 'does not initalize with a new order' do
327
+ controller.should_not_receive(:init_pos)
328
+ send_request
329
+ end
330
+
331
+ it 'redirects to action show' do
332
+ send_request
333
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
334
+ end
335
+ end
336
+
337
+ context 'no pending order' do
338
+ before { user.stub(:unpaid_pos_orders).and_return([]) }
339
+
340
+ context 'init_pos' do
341
+ it { Spree::Order.should_receive(:new).with(:state => "complete", :is_pos => true, :completed_at => @current_time, :payment_state => 'balance_due').and_return(@new_order) }
342
+ it { @new_order.should_receive(:assign_shipment_for_pos).and_return(true) }
343
+ it { @new_order.should_receive(:associate_user!).and_return(true) }
344
+ it { @new_order.should_receive(:save!).twice.and_return(true) }
345
+ after { send_request }
346
+ end
347
+
348
+ it 'redirects to action show' do
349
+ send_request
350
+ response.should redirect_to(admin_pos_show_order_path(:number => @new_order.number))
351
+ end
352
+ end
353
+ end
354
+
355
+ describe 'update_line_item_quantity' do
356
+ before do
357
+ @orders = [order]
358
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
359
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
360
+ @line_items = [line_item]
361
+ order.stub(:line_items).and_return(@line_items)
362
+ @line_items.stub(:where).and_return(@line_items)
363
+ line_item.stub(:save).and_return(true)
364
+ line_item.stub(:variant).and_return(variant)
365
+ line_item.stub(:quantity=).with('2').and_return(true)
366
+ end
367
+
368
+ def send_request(params = {})
369
+ post :update_line_item_quantity, params.merge!({:use_route => 'spree'})
370
+ end
371
+
372
+ context 'update_line_item_quantity' do
373
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
374
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
375
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
376
+ it { controller.should_not_receive(:ensure_payment_method) }
377
+ it { order.should_receive(:line_items).and_return(@line_items) }
378
+ it { line_item.should_receive(:quantity=).with('2').and_return(true) }
379
+ it { line_item.should_receive(:save).and_return(true) }
380
+ after { send_request(:number => order.number, :line_item_id => line_item.id, :quantity => 2) }
381
+ end
382
+
383
+ context 'updated successfully' do
384
+ it 'sets flash message' do
385
+ send_request(:number => order.number, :line_item_id => line_item.id, :quantity => 2)
386
+ flash[:notice].should eq('Quantity Updated')
387
+ end
388
+ end
389
+
390
+ context 'not updated successfully' do
391
+ before do
392
+ line_item_error_object.messages.merge!({:base => ["Adding more than available"]})
393
+ line_item.stub(:errors).and_return(line_item_error_object)
394
+ end
395
+
396
+ it 'sets flash message' do
397
+ send_request(:number => order.number, :line_item_id => line_item.id, :quantity => 2)
398
+ flash[:error].should eq('Adding more than available')
399
+ end
400
+ end
401
+ end
402
+
403
+ describe 'apply discount' do
404
+ def send_request(params = {})
405
+ post :apply_discount, params.merge!({:use_route => 'spree'})
406
+ end
407
+
408
+ before do
409
+ @orders = [order]
410
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
411
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
412
+ @line_items = [line_item]
413
+ order.stub(:line_items).and_return(@line_items)
414
+ @line_items.stub(:where).and_return(@line_items)
415
+ line_item.stub(:save).and_return(true)
416
+ line_item.stub(:variant).and_return(variant)
417
+ line_item.stub(:price=).with(18.0).and_return(true)
418
+ end
419
+
420
+ it { order.should_receive(:line_items).and_return(@line_items) }
421
+ it { line_item.should_receive(:variant).and_return(variant) }
422
+ it { line_item.should_receive(:save).and_return(true) }
423
+ it { line_item.should_receive(:price=).with(18.0).and_return(true) }
424
+ after { send_request(:number => order.number, :discount => 10, :item => line_item.id) }
425
+ end
426
+
427
+ describe 'find' do
428
+ def send_request(params = {})
429
+ get :find, params.merge!(:use_route => 'spree')
430
+ end
431
+
432
+ before do
433
+ @orders = [order]
434
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
435
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
436
+ @stock_location = mock_model(Spree::StockLocation)
437
+ @shipment = mock_model(Spree::Shipment)
438
+ order.stub(:shipment).and_return(@shipment)
439
+ @shipment.stub(:stock_location).and_return(@stock_location)
440
+ @variants = [variant]
441
+ @variants.stub(:result).with(:distinct => true).and_return(@variants)
442
+ @variants.stub(:page).with('1').and_return(@variants)
443
+ @variants.stub(:per).and_return(@variants)
444
+ Spree::Variant.stub(:includes).with([:product]).and_return(Spree::Variant)
445
+ Spree::Variant.stub(:available_at_stock_location).with(@stock_location.id).and_return(Spree::Variant)
446
+ Spree::Variant.stub(:ransack).with({"product_name_cont"=>"test-product", "meta_sort"=>"product_name asc", "deleted_at_null"=>"1", "product_deleted_at_null"=>"1", "published_at_not_null"=>"1"}).and_return(@variants)
447
+ end
448
+
449
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
450
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
451
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
452
+ it { controller.should_not_receive(:ensure_payment_method) }
453
+ it { order.should_receive(:shipment).and_return(@shipment) }
454
+ it { @shipment.should_receive(:stock_location).and_return(@stock_location) }
455
+ it { Spree::Variant.should_receive(:ransack).with({"product_name_cont"=>"test-product", "meta_sort"=>"product_name asc", "deleted_at_null"=>"1", "product_deleted_at_null"=>"1", "published_at_not_null"=>"1"}).and_return(@variants) }
456
+ it { @variants.should_receive(:result).with(:distinct => true).and_return(@variants) }
457
+ it { @variants.should_receive(:page).with('1').and_return(@variants) }
458
+ it { @variants.should_receive(:per).and_return(@variants) }
459
+
460
+ after { send_request(:number => order.number, :q => { :product_name_cont => 'test-product ' }, :page => 1) }
461
+ end
462
+
463
+ describe 'print' do
464
+ def send_request(params = {})
465
+ post :update_payment, params.merge!({ :use_route => 'spree'})
466
+ end
467
+
468
+ before do
469
+ @orders = [order]
470
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
471
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
472
+ @payment_method = mock_model(Spree::PaymentMethod)
473
+ Spree::PaymentMethod.stub(:where).with(:id => @payment_method.id.to_s).and_return([@payment_method])
474
+ order.stub(:save_payment_for_pos).with(@payment_method.id.to_s, 'Credit Card').and_return(payment)
475
+ order.stub(:complete_via_pos).and_return(true)
476
+ end
477
+
478
+ it 'completes order via pos' do
479
+ order.should_receive(:complete_via_pos).and_return(true)
480
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
481
+ end
482
+
483
+ it 'redirects to print url' do
484
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
485
+ response.should redirect_to("/admin/invoice/#{order.number}/receipt")
486
+ end
487
+ end
488
+
489
+ describe 'add' do
490
+ before do
491
+ @orders = [order]
492
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
493
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
494
+ Spree::Variant.stub(:where).with(:id => variant.id.to_s).and_return([variant])
495
+ @order_contents = double(Spree::OrderContents)
496
+ @shipment = mock_model(Spree::Shipment)
497
+ order.stub(:shipment).and_return(@shipment)
498
+ order.stub(:contents).and_return(@order_contents)
499
+ @order_contents.stub(:add).with(variant, 1, nil, @shipment).and_return(line_item)
500
+ end
501
+
502
+ def send_request(params = {})
503
+ post :add, params.merge!(:use_route => 'spree')
504
+ end
505
+
506
+ describe 'adds to order' do
507
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
508
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
509
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
510
+ it { controller.should_not_receive(:ensure_payment_method) }
511
+
512
+ it { order.should_receive(:contents).and_return(@order_contents) }
513
+ it { @order_contents.should_receive(:add).with(variant, 1, nil, @shipment).and_return(line_item) }
514
+ it { product.should_receive(:save).and_return(true) }
515
+
516
+ after { send_request(:number => order.number, :item => variant.id) }
517
+ end
518
+
519
+ it 'assigns line_item' do
520
+ send_request(:number => order.number, :item => variant.id)
521
+ assigns(:item).should eq(line_item)
522
+ end
523
+
524
+ context 'added successfully' do
525
+ it 'redirects to action show' do
526
+ send_request(:number => order.number, :item => variant.id)
527
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
528
+ end
529
+
530
+ it 'sets the flash message' do
531
+ send_request(:number => order.number, :item => variant.id)
532
+ flash[:notice].should eq('Product added')
533
+ end
534
+ end
535
+
536
+ context 'not added successfully' do
537
+ before do
538
+ line_item_error_object.messages.merge!({:base => ["Adding more than available"]})
539
+ line_item.stub(:errors).and_return(line_item_error_object)
540
+ end
541
+
542
+ it 'redirects to action show' do
543
+ send_request(:number => order.number, :item => variant.id)
544
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
545
+ end
546
+
547
+ it 'sets the flash message' do
548
+ send_request(:number => order.number, :item => variant.id)
549
+ flash[:error].should eq('Adding more than available')
550
+ end
551
+ end
552
+ end
553
+
554
+ describe 'remove' do
555
+ before do
556
+ @orders = [order]
557
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
558
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
559
+ Spree::Variant.stub(:where).with(:id => variant.id.to_s).and_return([variant])
560
+ @order_contents = double(Spree::OrderContents)
561
+ @shipment = mock_model(Spree::Shipment)
562
+ order.stub(:shipment).and_return(@shipment)
563
+ order.stub(:shipments).and_return([@shipment])
564
+ order.stub(:assign_shipment_for_pos).and_return(true)
565
+ order.stub(:contents).and_return(@order_contents)
566
+ @order_contents.stub(:remove).with(variant, 1, @shipment).and_return(line_item)
567
+ line_item.stub(:quantity).and_return(1)
568
+ end
569
+
570
+ def send_request(params = {})
571
+ post :remove, params.merge!(:use_route => 'spree')
572
+ end
573
+
574
+ describe 'removes from order' do
575
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
576
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
577
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
578
+ it { controller.should_not_receive(:ensure_payment_method) }
579
+
580
+ it { order.should_receive(:contents).and_return(@order_contents) }
581
+ it { @order_contents.should_receive(:remove).with(variant, 1, @shipment).and_return(line_item) }
582
+
583
+ after { send_request(:number => order.number, :item => variant.id) }
584
+ end
585
+
586
+ context 'item quantity is now 0' do
587
+ before { line_item.stub(:quantity).and_return(0) }
588
+ it 'sets flash message' do
589
+ send_request(:number => order.number, :item => variant.id)
590
+ flash[:notice].should eq(Spree.t('product_removed'))
591
+ end
592
+ end
593
+
594
+ context 'item quantity is now not 0' do
595
+ it 'sets flash message' do
596
+ send_request(:number => order.number, :item => variant.id)
597
+ flash[:notice].should eq('Quantity Updated')
598
+ end
599
+ end
600
+
601
+ context 'shipment is destroyed on empty order' do
602
+ it 'assigns shipment' do
603
+ order.should_not_receive(:assign_shipment_for_pos)
604
+ send_request(:number => order.number, :item => variant.id)
605
+ end
606
+ end
607
+
608
+ context 'shipment exists after remove' do
609
+ before { order.stub(:shipments).and_return([]) }
610
+
611
+ it 'assigns shipment' do
612
+ order.should_receive(:assign_shipment_for_pos).and_return(true)
613
+ send_request(:number => order.number, :item => variant.id)
614
+ end
615
+ end
616
+
617
+ it 'redirects to action show' do
618
+ send_request(:number => order.number, :item => variant.id)
619
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
620
+ end
621
+ end
622
+
623
+ describe 'clean_order' do
624
+ before do
625
+ @orders = [order]
626
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
627
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
628
+ order.stub(:clean!).and_return(true)
629
+ end
630
+
631
+ def send_request(params = {})
632
+ put :clean_order, params.merge!({:use_route => 'spree'})
633
+ end
634
+
635
+ context 'before filters' do
636
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
637
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
638
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
639
+ it { controller.should_not_receive(:ensure_payment_method) }
640
+ after { send_request({:number => order.number}) }
641
+ end
642
+
643
+ it 'calls clean! method on order' do
644
+ order.should_receive(:clean!).and_return(true)
645
+ send_request({:number => order.number})
646
+ end
647
+
648
+ it 'redirects to action show' do
649
+ send_request(:number => order.number)
650
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
651
+ end
652
+
653
+ it 'sets flash message' do
654
+ send_request({:number => order.number})
655
+ flash[:notice].should eq('Removed all items')
656
+ end
657
+ end
658
+
659
+ describe 'associate_user' do
660
+ before do
661
+ @orders = [order]
662
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
663
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
664
+ order.stub(:associate_user_for_pos).with('test-user@pos.com').and_return(user)
665
+ order.stub(:save!).and_return(true)
666
+ end
667
+
668
+ def send_request(params = {})
669
+ post :associate_user, params.merge!({:use_route => 'spree'})
670
+ end
671
+
672
+ context 'before filters' do
673
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
674
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
675
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
676
+ it { controller.should_not_receive(:ensure_payment_method) }
677
+ after { send_request(:number => order.number, :new_email =>'test-user@pos.com') }
678
+ end
679
+
680
+ it 'associates user with order' do
681
+ order.should_receive(:associate_user_for_pos).with('test-user@pos.com').and_return(user)
682
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
683
+ end
684
+
685
+ it 'saves the changes in order' do
686
+ order.should_receive(:save!).and_return(true)
687
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
688
+ end
689
+
690
+ context 'if user added successfully' do
691
+ it 'redirects to action show' do
692
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
693
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
694
+ end
695
+
696
+ it 'sets the flash message' do
697
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
698
+ flash[:notice].should eq('Successfully Associated User')
699
+ end
700
+ end
701
+
702
+ context 'if user not added' do
703
+ before do
704
+ @error_object = Object.new
705
+ @error_object.stub_chain(:full_messages, :to_sentence).and_return('error_message')
706
+ user.stub(:errors).and_return(@error_object)
707
+ end
708
+
709
+ it 'redirects to action show' do
710
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
711
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
712
+ end
713
+
714
+ it 'sets the flash message' do
715
+ send_request(:number => order.number, :new_email =>'test-user@pos.com')
716
+ flash[:error].should eq('Could not add the user:error_message')
717
+ end
718
+ end
719
+ end
720
+
721
+ describe 'update_payment' do
722
+ def send_request(params = {})
723
+ post :update_payment, params.merge!({ :use_route => 'spree'})
724
+ end
725
+
726
+ before do
727
+ @orders = [order]
728
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
729
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
730
+ @payment_method = mock_model(Spree::PaymentMethod)
731
+ Spree::PaymentMethod.stub(:where).with(:id => @payment_method.id.to_s).and_return([@payment_method])
732
+ order.stub(:save_payment_for_pos).with(@payment_method.id.to_s, 'Credit Card').and_return(payment)
733
+ order.stub(:complete_via_pos).and_return(true)
734
+ end
735
+
736
+ context 'before filters' do
737
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
738
+ it { controller.should_receive(:ensure_payment_method).and_return(true) }
739
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
740
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
741
+
742
+ after { send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card') }
743
+ end
744
+
745
+ it 'save payment for order' do
746
+ order.should_receive(:save_payment_for_pos).with(@payment_method.id.to_s, 'Credit Card').and_return(payment)
747
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
748
+ end
749
+
750
+ context 'payment successfully updated' do
751
+ it 'prints the order' do
752
+ controller.should_receive(:print).and_return{ controller.render :nothing => true }
753
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
754
+ end
755
+ end
756
+
757
+ context 'payment not saved' do
758
+ before do
759
+ @error_object = Object.new
760
+ @error_object.stub_chain(:full_messages, :to_sentence).and_return('error_message')
761
+ payment.stub(:errors).and_return(@error_object)
762
+ end
763
+
764
+ it 'redirects to action show' do
765
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
766
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
767
+ end
768
+
769
+ it 'sets the error message' do
770
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
771
+ flash[:error].should eq('error_message')
772
+ end
773
+
774
+ it 'should not complete order' do
775
+ order.should_not_receive(:complete_via_pos)
776
+ send_request(:number => order.number, :payment_method_id => @payment_method.id, :card_name => 'Credit Card')
777
+ end
778
+ end
779
+ end
780
+
781
+ describe 'update_stock_location' do
782
+ def send_request(params = {})
783
+ put :update_stock_location, params.merge!(:use_route => 'spree')
784
+ end
785
+
786
+ before do
787
+ @orders = [order]
788
+ order.stub(:clean!).and_return(true)
789
+ order.stub(:assign_shipment_for_pos).and_return(true)
790
+ Spree::Order.stub(:by_number).with(order.number).and_return(@orders)
791
+ @orders.stub(:includes).with([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }]).and_return(@orders)
792
+ @stock_location = mock_model(Spree::StockLocation)
793
+ @stock_location.stub(:address).and_return(address)
794
+ @stock_locations = [@stock_location]
795
+ @stock_locations.stub(:where).with(:id => @stock_location.id.to_s).and_return(@stock_locations)
796
+ Spree::StockLocation.stub_chain(:active, :stores).and_return(@stock_locations)
797
+
798
+ @shipment = mock_model(Spree::Shipment)
799
+ order.stub(:ship_address=).with(address).and_return(address)
800
+ order.stub(:bill_address=).with(address).and_return(address)
801
+ @shipment.stub(:stock_location=).with(@stock_location).and_return(@stock_location)
802
+ @shipment.stub(:stock_location).and_return(@stock_location)
803
+
804
+ order.stub(:shipment).and_return(@shipment)
805
+ order.stub(:save).and_return(true)
806
+ @shipment.stub(:save).and_return(true)
807
+ end
808
+
809
+ describe 'updates order addresses and update shipment' do
810
+ it { order.should_receive(:clean!).and_return(true) }
811
+ it { controller.should_receive(:load_order).twice.and_return(true) }
812
+ it { @shipment.should_receive(:stock_location=).with(@stock_location).and_return(@stock_location) }
813
+ it { order.should_receive(:shipment).and_return(@shipment) }
814
+ it { @shipment.should_receive(:save).and_return(true) }
815
+ it { controller.should_not_receive(:ensure_pos_shipping_method) }
816
+ it { controller.should_not_receive(:ensure_payment_method) }
817
+ it { controller.should_receive(:ensure_unpaid_order).and_return(true) }
818
+ it { controller.should_receive(:ensure_pos_order).and_return(true) }
819
+
820
+ after { send_request(:number => order.number, :stock_location_id => @stock_location.id) }
821
+ end
822
+
823
+ context 'shipment saved successfully' do
824
+ it 'sets notice' do
825
+ send_request(:number => order.number, :stock_location_id => @stock_location.id)
826
+ flash[:notice].should eq('Updated Successfully')
827
+ end
828
+ end
829
+
830
+ context 'shipment not saved successfully' do
831
+ before do
832
+ shipment_error_object.messages.merge!({:base => ["Error Message"]})
833
+ @shipment.stub(:errors).and_return(shipment_error_object)
834
+ @shipment.stub(:save).and_return(false)
835
+ end
836
+
837
+ it 'sets error' do
838
+ send_request(:number => order.number, :stock_location_id => @stock_location.id)
839
+ flash[:error].should eq('Error Message')
840
+ end
841
+ end
842
+
843
+ it 'redirects to action show' do
844
+ send_request(:number => order.number, :stock_location_id => @stock_location.id)
845
+ response.should redirect_to(admin_pos_show_order_path(:number => order.number))
846
+ end
847
+ end
848
+ end
849
+ end