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
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .project
7
+ tmp
8
+ nbproject
9
+ *.swp
10
+ log/
11
+ config/initializers/spree.rb
12
+ config/environment.rb
13
+ config/database.yml
14
+ app/controllers/application_controller.rb
15
+ coverage/
16
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source "https://rubygems.org"
2
+ gem 'rails', '3.2.16'
3
+ gem 'mysql2'
4
+
5
+
6
+ gem 'spree', :git => 'git://github.com/spree/spree.git', :tag => 'v2.0.3'
7
+ gem 'spree_html_invoice' , :git => 'git://github.com/dancinglightning/spree-html-invoice.git'
8
+
9
+ # Provides basic authentication functionality for testing parts of your engine
10
+ gem 'spree_auth_devise', github: 'spree/spree_auth_devise', :branch => '2-0-stable'
11
+
12
+ gemspec
13
+
14
+ group :test do
15
+ gem 'rspec-rails', '~> 2.10'
16
+ gem 'shoulda-matchers', '2.2.0'
17
+ gem 'simplecov', :require => false
18
+ gem 'database_cleaner'
19
+ gem 'rspec-html-matchers'
20
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Redistribution and use in source and binary forms, with or without modification,
2
+ are permitted provided that the following conditions are met:
3
+
4
+ * Redistributions of source code must retain the above copyright notice,
5
+ this list of conditions and the following disclaimer.
6
+ * Redistributions in binary form must reproduce the above copyright notice,
7
+ this list of conditions and the following disclaimer in the documentation
8
+ and/or other materials provided with the distribution.
9
+ * Neither the name of the Rails Dog LLC nor the names of its
10
+ contributors may be used to endorse or promote products derived from this
11
+ software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ SpreePos
2
+ ===============
3
+ SpreePos hooks into the Admin Tab and is meant to be used to sell at a shop.
4
+
5
+ Allows you to search and add items available at the selected stock location.
6
+ Apply discount on items, associate the order to customer email and save the details of payment to finally finish the order with an invoice ready to print.
7
+
8
+
9
+ Dependencies
10
+ ============
11
+ 1)spree_html_invoice(optional)
12
+
13
+ By default POS relies on html-invoice to print a receipt. You can configure this away by setting :pos_printing to the url where you want to redirect after print.
14
+
15
+ 2)barby
16
+
17
+ 3)prawn
18
+
19
+ 4)chunky_png
20
+
21
+
22
+ SET UP
23
+ =======
24
+ To your Gemfile add:
25
+
26
+ 1) gem "spree_pos", :git => "git://github.com/vinsol/spree-point-of-sale.git"
27
+
28
+ 2) If you DONT change the :pos_printing config as described above, you must also add
29
+
30
+ gem 'spree_html_invoice' , :git => 'git://github.com/dancinglightning/spree-html-invoice.git'
31
+
32
+ and run bundler.
33
+
34
+ Finally for migrations, css and javascript do
35
+
36
+ bundle exec rails g spree_pos:install
37
+
38
+
39
+ Configure
40
+ =========
41
+ You must configure:
42
+
43
+ 1)ShippingMethod : Create a shipping method for pos and set it from the admin end via general settings.
44
+ Usually something like "pickup" with cost 0.
45
+
46
+ 2)Payment Methods : They can be added under PointOfSale payment method from admin end itself.
47
+
48
+ 3)Store : Make sure atleast one of your stock locations is marked as store.
49
+
50
+
51
+ Order
52
+ =========
53
+ The order is linked to the admin creating the order to keep a track of pos orders initiated by a particular admin.
54
+
55
+ Admin won't be allowed to update a paid order or even to create a new order when there is an order pending to be paid.
56
+
57
+
58
+ Stock Location and Inventory
59
+ =========
60
+ By default the first active stock location is picked up considering a single stock location. In case of multiple stock locations you can easily switch them.
61
+
62
+ Stock Locations available to be selected can be easily configured by re-defining user_stock_locations for pos_controller.
63
+
64
+ The inventory is updated along with addition and removal of items from the order.
65
+
66
+
67
+ Barcode printing and SKU
68
+ ========
69
+ Barcode printing relies on sku to be provided for variants.
70
+
71
+ There are links provided to print barcodes for individual variants in the variants index for a product or barcodes for all variants can be printed from the product listings as well.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/packagetask'
4
+ require 'rubygems/package_task'
5
+ require 'rspec/core/rake_task'
6
+ require 'spree_core/testing_support/common_rake'
7
+
8
+ RSpec::Core::RakeTask.new
9
+
10
+ task :default => [:spec, :cucumber ]
11
+
12
+ spec = eval(File.read('spree_pos.gemspec'))
13
+
14
+ Gem::PackageTask.new(spec) do |p|
15
+ p.gem_spec = spec
16
+ end
17
+
18
+ desc "Release to gemcutter"
19
+ task :release => :package do
20
+ require 'rake/gemcutter'
21
+ Rake::Gemcutter::Tasks.new(spec).define
22
+ Rake::Task['gem:push'].invoke
23
+ end
24
+
25
+ desc "Generates a dummy app for testing"
26
+ task :test_app do
27
+ ENV['LIB_NAME'] = 'spree_pos'
28
+ Rake::Task['common:test_app'].invoke
29
+ end
data/Versionfile ADDED
@@ -0,0 +1,11 @@
1
+ # This file is used to designate compatibilty with different versions of Spree
2
+ # Please see http://spreecommerce.com/documentation/extensions.html#versionfile for details
3
+
4
+ "0.70.x" => { :ref => "793ca3ad2822877babf60c5e3d3bd7b3f39be3db"}
5
+ # note: the 1.0 version was in never in production use as I had server crashes with 1.0 and upgraded immediately to 1.1
6
+ "1.0.x" => { :ref => "7075b1b483faa183679761f060072515e45dcaf7"}
7
+
8
+ "1.1.x" => { :branch => "master" }
9
+
10
+
11
+
@@ -0,0 +1,20 @@
1
+ $( document ).ready(function() {
2
+ $('#sku').focus();
3
+ $( "#pos-tabs" ).tabs();
4
+
5
+ $( "#associate_user_toggle" ).click(function() {
6
+ $( "#associate_user" ).slideToggle( "slow", function() {
7
+ });
8
+ });
9
+
10
+ $('#update_payment input[type=radio]').click(function() {
11
+ $('#card_name_options').val('');
12
+ $('#card_name_options').hide();
13
+ });
14
+
15
+ $('#update_payment input[type=radio][data-name ~= card],#update_payment input[type=radio][data-name ~= Card]').click(function() {
16
+ $('#card_name_options').show();
17
+ });
18
+ $("#update_payment input[name='payment_method_id']:first").click();
19
+ $( "#associate_user" ).toggle();
20
+ });
@@ -0,0 +1,20 @@
1
+ @page {
2
+ margin-left:1mm;
3
+ margin-right:1mm;
4
+ margin-top:1mm;
5
+ margin-bottom:1mm;
6
+ }
7
+
8
+ body {
9
+ font-family:"Helvetica";
10
+ color:#000000;
11
+ width:200px;
12
+ }
13
+
14
+ .label-name {
15
+ font-size:13px;
16
+ }
17
+
18
+ .label-price {
19
+ font-size:13px;
20
+ }
@@ -0,0 +1,25 @@
1
+ #pos-tabs { border:none; padding:20px 0px; float:left; width:100%; }
2
+ #pos-tabs .ui-tabs-nav { display:inline-block; width:100%; border:none; background:none; border-radius:3px; background:#5498DA;}
3
+ #pos-tabs .ui-tabs-nav .ui-state-default { float:left; width:50%; text-align:center; border:none; background:none;}
4
+ #pos-tabs .ui-tabs-nav .ui-state-default .ui-tabs-anchor { display:block; padding:10px; font-weight:normal; text-transform:uppercase; font-size:11px; color:#fff !important; position:relative;}
5
+ #pos-tabs .ui-tabs-nav .ui-state-active .ui-tabs-anchor { background:#9FC820; border-radius:3px;}
6
+ #pos-tabs .ui-tabs-nav .ui-state-active .ui-tabs-anchor:after {
7
+ content: '';
8
+ position: absolute;
9
+ border-left: 10px solid transparent;
10
+ border-right: 10px solid transparent;
11
+ border-top: 5px solid #9fc820;
12
+ bottom: 0px;
13
+ margin-bottom: -5px;
14
+ left: 50%;
15
+ margin-left: -10px;
16
+ z-index: 1;
17
+ }
18
+ #pos-tabs .commonfieldset .row { margin:0;}
19
+ #pos-tabs .commonfieldset p { padding-bottom:10px;}
20
+ #pos-tabs .ui-widget-content { border:none; }
21
+ table#pos-order-table th { border-top: 1px solid #cee1f4;}
22
+ table#pos-order-table { padding-top: 10px;}
23
+ table#pos-order-table td.discount input.submit{ margin: 2px 0 0 10px;}
24
+ fieldset.no-bottom-margin { margin-bottom: 0px;}
25
+ a#create_pos_order { float:right; padding:4px 9px;}
@@ -0,0 +1,49 @@
1
+ require 'barby'
2
+ require 'prawn'
3
+ require 'prawn/measurement_extensions'
4
+ require 'barby/barcode/code_128'
5
+ require 'barby/barcode/ean_13'
6
+ require 'barby/outputter/png_outputter'
7
+
8
+ class Spree::Admin::BarcodeController < Spree::Admin::BaseController
9
+ include Admin::BarcodeHelper
10
+
11
+ before_filter :load, :only => [:print]
12
+ before_filter :load_product_and_variants, :only => [:print_variants_barcodes]
13
+ layout :false
14
+
15
+ def print_variants_barcodes
16
+ if @variants.present?
17
+ pdf = @variants.inject(empty_pdf({:height => 120})) { |pdf, variant| append_barcode_to_pdf_for_variant(variant, pdf) }
18
+ send_data pdf.render , :type => "application/pdf" , :filename => "#{@product.name}.pdf"
19
+ else
20
+ #just to have @variant so that print can be called directly without a request skipping load method
21
+ @variant = @product.master
22
+ print
23
+ end
24
+ end
25
+
26
+ # moved to pdf as html has uncontrollable margins
27
+ def print
28
+ pdf = append_barcode_to_pdf_for_variant(@variant)
29
+ send_data pdf.render , :type => "application/pdf" , :filename => "#{@variant.name}.pdf"
30
+ end
31
+
32
+ private
33
+
34
+ # leave this in here maybe for later, not used anymore
35
+ # def code
36
+ # barcode = get_barcode
37
+ # return unless barcode
38
+ # send_data barcode.to_png(:xdim => 5) , :type => 'image/png', :disposition => 'inline'
39
+ # end
40
+
41
+ def load
42
+ @variant = Spree::Variant.where(:id => params[:id]).first
43
+ end
44
+
45
+ def load_product_and_variants
46
+ @product = Spree::Product.where(:id => params[:id]).first
47
+ @variants = @product.variants
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ Spree::Admin::GeneralSettingsController.class_eval do
2
+ before_filter :update_pos_config, :only => :update
3
+
4
+ def update_pos_config
5
+ SpreePos::Config[:pos_shipping] = params[:pos_shipping]
6
+ end
7
+ end
@@ -0,0 +1,205 @@
1
+ class Spree::Admin::PosController < Spree::Admin::BaseController
2
+ before_filter :load_order, :ensure_pos_order, :ensure_unpaid_order, :except => [:new]
3
+ helper_method :user_stock_locations
4
+ before_filter :load_variant, :only => [:add, :remove]
5
+ before_filter :ensure_pos_shipping_method, :only => [:new]
6
+ before_filter :ensure_payment_method, :only => [:update_payment]
7
+ before_filter :ensure_existing_user, :only => [:associate_user]
8
+ before_filter :check_unpaid_pos_order, :only => :new
9
+ before_filter :check_discount_request, :only => :apply_discount
10
+ before_filter :load_line_item, :only => [:update_line_item_quantity, :apply_discount]
11
+ before_filter :clean_and_reload_order, :only => [:update_stock_location]
12
+
13
+ def new
14
+ init_pos
15
+ redirect_to admin_pos_show_order_path(:number => @order.number)
16
+ end
17
+
18
+ def find
19
+ init_search
20
+
21
+ stock_location = @order.shipment.stock_location
22
+ @search = Spree::Variant.includes([:product]).available_at_stock_location(stock_location.id).ransack(params[:q])
23
+ @variants = @search.result(:distinct => true).page(params[:page]).per(PRODUCTS_PER_SEARCH_PAGE)
24
+ end
25
+
26
+ def add
27
+ @item = add_variant(@variant) if @variant.present?
28
+ flash[:notice] = Spree.t('product_added') if @item.errors.blank?
29
+ flash[:error] = @item.errors.full_messages.to_sentence if @item.errors.present?
30
+ redirect_to admin_pos_show_order_path(:number => @order.number)
31
+ end
32
+
33
+ def remove
34
+ line_item = @order.contents.remove(@variant, 1, @order.shipment)
35
+ @order.assign_shipment_for_pos if @order.reload.shipments.blank?
36
+ flash.notice = line_item.quantity.zero? ? Spree.t('product_removed') : 'Quantity Updated'
37
+ redirect_to admin_pos_show_order_path(:number => @order.number)
38
+ end
39
+
40
+ def update_line_item_quantity
41
+ @item.quantity = params[:quantity]
42
+ @item.save
43
+
44
+ flash[:notice] = 'Quantity Updated' if @item.errors.blank?
45
+ flash[:error] = @item.errors.full_messages.to_sentence if @item.errors.present?
46
+ redirect_to admin_pos_show_order_path(:number => @order.number)
47
+ end
48
+
49
+ def apply_discount
50
+ @item.price = @item.variant.price * ( 1.0 - @discount/100.0 )
51
+ @item.save
52
+ redirect_to admin_pos_show_order_path(:number => @order.number)
53
+ end
54
+
55
+ def clean_order
56
+ @order.clean!
57
+ redirect_to admin_pos_show_order_path(:number => @order.number), :notice => "Removed all items"
58
+ end
59
+
60
+ def associate_user
61
+ @user = @order.associate_user_for_pos(params[:email].present? ? params[:email] : params[:new_email])
62
+ if @user.errors.present?
63
+ add_error "Could not add the user:#{@user.errors.full_messages.to_sentence}"
64
+ else
65
+ @order.save!
66
+ flash[:notice] = 'Successfully Associated User'
67
+ end
68
+
69
+ redirect_to admin_pos_show_order_path(:number => @order.number)
70
+ end
71
+
72
+ def update_payment
73
+ @payment_method_id = params[:payment_method_id]
74
+ @payment = @order.save_payment_for_pos(params[:payment_method_id], params[:card_name])
75
+ if @payment.errors.blank?
76
+ print
77
+ else
78
+ add_error @payment.errors.full_messages.to_sentence
79
+ redirect_to admin_pos_show_order_path(:number => @order.number)
80
+ end
81
+ end
82
+
83
+ def update_stock_location
84
+ @order.shipment.stock_location = user_stock_locations(spree_current_user).where(:id => params[:stock_location_id]).first
85
+ if @order.shipment.save
86
+ flash[:notice] = "Updated Successfully"
87
+ else
88
+ flash[:error] = @order.shipment.errors.full_messages.to_sentence
89
+ end
90
+ redirect_to admin_pos_show_order_path(:number => @order.number)
91
+ end
92
+
93
+ private
94
+
95
+ def clean_and_reload_order
96
+ @order.clean!
97
+ load_order
98
+ end
99
+
100
+ def check_discount_request
101
+ @discount = params[:discount].try(:to_f)
102
+ redirect_to admin_pos_show_order_path(:number => @order.number), :flash => { :error => 'Please enter a valid discount' } unless VALID_DISCOUNT_REGEX.match(params[:discount]) || @discount >= 100
103
+ end
104
+
105
+ def ensure_pos_order
106
+ unless @order.is_pos?
107
+ flash[:error] = 'This is not a pos order'
108
+ render :show
109
+ end
110
+ end
111
+
112
+ def ensure_unpaid_order
113
+ if @order.paid?
114
+ flash[:error] = 'This order is already completed. Please use a new one.'
115
+ render :show
116
+ end
117
+ end
118
+
119
+ def load_line_item
120
+ @item = @order.line_items.where(:id => params[:line_item_id]).first
121
+ end
122
+
123
+ def check_unpaid_pos_order
124
+ if spree_current_user.unpaid_pos_orders.present?
125
+ add_error("You have an unpaid/empty order. Please either complete it or update items in the same order.")
126
+ redirect_to admin_pos_show_order_path(:number => spree_current_user.unpaid_pos_orders.first.number)
127
+ end
128
+ end
129
+
130
+ def ensure_existing_user
131
+ invalid_user_message = "No user with email #{params[:email]}" if params[:email].present? && Spree::User.where(:email => params[:email]).blank?
132
+ invalid_user_message = "User Already exists for the email #{params[:new_email]}" if params[:new_email].present? && Spree::User.where(:email => params[:new_email]).present?
133
+ redirect_to admin_pos_show_order_path(:number => @order.number), :flash => { :error => invalid_user_message } if invalid_user_message
134
+ end
135
+
136
+ def ensure_pos_shipping_method
137
+ redirect_to '/', :flash => { :error => 'No shipping method available for POS orders. Please assign one.'} and return unless Spree::ShippingMethod.where(:name => SpreePos::Config[:pos_shipping]).first
138
+ end
139
+
140
+ def load_order
141
+ @order = Spree::Order.by_number(params[:number]).includes([{ :line_items => [{ :variant => [:default_price, { :product => [:master] } ] }] } , { :adjustments => :adjustable }] ).first
142
+ raise "No order found for -#{params[:number]}-" unless @order
143
+ end
144
+
145
+ def load_variant
146
+ @variant = Spree::Variant.where(:id => params[:item]).first
147
+ unless @variant
148
+ flash[:error] = "No variant"
149
+ render :show
150
+ end
151
+ end
152
+
153
+ def check_valid_order
154
+ if @order.paid? || !@order.is_pos?
155
+ flash[:error] = 'This order is already completed. Please use a new one.' if @order.paid?
156
+ flash[:error] = 'This is not a pos order' unless @order.is_pos?
157
+ render :show
158
+ end
159
+ end
160
+
161
+ def ensure_payment_method
162
+ if Spree::PaymentMethod.where(:id => params[:payment_method_id]).blank?
163
+ flash[:error] = 'Please select a payment method'
164
+ redirect_to admin_pos_show_order_path(:number => @order.number)
165
+ end
166
+ end
167
+
168
+ def init_pos
169
+ @order = Spree::Order.new(:state => "complete", :is_pos => true, :completed_at => Time.current, :payment_state => 'balance_due')
170
+ @order.associate_user!(spree_current_user)
171
+ @order.save!
172
+ @order.assign_shipment_for_pos
173
+ @order.save!
174
+ session[:pos_order] = @order.number
175
+ end
176
+
177
+ def add_error error_message
178
+ flash[:error] = "" unless flash[:error]
179
+ flash[:error] << error_message
180
+ end
181
+
182
+ def add_variant var , quant = 1
183
+ line_item = @order.contents.add(var, quant, nil, @order.shipment)
184
+ var.product.save
185
+ line_item
186
+ end
187
+
188
+ def user_stock_locations(user)
189
+ # use this code when stock managers implemented
190
+ # @stock_location ||= (user.has_spree_role?('pos_admin') ? Spree::StockLocation.active.stores : user.stock_locations.active.store)
191
+ Spree::StockLocation.active.stores
192
+ end
193
+
194
+ def init_search
195
+ params[:q] ||= {}
196
+ params[:q].merge!(:meta_sort => "product_name asc", :deleted_at_null => "1", :product_deleted_at_null => "1", :published_at_not_null => "1")
197
+ params[:q][:product_name_cont].try(:strip!)
198
+ end
199
+
200
+ def print
201
+ @order.complete_via_pos
202
+ url = SpreePos::Config[:pos_printing].sub("number" , @order.number.to_s)
203
+ redirect_to url
204
+ end
205
+ end