[MERGE] point_of_sale: hardware proxy reliability improvements
bzr revid: fva@openerp.com-20140127132942-sz8yj8frk59c5z6m
This commit is contained in:
commit
1d7caa58bc
|
@ -10,6 +10,8 @@ import random
|
|||
import math
|
||||
import openerp.addons.hw_proxy.controllers.main as hw_proxy
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
|
||||
try:
|
||||
import usb.core
|
||||
|
@ -27,11 +29,16 @@ from openerp.addons.web.controllers.main import manifest_list, module_boot, html
|
|||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class EscposDriver(hw_proxy.Proxy):
|
||||
|
||||
supported_printers = [
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' }
|
||||
]
|
||||
class EscposDriver(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
self.queue = Queue()
|
||||
self.status = {'status':'connecting', 'messages':[]}
|
||||
|
||||
self.supported_printers = [
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' },
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0202, 'name' : 'Epson TM-T70' },
|
||||
]
|
||||
|
||||
def connected_usb_devices(self,devices):
|
||||
connected = []
|
||||
|
@ -41,28 +48,74 @@ class EscposDriver(hw_proxy.Proxy):
|
|||
return connected
|
||||
|
||||
def get_escpos_printer(self):
|
||||
printers = self.connected_usb_devices(self.supported_printers)
|
||||
if len(printers) > 0:
|
||||
return escpos.printer.Usb(printers[0]['vendor'], printers[0]['product'])
|
||||
else:
|
||||
try:
|
||||
printers = self.connected_usb_devices(self.supported_printers)
|
||||
if len(printers) > 0:
|
||||
self.set_status('connected','Connected to '+printers[0]['name'])
|
||||
return escpos.printer.Usb(printers[0]['vendor'], printers[0]['product'])
|
||||
else:
|
||||
self.set_status('disconnected','Printer Not Found')
|
||||
return None
|
||||
except Exception as e:
|
||||
self.set_status('error',str(e))
|
||||
return None
|
||||
|
||||
@http.route('/hw_proxy/open_cashbox', type='json', auth='admin')
|
||||
def open_cashbox(self):
|
||||
print 'ESC/POS: OPEN CASHBOX'
|
||||
eprint = self.get_escpos_printer()
|
||||
if eprint != None:
|
||||
eprint.cashdraw(2)
|
||||
eprint.cashdraw(5)
|
||||
|
||||
@http.route('/hw_proxy/print_receipt', type='json', auth='admin')
|
||||
def print_receipt(self, receipt):
|
||||
print 'ESC/POS: PRINT RECEIPT'
|
||||
eprint = self.get_escpos_printer()
|
||||
if eprint != None:
|
||||
self.print_receipt_body(eprint,receipt)
|
||||
eprint.cut()
|
||||
|
||||
|
||||
def get_status(self):
|
||||
self.push_task('status')
|
||||
return self.status
|
||||
|
||||
def open_cashbox(printer):
|
||||
printer.cashdraw(2)
|
||||
printer.cashdraw(5)
|
||||
|
||||
def set_status(self, status, message = None):
|
||||
if status == self.status['status']:
|
||||
if message != None and message != self.status['messages'][-1]:
|
||||
self.status['messages'].append(message)
|
||||
else:
|
||||
self.status['status'] = status
|
||||
if message:
|
||||
self.status['messages'] = [message]
|
||||
else:
|
||||
self.status['messages'] = []
|
||||
|
||||
if status == 'error' and message:
|
||||
_logger.error('ESC/POS Error: '+message)
|
||||
elif status == 'disconnected' and message:
|
||||
_logger.warning('ESC/POS Device Disconnected: '+message)
|
||||
|
||||
def run(self):
|
||||
self.queue = Queue()
|
||||
while True:
|
||||
try:
|
||||
timestamp, task, data = self.queue.get(True)
|
||||
|
||||
printer = self.get_escpos_printer()
|
||||
|
||||
if printer == None:
|
||||
if task != 'status':
|
||||
self.queue.put((timestamp,task,data))
|
||||
time.sleep(5)
|
||||
continue
|
||||
elif task == 'receipt':
|
||||
if timestamp >= time.time() - 1 * 60 * 60:
|
||||
self.print_receipt_body(printer,data)
|
||||
printer.cut()
|
||||
elif task == 'cashbox':
|
||||
if timestamp >= time.time() * 12:
|
||||
self.open_cashbox(printer)
|
||||
elif task == 'status':
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
self.set_status('error', str(e))
|
||||
_logger.error(e);
|
||||
|
||||
def push_task(self,task, data = None):
|
||||
if not self.isAlive():
|
||||
self.start()
|
||||
self.queue.put((time.time(),task,data))
|
||||
|
||||
def print_receipt_body(self,eprint,receipt):
|
||||
|
||||
def check(string):
|
||||
|
@ -203,4 +256,20 @@ class EscposDriver(hw_proxy.Proxy):
|
|||
+'/'+ str(receipt['date']['year']).zfill(4)
|
||||
+' '+ str(receipt['date']['hour']).zfill(2)
|
||||
+':'+ str(receipt['date']['minute']).zfill(2) )
|
||||
|
||||
driver = EscposDriver()
|
||||
|
||||
hw_proxy.drivers['escpos'] = driver
|
||||
|
||||
class EscposProxy(hw_proxy.Proxy):
|
||||
|
||||
@http.route('/hw_proxy/open_cashbox', type='json', auth='admin')
|
||||
def open_cashbox(self):
|
||||
_logger.info('ESC/POS: OPEN CASHBOX')
|
||||
driver.push_task('cashbox')
|
||||
|
||||
@http.route('/hw_proxy/print_receipt', type='json', auth='admin')
|
||||
def print_receipt(self, receipt):
|
||||
_logger.info('ESC/POS: PRINT RECEIPT')
|
||||
driver.push_task('receipt',receipt)
|
||||
|
||||
|
|
|
@ -44,10 +44,42 @@ TXT_ENC_PC865 = '\x1b\x74\x05' # PC865 Nordic
|
|||
TXT_ENC_KANJI6 = '\x1b\x74\x06' # One-pass Kanji, Hiragana
|
||||
TXT_ENC_KANJI7 = '\x1b\x74\x07' # One-pass Kanji
|
||||
TXT_ENC_KANJI8 = '\x1b\x74\x08' # One-pass Kanji
|
||||
TXT_ENC_PC851 = '\x1b\x74\x0b' # PC851 Greek
|
||||
TXT_ENC_PC853 = '\x1b\x74\x0c' # PC853 Turkish
|
||||
TXT_ENC_PC857 = '\x1b\x74\x0d' # PC857 Turkish
|
||||
TXT_ENC_PC737 = '\x1b\x74\x0e' # PC737 Greek
|
||||
TXT_ENC_8859_7 = '\x1b\x74\x0f' # ISO8859-7 Greek
|
||||
TXT_ENC_WPC1252 = '\x1b\x74\x10' # WPC1252
|
||||
TXT_ENC_PC866 = '\x1b\x74\x11' # PC866 Cyrillic #2
|
||||
TXT_ENC_PC852 = '\x1b\x74\x12' # PC852 Latin2
|
||||
TXT_ENC_PC858 = '\x1b\x74\x13' # PC858 Euro
|
||||
TXT_ENC_KU42 = '\x1b\x74\x14' # KU42 Thai
|
||||
TXT_ENC_TIS11 = '\x1b\x74\x15' # TIS11 Thai
|
||||
TXT_ENC_TIS18 = '\x1b\x74\x1a' # TIS18 Thai
|
||||
TXT_ENC_TCVN3 = '\x1b\x74\x1e' # TCVN3 Vietnamese
|
||||
TXT_ENC_TCVN3B = '\x1b\x74\x1f' # TCVN3 Vietnamese
|
||||
TXT_ENC_PC720 = '\x1b\x74\x20' # PC720 Arabic
|
||||
TXT_ENC_WPC775 = '\x1b\x74\x21' # WPC775 Baltic Rim
|
||||
TXT_ENC_PC855 = '\x1b\x74\x22' # PC855 Cyrillic
|
||||
TXT_ENC_PC861 = '\x1b\x74\x23' # PC861 Icelandic
|
||||
TXT_ENC_PC862 = '\x1b\x74\x24' # PC862 Hebrew
|
||||
TXT_ENC_PC864 = '\x1b\x74\x25' # PC864 Arabic
|
||||
TXT_ENC_PC869 = '\x1b\x74\x26' # PC869 Greek
|
||||
TXT_ENC_8859_2 = '\x1b\x74\x27' # ISO8859-2 Latin2
|
||||
TXT_ENC_8859_9 = '\x1b\x74\x28' # ISO8859-2 Latin9
|
||||
TXT_ENC_PC1098 = '\x1b\x74\x29' # PC1098 Farsi
|
||||
TXT_ENC_PC1118 = '\x1b\x74\x2a' # PC1118 Lithuanian
|
||||
TXT_ENC_PC1119 = '\x1b\x74\x2b' # PC1119 Lithuanian
|
||||
TXT_ENC_PC1125 = '\x1b\x74\x2c' # PC1125 Ukrainian
|
||||
TXT_ENC_WPC1250 = '\x1b\x74\x2d' # WPC1250 Latin2
|
||||
TXT_ENC_WPC1251 = '\x1b\x74\x2e' # WPC1251 Cyrillic
|
||||
TXT_ENC_WPC1253 = '\x1b\x74\x2f' # WPC1253 Greek
|
||||
TXT_ENC_WPC1254 = '\x1b\x74\x30' # WPC1254 Turkish
|
||||
TXT_ENC_WPC1255 = '\x1b\x74\x31' # WPC1255 Hebrew
|
||||
TXT_ENC_WPC1256 = '\x1b\x74\x32' # WPC1256 Arabic
|
||||
TXT_ENC_WPC1257 = '\x1b\x74\x33' # WPC1257 Baltic Rim
|
||||
TXT_ENC_WPC1258 = '\x1b\x74\x34' # WPC1258 Vietnamese
|
||||
TXT_ENC_KZ1048 = '\x1b\x74\x35' # KZ-1048 Kazakhstan
|
||||
|
||||
TXT_ENC_KATAKANA_MAP = {
|
||||
# Maps UTF-8 Katakana symbols to KATAKANA Page Codes
|
||||
|
|
|
@ -207,16 +207,28 @@ class Escpos:
|
|||
encoded = ''
|
||||
encoding = self.encoding # we reuse the last encoding to prevent code page switches at every character
|
||||
encodings = {
|
||||
# TODO use ordering to prevent useless switches
|
||||
# TODO Support other encodings not natively supported by python ( Thai, Khazakh, Kanjis )
|
||||
'cp437': TXT_ENC_PC437,
|
||||
'cp850': TXT_ENC_PC850,
|
||||
'cp852': TXT_ENC_PC852,
|
||||
'cp857': TXT_ENC_PC857,
|
||||
'cp858': TXT_ENC_PC858,
|
||||
'cp865': TXT_ENC_PC860,
|
||||
'cp860': TXT_ENC_PC860,
|
||||
'cp863': TXT_ENC_PC863,
|
||||
'cp865': TXT_ENC_PC865,
|
||||
'cp866': TXT_ENC_PC866,
|
||||
'cp862': TXT_ENC_PC862,
|
||||
'cp720': TXT_ENC_PC720,
|
||||
'iso8859_2': TXT_ENC_8859_2,
|
||||
'iso8859_7': TXT_ENC_8859_7,
|
||||
'iso8859_9': TXT_ENC_8859_9,
|
||||
'cp1254' : TXT_ENC_WPC1254,
|
||||
'cp1255' : TXT_ENC_WPC1255,
|
||||
'cp1256' : TXT_ENC_WPC1256,
|
||||
'cp1257' : TXT_ENC_WPC1257,
|
||||
'cp1258' : TXT_ENC_WPC1258,
|
||||
'katakana' : TXT_ENC_KATAKANA,
|
||||
# TODO Support other encodings not natively supported by python
|
||||
}
|
||||
remaining = copy.copy(encodings)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import openerp
|
|||
import time
|
||||
import random
|
||||
import subprocess
|
||||
import simplejson
|
||||
import werkzeug
|
||||
import werkzeug.wrappers
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
@ -17,13 +18,23 @@ from openerp.http import request
|
|||
from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
|
||||
|
||||
|
||||
# drivers modules must add to drivers an object with a get_status() method
|
||||
# so that 'status' can return the status of all active drivers
|
||||
drivers = {}
|
||||
|
||||
class Proxy(http.Controller):
|
||||
def __init__(self):
|
||||
self.scale = 'closed'
|
||||
self.scale_weight = 0.0
|
||||
|
||||
def get_status(self):
|
||||
statuses = {}
|
||||
for driver in drivers:
|
||||
statuses[driver] = drivers[driver].get_status()
|
||||
return statuses
|
||||
|
||||
@http.route('/hw_proxy/hello', type='http', auth='admin')
|
||||
def helloajx(self):
|
||||
def hello(self):
|
||||
return request.make_response('ping', {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
|
@ -35,6 +46,39 @@ class Proxy(http.Controller):
|
|||
def handshake(self):
|
||||
return True
|
||||
|
||||
@http.route('/hw_proxy/status', type='http', auth='admin')
|
||||
def status_http(self):
|
||||
resp = '<html>\n<body>\n<h1>Hardware Proxy Status</h1>\n'
|
||||
statuses = self.get_status()
|
||||
for driver in statuses:
|
||||
|
||||
status = statuses[driver]
|
||||
|
||||
if status['status'] == 'connecting':
|
||||
color = 'black'
|
||||
elif status['status'] == 'connected':
|
||||
color = 'green'
|
||||
else:
|
||||
color = 'red'
|
||||
|
||||
resp += "<h2 style='color:"+color+";'>"+driver+' : '+status['status']+"</h2>\n"
|
||||
resp += "<ul>\n"
|
||||
for msg in status['messages']:
|
||||
resp += '<li>'+msg+'</li>\n'
|
||||
resp += "</ul>\n"
|
||||
resp += "<script>\n\tsetTimeout(function(){window.location.reload();},30000);\n</script>\n</body>\n</html>\n\n"
|
||||
|
||||
return request.make_response(resp,{
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET',
|
||||
})
|
||||
|
||||
@http.route('/hw_proxy/status_json', type='json', auth='admin')
|
||||
def status_json(self):
|
||||
return self.get_status()
|
||||
|
||||
@http.route('/hw_proxy/scan_item_success', type='json', auth='admin')
|
||||
def scan_item_success(self, ean):
|
||||
"""
|
||||
|
|
|
@ -26,7 +26,9 @@ except ImportError:
|
|||
class Scanner(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
self.status = {'status':'connecting', 'messages':[]}
|
||||
self.input_dir = '/dev/input/by-id/'
|
||||
self.barcodes = Queue()
|
||||
self.keymap = {
|
||||
2: ("1","!"),
|
||||
3: ("2","@"),
|
||||
|
@ -84,6 +86,24 @@ class Scanner(Thread):
|
|||
57:(" "," "),
|
||||
}
|
||||
|
||||
def set_status(self, status, message = None):
|
||||
if status == self.status['status']:
|
||||
if message != None and message != self.status['messages'][-1]:
|
||||
self.status['messages'].append(message)
|
||||
else:
|
||||
self.status['status'] = status
|
||||
if message:
|
||||
self.status['messages'] = [message]
|
||||
else:
|
||||
self.status['messages'] = []
|
||||
|
||||
if status == 'error' and message:
|
||||
_logger.error('Barcode Scanner Error: '+message)
|
||||
elif status == 'disconnected' and message:
|
||||
_logger.warning('Disconnected Barcode Scanner: '+message)
|
||||
|
||||
|
||||
|
||||
def get_device(self):
|
||||
try:
|
||||
if not evdev:
|
||||
|
@ -92,14 +112,16 @@ class Scanner(Thread):
|
|||
keyboards = [ device for device in devices if 'kbd' in device ]
|
||||
scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower()) ]
|
||||
if len(scanners) > 0:
|
||||
self.set_status('connected','Connected to '+scanners[0])
|
||||
return evdev.InputDevice(join(self.input_dir,scanners[0]))
|
||||
elif len(keyboards) > 0:
|
||||
self.set_status('connected','Connected to '+keyboards[0])
|
||||
return evdev.InputDevice(join(self.input_dir,keyboards[0]))
|
||||
else:
|
||||
_logger.error('Could not find the Barcode Scanner')
|
||||
self.set_status('disconnected','Barcode Scanner Not Found')
|
||||
return None
|
||||
except Exception as e:
|
||||
_logger.error('Found the Barcode Scanner, but unable to access it\n Exception: ' + str(e))
|
||||
self.set_status('error',str(e))
|
||||
return None
|
||||
|
||||
@http.route('/hw_proxy/Vis_scanner_connected', type='json', auth='admin')
|
||||
|
@ -120,6 +142,9 @@ class Scanner(Thread):
|
|||
return barcode
|
||||
except Empty:
|
||||
return ''
|
||||
|
||||
def get_status(self):
|
||||
return self.status
|
||||
|
||||
def run(self):
|
||||
""" This will start a loop that catches all keyboard events, parse barcode
|
||||
|
@ -138,7 +163,7 @@ class Scanner(Thread):
|
|||
try:
|
||||
device.ungrab()
|
||||
except Exception as e:
|
||||
_logger.error('Unable to release barcode scanner\n Exception:'+str(e))
|
||||
self.set_status('error',str(e))
|
||||
device = self.get_device()
|
||||
if not device:
|
||||
time.sleep(5) # wait until a suitable device is plugged
|
||||
|
@ -173,17 +198,13 @@ class Scanner(Thread):
|
|||
shift = False
|
||||
|
||||
except Exception as e:
|
||||
_logger.error('Could not read Barcode Scanner Events:\n Exception: '+str(e))
|
||||
self.set_status('error',str(e))
|
||||
|
||||
s = Scanner()
|
||||
|
||||
hw_proxy.drivers['scanner'] = s
|
||||
|
||||
class ScannerDriver(hw_proxy.Proxy):
|
||||
@http.route('/hw_proxy/is_scanner_connected', type='json', auth='admin')
|
||||
def is_scanner_connected(self):
|
||||
if not s.isAlive():
|
||||
s.start()
|
||||
return s.get_device() != None
|
||||
|
||||
@http.route('/hw_proxy/scanner', type='json', auth='admin')
|
||||
def scanner(self):
|
||||
if not s.isAlive():
|
||||
|
|
|
@ -379,13 +379,16 @@ td {
|
|||
width:20px; height:16px;
|
||||
color: white;
|
||||
}
|
||||
.pos .oe_icon.oe_red{
|
||||
.pos .oe_status .oe_red,
|
||||
.pos .oe_icon.oe_red {
|
||||
color: rgb(197, 52, 0);
|
||||
}
|
||||
.pos .oe_icon.oe_green{
|
||||
.pos .oe_statu .oe_green,
|
||||
.pos .oe_icon.oe_green {
|
||||
color: rgb(94, 185, 55);
|
||||
}
|
||||
.pos .oe_icon.oe_orange{
|
||||
.pos .oe_status .oe_orange,
|
||||
.pos .oe_icon.oe_orange {
|
||||
color: rgb(239, 153, 65);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,8 +81,9 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
// connected to the Point of Sale. As the communication only goes from the POS to the proxy,
|
||||
// methods are used both to signal an event, and to fetch information.
|
||||
|
||||
module.ProxyDevice = instance.web.Class.extend({
|
||||
init: function(options){
|
||||
module.ProxyDevice = instance.web.Class.extend(openerp.PropertiesMixin,{
|
||||
init: function(parent,options){
|
||||
openerp.PropertiesMixin.init.call(this,parent);
|
||||
var self = this;
|
||||
options = options || {};
|
||||
url = options.url || 'http://localhost:8069';
|
||||
|
@ -105,56 +106,117 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
this.bypass_proxy = false;
|
||||
|
||||
this.connection = null;
|
||||
this.connected = new $.Deferred();
|
||||
this.status = 'disconnected';
|
||||
this.host = '';
|
||||
this.keptalive = false;
|
||||
|
||||
window.proxy = this;
|
||||
this.set('status',{});
|
||||
|
||||
this.set_connection_status('disconnected');
|
||||
|
||||
window.hw_proxy = this;
|
||||
},
|
||||
close: function(){
|
||||
if(this.status !== 'disconnected'){
|
||||
set_connection_status: function(status,drivers){
|
||||
oldstatus = this.get('status');
|
||||
newstatus = {};
|
||||
newstatus.status = status;
|
||||
newstatus.drivers = status === 'disconnected' ? {} : oldstatus.drivers;
|
||||
newstatus.drivers = drivers ? drivers : newstatus.drivers;
|
||||
this.set('status',newstatus);
|
||||
},
|
||||
disconnect: function(){
|
||||
if(this.get('status').status !== 'disconnected'){
|
||||
this.connection.destroy();
|
||||
this.status = 'disconnected';
|
||||
this.set_connection_status('disconnected');
|
||||
}
|
||||
},
|
||||
connect : function(url){
|
||||
|
||||
// connects to the specified url
|
||||
connect: function(url){
|
||||
var self = this;
|
||||
this.connection = new instance.web.Session(undefined,url);
|
||||
this.status = 'connecting';
|
||||
this.host = url;
|
||||
this.set_connection_status('connecting',{});
|
||||
|
||||
return this.message('handshake').then(function(){
|
||||
self.status = 'connected';
|
||||
localStorage['hw_proxy_url'] = url;
|
||||
self.connected.resolve();
|
||||
return this.message('handshake').then(function(response){
|
||||
if(response){
|
||||
self.set_connection_status('connected');
|
||||
localStorage['hw_proxy_url'] = url;
|
||||
self.keepalive();
|
||||
}else{
|
||||
self.set_connection_status('disconnected');
|
||||
console.error('Connection refused by the Proxy');
|
||||
}
|
||||
},function(){
|
||||
self.status = 'disconnected';
|
||||
self.connected.reject();
|
||||
self.set_connection_status('disconnected');
|
||||
console.error('Could not connect to the Proxy');
|
||||
});
|
||||
},
|
||||
|
||||
// find a proxy and connects to it. for options see find_proxy
|
||||
autoconnect: function(options){
|
||||
var self = this;
|
||||
this.set_connection_status('connecting',{});
|
||||
var success = new $.Deferred();
|
||||
this.find_proxy(options)
|
||||
.then(function(proxies){
|
||||
if(proxies.length > 0){
|
||||
self.connect(proxies[0])
|
||||
.then(function(){
|
||||
success.resolve();
|
||||
},function(){
|
||||
self.set_connection_status('disconnected');
|
||||
success.reject();
|
||||
});
|
||||
}else{
|
||||
self.set_connection_status('disconnected');
|
||||
success.reject();
|
||||
}
|
||||
});
|
||||
return success;
|
||||
},
|
||||
|
||||
// starts a loop that updates the connection status
|
||||
keepalive: function(){
|
||||
var self = this;
|
||||
if(!this.keptalive){
|
||||
this.keptalive = true;
|
||||
function status(){
|
||||
self.connection.rpc('/hw_proxy/status_json',{},{timeout:500})
|
||||
.then(function(driver_status){
|
||||
self.set_connection_status('connected',driver_status);
|
||||
},function(){
|
||||
if(self.get('status').status !== 'connecting'){
|
||||
self.set_connection_status('disconnected');
|
||||
}
|
||||
}).always(function(){
|
||||
setTimeout(status,5000);
|
||||
});
|
||||
}
|
||||
status();
|
||||
};
|
||||
},
|
||||
|
||||
message : function(name,params){
|
||||
var callbacks = this.notifications[name] || [];
|
||||
for(var i = 0; i < callbacks.length; i++){
|
||||
callbacks[i](params);
|
||||
}
|
||||
if(this.status !== 'disconnected'){
|
||||
if(this.get('status').status !== 'disconnected'){
|
||||
return this.connection.rpc('/hw_proxy/' + name, params || {});
|
||||
}else{
|
||||
return (new $.Deferred()).reject();
|
||||
}
|
||||
},
|
||||
|
||||
test_connection: function(host,timeout){
|
||||
return $.ajax({
|
||||
url: host + '/hw_proxy/hello',
|
||||
method: 'GET',
|
||||
timeout: timeout || 10000,
|
||||
});
|
||||
},
|
||||
|
||||
// returns as a deferred a list of valid hosts urls that can be used as proxy.
|
||||
// options:
|
||||
// - port: what port to listen to (default 8069)
|
||||
// - force_ip : limit the search to the specified ip
|
||||
// - progress(fac) : callback for search progress ( fac in [0,1] )
|
||||
find_proxy: function(options){
|
||||
options = options || {};
|
||||
var self = this;
|
||||
var port = ':8069';
|
||||
var port = ':' + (options.port || '8069');
|
||||
var urls = [];
|
||||
var found = false;
|
||||
var proxies = [];
|
||||
|
@ -163,6 +225,8 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
var threads = [];
|
||||
var progress = 0;
|
||||
|
||||
this.set_connection_status('connecting');
|
||||
|
||||
if(options.force_ip){
|
||||
urls.push(options.force_ip);
|
||||
}else{
|
||||
|
@ -193,8 +257,11 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
if(!url){
|
||||
done.resolve();
|
||||
}
|
||||
var c = self.test_connection(url, 300)
|
||||
.done(function(){
|
||||
var c = $.ajax({
|
||||
url: url + '/hw_proxy/hello',
|
||||
method: 'GET',
|
||||
timeout: 300,
|
||||
}).done(function(){
|
||||
found = true;
|
||||
update_progress();
|
||||
proxies.push(url);
|
||||
|
@ -235,6 +302,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
|
||||
stop_searching: function(){
|
||||
this.searching_for_proxy = false;
|
||||
this.set_connection_status('disconnected');
|
||||
},
|
||||
|
||||
// this allows the client to be notified when a proxy call is made. The notification
|
||||
|
@ -245,8 +313,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
}
|
||||
this.notifications[name].push(callback);
|
||||
},
|
||||
|
||||
|
||||
|
||||
//a product has been scanned and recognized with success
|
||||
// ean is a parsed ean object
|
||||
|
@ -465,6 +531,8 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
this.pos = attributes.pos;
|
||||
this.action_callback = {};
|
||||
this.proxy = attributes.proxy;
|
||||
this.remote_scanning = false;
|
||||
this.remote_active = 0;
|
||||
|
||||
this.action_callback_stack = [];
|
||||
|
||||
|
@ -473,6 +541,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
this.price_prefix_set = attributes.price_prefix_set || {'23':''};
|
||||
this.cashier_prefix_set = attributes.cashier_prefix_set || {'041':''};
|
||||
this.client_prefix_set = attributes.client_prefix_set || {'042':''};
|
||||
|
||||
},
|
||||
|
||||
save_callbacks: function(){
|
||||
|
@ -699,30 +768,41 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
disconnect: function(){
|
||||
$('body').off('keypress', this.handler)
|
||||
},
|
||||
disconnect_from_proxy: function(){
|
||||
this.remote_scanning = false;
|
||||
},
|
||||
connect_to_proxy: function(){
|
||||
|
||||
// the barcode scanner will listen on the hw_proxy/scanner interface for
|
||||
// scan events until disconnect_from_proxy is called
|
||||
connect_to_proxy: function(){
|
||||
var self = this;
|
||||
this.remote_scanning = true;
|
||||
if(this.remote_active >= 1){
|
||||
return;
|
||||
}
|
||||
this.remote_active = 1;
|
||||
|
||||
this.proxy.connected.then(function waitforbarcode(){
|
||||
if(!self.remote_scanning){
|
||||
return;
|
||||
}
|
||||
return self.proxy.connection.rpc('/hw_proxy/scanner',{}).then(function(barcode){
|
||||
function waitforbarcode(){
|
||||
return self.proxy.connection.rpc('/hw_proxy/scanner',{},{timeout:7500})
|
||||
.then(function(barcode){
|
||||
if(!self.remote_scanning){
|
||||
self.remote_active = 0;
|
||||
return;
|
||||
}
|
||||
self.pos.set('proxy_status','connected');
|
||||
self.scan(barcode);
|
||||
waitforbarcode();
|
||||
},
|
||||
function(){
|
||||
if(!self.remote_scanning){
|
||||
self.remote_active = 0;
|
||||
return;
|
||||
}
|
||||
setTimeout(waitforbarcode,5000);
|
||||
self.pos.set('proxy_status','disconnected');
|
||||
});
|
||||
});
|
||||
}
|
||||
waitforbarcode();
|
||||
},
|
||||
|
||||
// the barcode scanner will stop listening on the hw_proxy/scanner remote interface
|
||||
disconnect_from_proxy: function(){
|
||||
this.remote_scanning = false;
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.flush_mutex = new $.Mutex(); // used to make sure the orders are sent to the server once at time
|
||||
this.pos_widget = attributes.pos_widget;
|
||||
|
||||
this.proxy = new module.ProxyDevice(); // used to communicate to the hardware devices via a local proxy
|
||||
this.proxy = new module.ProxyDevice(this); // used to communicate to the hardware devices via a local proxy
|
||||
this.barcode_reader = new module.BarcodeReader({'pos': this, proxy:this.proxy}); // used to read barcodes
|
||||
this.proxy_queue = new module.JobQueue(); // used to prevent parallels communications to the proxy
|
||||
this.db = new module.PosDB(); // a local database used to search trough products and categories & store pending orders
|
||||
|
@ -55,7 +55,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
'synch': { state:'connected', pending:0 },
|
||||
'orders': new module.OrderCollection(),
|
||||
'selectedOrder': null,
|
||||
'proxy_status': 'connecting',
|
||||
});
|
||||
|
||||
this.bind('change:synch',function(pos,synch){
|
||||
|
@ -91,32 +90,21 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.barcode_reader.disconnect();
|
||||
this.barcode_reader.disconnect_from_proxy();
|
||||
},
|
||||
|
||||
connect_to_proxy: function(){
|
||||
var self = this;
|
||||
this.barcode_reader.disconnect_from_proxy();
|
||||
this.pos_widget.loading_message(_t('Connecting to the PosBox'),0);
|
||||
this.set('proxy_status', 'connecting');
|
||||
|
||||
this.pos_widget.loading_skip(function(){
|
||||
self.proxy.stop_searching();
|
||||
self.set('proxy_status', 'disconnected');
|
||||
});
|
||||
|
||||
return this.proxy.find_proxy({
|
||||
this.proxy.autoconnect({
|
||||
force_ip: self.config.proxy_ip || undefined,
|
||||
progress: function(prog){
|
||||
self.pos_widget.loading_progress(prog);
|
||||
},
|
||||
}).then(function(proxies){
|
||||
if(proxies.length > 0){
|
||||
self.proxy.connect(proxies[0]);
|
||||
if(self.config.iface_scan_via_proxy){
|
||||
self.barcode_reader.connect_to_proxy();
|
||||
}
|
||||
self.set('proxy_status', 'connected');
|
||||
}else{
|
||||
self.set('proxy_status', 'disconnected');
|
||||
}).then(function(){
|
||||
if(self.config.iface_scan_via_proxy){
|
||||
self.barcode_reader.connect_to_proxy();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -856,13 +856,39 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
// this is used to notify the user if the pos is connected to the proxy
|
||||
module.ProxyStatusWidget = module.StatusWidget.extend({
|
||||
template: 'ProxyStatusWidget',
|
||||
set_smart_status: function(status){
|
||||
if(status.status === 'connected'){
|
||||
var warning = false;
|
||||
var msg = ''
|
||||
if(this.pos.config.iface_scan_via_proxy){
|
||||
var scanner = status.drivers.scanner ? status.drivers.scanner.status : false;
|
||||
if( scanner != 'connected' && scanner != 'connecting'){
|
||||
warning = true;
|
||||
msg += _t('Scanner');
|
||||
}
|
||||
}
|
||||
if( this.pos.config.iface_print_via_proxy ||
|
||||
this.pos.config.iface_cashdrawer ){
|
||||
var printer = status.drivers.escpos ? status.drivers.escpos.status : false;
|
||||
if( printer != 'connected' && printer != 'connecting'){
|
||||
warning = true;
|
||||
msg = msg ? msg + ' & ' : msg;
|
||||
msg += _t('Printer');
|
||||
}
|
||||
}
|
||||
msg = msg ? msg + ' ' + _t('Offline') : msg;
|
||||
this.set_status(warning ? 'warning' : 'connected', msg);
|
||||
}else{
|
||||
this.set_status(status.status,'');
|
||||
}
|
||||
},
|
||||
start: function(){
|
||||
var self = this;
|
||||
|
||||
this.set_status(this.pos.get('proxy_status'),'');
|
||||
this.set_smart_status(this.pos.proxy.get('status'));
|
||||
|
||||
this.pos.bind('change:proxy_status', function(pos,status){
|
||||
self.set_status(status,'');
|
||||
this.pos.proxy.on('change:status',this,function(eh,status){ //FIXME remove duplicate changes
|
||||
self.set_smart_status(status.newValue);
|
||||
});
|
||||
|
||||
this.$el.click(function(){
|
||||
|
|
|
@ -117,13 +117,16 @@
|
|||
|
||||
<t t-name="ProxyStatusWidget">
|
||||
<div class="oe_status js_proxy">
|
||||
<span class='js_msg oe_hidden'></span>
|
||||
<span class='js_msg oe_orange oe_hidden'></span>
|
||||
<div class="js_connected oe_icon oe_green">
|
||||
<i class='fa fa-fw fa-sitemap'></i>
|
||||
</div>
|
||||
<div class="js_connecting oe_icon oe_hidden">
|
||||
<i class='fa fa-fw fa-spin fa-spinner'></i>
|
||||
</div>
|
||||
<div class="js_warning oe_icon oe_orange oe_hidden">
|
||||
<i class='fa fa-fw fa-sitemap'></i>
|
||||
</div>
|
||||
<div class="js_disconnected oe_icon oe_red oe_hidden">
|
||||
<i class='fa fa-fw fa-sitemap'></i>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue