[MERGE] point_of_sale: posbox related usability & reliability improvements + firefox...
authorFrédéric van der Essen <fva@openerp.com>
Mon, 10 Feb 2014 15:53:18 +0000 (16:53 +0100)
committerFrédéric van der Essen <fva@openerp.com>
Mon, 10 Feb 2014 15:53:18 +0000 (16:53 +0100)
bzr revid: fva@openerp.com-20140210155318-1exkkl4ij93jtbq2

addons/hw_escpos/controllers/main.py
addons/hw_scanner/controllers/main.py
addons/point_of_sale/static/src/js/devices.js
addons/point_of_sale/static/src/js/widgets.js
addons/point_of_sale/static/src/xml/pos.xml

index 5230731..c2e777f 100644 (file)
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+import commands
 import logging
 import simplejson
 import os
@@ -11,7 +12,7 @@ import math
 import md5
 import openerp.addons.hw_proxy.controllers.main as hw_proxy
 import subprocess
-from threading import Thread
+from threading import Thread, Lock
 from Queue import Queue, Empty
 
 try:
@@ -39,6 +40,7 @@ class EscposDriver(Thread):
     def __init__(self):
         Thread.__init__(self)
         self.queue = Queue()
+        self.lock  = Lock()
         self.status = {'status':'connecting', 'messages':[]}
 
     def connected_usb_devices(self):
@@ -47,6 +49,13 @@ class EscposDriver(Thread):
             if usb.core.find(idVendor=device['vendor'], idProduct=device['product']) != None:
                 connected.append(device)
         return connected
+
+    def lockedstart(self):
+        self.lock.acquire()
+        if not self.isAlive():
+            self.daemon = True
+            self.start()
+        self.lock.release()
     
     def get_escpos_printer(self):
         try:
@@ -105,6 +114,8 @@ class EscposDriver(Thread):
                 elif task == 'cashbox':
                     if timestamp >= time.time() - 12:
                         self.open_cashbox(printer)
+                elif task == 'printstatus':
+                    self.print_status(printer)
                 elif task == 'status':
                     pass
 
@@ -113,10 +124,31 @@ class EscposDriver(Thread):
                 _logger.error(e);
 
     def push_task(self,task, data = None):
-        if not self.isAlive():
-            self.start()
+        self.lockedstart()
         self.queue.put((time.time(),task,data))
 
+    def print_status(self,eprint):
+        localips = ['0.0.0.0','127.0.0.1','127.0.1.1']
+        ips =  [ c.split(':')[1].split(' ')[0] for c in commands.getoutput("/sbin/ifconfig").split('\n') if 'inet addr' in c ]
+        ips =  [ ip for ip in ips if ip not in localips ] 
+        eprint.text('\n\n')
+        eprint.set(align='center',type='b',height=2,width=2)
+        eprint.text('PosBox Status\n')
+        eprint.text('\n')
+        eprint.set(align='center')
+
+        if len(ips) == 0:
+            eprint.text('ERROR: Could not connect to LAN\n\nPlease check that the PosBox is correc-\ntly connected with a network cable,\n that the LAN is setup with DHCP, and\nthat network addresses are available')
+        elif len(ips) == 1:
+            eprint.text('IP Address\n'+ips[0]+'\n')
+        else:
+            eprint.text('IP Addresses\n')
+            for ip in ips:
+                eprint.text(ip+'\n')
+
+        eprint.text('\n\n')
+        eprint.cut()
+
     def print_receipt_body(self,eprint,receipt):
 
         def check(string):
@@ -134,7 +166,6 @@ class EscposDriver(Thread):
             else:
                 return str(amount)
 
-
         def printline(left, right='', width=40, ratio=0.5, indent=0):
             lwidth = int(width * ratio) 
             rwidth = width - lwidth 
@@ -157,6 +188,7 @@ class EscposDriver(Thread):
 
         # Receipt Header
         if receipt['company']['logo']:
+            eprint.set(align='center')
             eprint.print_base64_image(receipt['company']['logo'])
             eprint.text('\n')
         else:
@@ -245,6 +277,8 @@ class EscposDriver(Thread):
 driver = EscposDriver()
 
 hw_proxy.drivers['escpos'] = driver
+
+driver.push_task('printstatus')
         
 class EscposProxy(hw_proxy.Proxy):
     
index 105856a..8fbdae6 100644 (file)
@@ -4,7 +4,7 @@ import os
 import time
 from os import listdir
 from os.path import join
-from threading import Thread
+from threading import Thread, Lock
 from select import select
 from Queue import Queue, Empty
 
@@ -26,6 +26,7 @@ except ImportError:
 class Scanner(Thread):
     def __init__(self):
         Thread.__init__(self)
+        self.lock = Lock()
         self.status = {'status':'connecting', 'messages':[]}
         self.input_dir = '/dev/input/by-id/'
         self.barcodes = Queue()
@@ -86,6 +87,12 @@ class Scanner(Thread):
             57:(" "," "),
         }
 
+    def lockedstart(self):
+        self.lock.acquire()
+        if not self.isAlive():
+            self.start()
+        self.lock.release()
+
     def set_status(self, status, message = None):
         if status == self.status['status']:
             if message != None and message != self.status['messages'][-1]:
@@ -102,8 +109,6 @@ class Scanner(Thread):
         elif status == 'disconnected' and message:
             _logger.warning('Disconnected Barcode Scanner: '+message)
 
-            
-
     def get_device(self):
         try:
             if not evdev:
@@ -135,6 +140,8 @@ class Scanner(Thread):
             busy reading another barcode
         """
 
+        self.lockedstart()
+
         while True:
             try:
                 timestamp, barcode = self.barcodes.get(True, 5)
@@ -144,8 +151,7 @@ class Scanner(Thread):
                 return ''
     
     def get_status(self):
-        if not s.isAlive():
-            s.start()
+        self.lockedstart()
         return self.status
 
     def run(self):
@@ -209,7 +215,6 @@ hw_proxy.drivers['scanner'] = s
 class ScannerDriver(hw_proxy.Proxy):
     @http.route('/hw_proxy/scanner', type='json', auth='none', cors='*')
     def scanner(self):
-        if not s.isAlive():
-            s.start()
         return s.get_barcode()
         
+        
index 8eb32d6..683cfae 100644 (file)
@@ -162,25 +162,37 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
         },
 
         // find a proxy and connects to it. for options see find_proxy
+        //   - force_ip : only try to connect to the specified ip. 
+        //   - port: what port to listen to (default 8069)
+        //   - progress(fac) : callback for search progress ( fac in [0,1] ) 
         autoconnect: function(options){
             var self = this;
             this.set_connection_status('connecting',{});
+            var found_url = new $.Deferred();
             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();
-                    }
+
+            if ( options.force_ip ){
+                // if the ip is forced by server config, bailout on fail
+                found_url = this.try_hard_to_connect(options.force_ip, options)
+            }else if( localStorage['hw_proxy_url'] ){
+                // try harder when we remember a good proxy url
+                found_url = this.try_hard_to_connect(localStorage['hw_proxy_url'], options)
+                    .then(null,function(){
+                        return self.find_proxy(options);
+                    });
+            }else{
+                // just find something quick
+                found_url = this.find_proxy(options);
+            }
+
+            success = found_url.then(function(url){
+                    return self.connect(url);
                 });
+
+            success.fail(function(){
+                self.set_connection_status('disconnected');
+            });
+
             return success;
         },
 
@@ -217,10 +229,50 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
             }
         },
 
-        // returns as a deferred a list of valid hosts urls that can be used as proxy.
+        // try several time to connect to a known proxy url
+        try_hard_to_connect: function(url,options){
+            options   = options || {};
+            var port  = ':' + (options.port || '8069');
+
+            this.set_connection_status('connecting');
+
+            if(url.indexOf('//') < 0){
+                url = 'http://'+url;
+            }
+
+            if(url.indexOf(':',5) < 0){
+                url = url+port;
+            }
+
+            // try real hard to connect to url, with a 1sec timeout and up to 'retries' retries
+            function try_real_hard_to_connect(url, retries, done){
+
+                done = done || new $.Deferred();
+
+                var c = $.ajax({
+                    url: url + '/hw_proxy/hello',
+                    method: 'GET',
+                    timeout: 1000,
+                })
+                .done(function(){
+                    done.resolve(url);
+                })
+                .fail(function(){
+                    if(retries > 0){
+                        try_real_hard_to_connect(url,retries-1,done);
+                    }else{
+                        done.reject();
+                    }
+                });
+                return done;
+            }
+
+            return try_real_hard_to_connect(url,3);
+        },
+
+        // returns as a deferred a valid host url 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 || {};
@@ -228,36 +280,17 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
             var port  = ':' + (options.port || '8069');
             var urls  = [];
             var found = false;
-            var proxies = [];
-            var done  = new $.Deferred();
             var parallel = 8;
+            var done = new $.Deferred(); // will be resolved with the proxies valid urls
             var threads  = [];
             var progress = 0;
 
-            this.set_connection_status('connecting');
 
-            if(options.force_ip){
-                var url = options.force_ip;
-                if(url.indexOf('//') < 0){
-                    url = 'http://'+url;
-                }
-                if(url.indexOf(':',5) < 0){
-                    url = url+port;
-                }
-                urls.push(url);
-            }else{
-                if(localStorage['hw_proxy_url']){
-                    urls.push(localStorage['hw_proxy_url']);
-                }
-
-                urls.push('http://localhost'+port);
-
-                for(var i = 0; i < 256; i++){
-                    urls.push('http://192.168.0.'+i+port);
-                    urls.push('http://192.168.1.'+i+port);
-                    urls.push('http://192.168.2.'+i+port);
-                    urls.push('http://10.0.0.'+i+port);
-                }
+            urls.push('http://localhost'+port);
+            for(var i = 0; i < 256; i++){
+                urls.push('http://192.168.0.'+i+port);
+                urls.push('http://192.168.1.'+i+port);
+                urls.push('http://10.0.0.'+i+port);
             }
 
             var prog_inc = 1/urls.length; 
@@ -269,40 +302,39 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
                 }
             }
 
-            function thread(url,done){
-                if(!url){ 
+            function thread(done){
+                var url = urls.shift();
+
+                done = done || new $.Deferred();
+
+                if( !url || found || !self.searching_for_proxy ){ 
                     done.resolve();
+                    return done;
                 }
+
                 var c = $.ajax({
                         url: url + '/hw_proxy/hello',
                         method: 'GET',
-                        timeout: 300, 
+                        timeout: 400, 
                     }).done(function(){
                         found = true;
                         update_progress();
-                        proxies.push(url);
                         done.resolve(url);
                     })
                     .fail(function(){
                         update_progress();
-                        var next_url = urls.shift();
-                        if(found ||! self.searching_for_proxy || !next_url){
-                            done.resolve();
-                        }else{
-                            thread(next_url,done);
-                        }
+                        thread(done);
                     });
+
                 return done;
             }
 
             this.searching_for_proxy = true;
 
-            for(var i = 0; i < Math.min(parallel,urls.length); i++){
-                threads.push(thread(urls.shift(),new $.Deferred()));
+            for(var i = 0, len = Math.min(parallel,urls.length); i < len; i++){
+                threads.push(thread());
             }
             
-            var done = new $.Deferred();
-            
             $.when.apply($,threads).then(function(){
                 var urls = [];
                 for(var i = 0; i < arguments.length; i++){
@@ -310,7 +342,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
                         urls.push(arguments[i]);
                     }
                 }
-                done.resolve(urls);
+                done.resolve(urls[0]);
             });
 
             return done;
index f2a2545..a2f0759 100644 (file)
@@ -258,8 +258,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
             var total     = order ? order.getTotalTaxIncluded() : 0;
             var taxes     = order ? total - order.getTotalTaxExcluded() : 0;
 
-            this.el.querySelector('.summary .total > .value').innerText = this.format_currency(total);
-            this.el.querySelector('.summary .total .subentry .value').innerText = this.format_currency(taxes);
+            this.el.querySelector('.summary .total > .value').textContent = this.format_currency(total);
+            this.el.querySelector('.summary .total .subentry .value').textContent = this.format_currency(taxes);
         },
     });
 
index 748fcbf..d0cd945 100644 (file)
             Shop: <t t-esc="widget.pos.shop.name"/><br />
             <br />
             <t t-if="widget.pos.config.receipt_header">
-                <pre>
+                <div style='text-align:center'>
                     <t t-esc="widget.pos.config.receipt_header" />
-                </pre>
+                </div>
                 <br />
             </t>
             <table>
             </table>
             <t t-if="widget.pos.config.receipt_footer">
                 <br />
-                <pre>
+                <div style='text-align:center'>
                     <t t-esc="widget.pos.config.receipt_footer" />
-                </pre>
+                </div>
             </t>
         </div>
     </t>