[MERGE] forward porting fixes from saas-3
bzr revid: fva@openerp.com-20140210155628-75mgw7qcq9k5ncem
This commit is contained in:
commit
04a6074b1a
|
@ -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):
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -635,9 +635,9 @@
|
|||
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>
|
||||
|
@ -711,9 +711,9 @@
|
|||
</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>
|
||||
|
|
|
@ -133,8 +133,9 @@ class view(osv.osv):
|
|||
if not context:
|
||||
context = {}
|
||||
|
||||
qcontext = context.copy()
|
||||
qcontext = dict(editable=False)
|
||||
qcontext.update(
|
||||
context.copy(),
|
||||
website=request.website,
|
||||
url_for=website.url_for,
|
||||
slug=website.slug,
|
||||
|
|
|
@ -638,7 +638,7 @@
|
|||
image_dialog(editor, new CKEDITOR.dom.element(previous));
|
||||
$image_button.hide();
|
||||
previous = null;
|
||||
});
|
||||
}, 'btn-sm');
|
||||
|
||||
// previous is the state of the button-trigger: it's the
|
||||
// currently-ish hovered element which can trigger a button showing.
|
||||
|
|
|
@ -71,8 +71,8 @@
|
|||
{
|
||||
snippet: 'three-columns',
|
||||
placement: 'bottom',
|
||||
title: _t("Drag & Drop a Block"),
|
||||
content: _t("Drag the <em>'3 Columns'</em> block and drop it below the banner."),
|
||||
title: _t("Drag & Drop This Block"),
|
||||
content: _t("Drag the <em>'Three Columns'</em> block and drop it below the banner."),
|
||||
popover: { fixed: true },
|
||||
},
|
||||
{
|
||||
|
@ -98,17 +98,18 @@
|
|||
popover: { fixed: true },
|
||||
},
|
||||
{
|
||||
element: 'button[data-dismiss=modal]',
|
||||
element: '.modal:has(#mobile-viewport) button[data-dismiss=modal]',
|
||||
placement: 'right',
|
||||
title: _t("Close Mobile Preview"),
|
||||
content: _t("Scroll in the mobile preview to test the rendering. Once it's ok, close this dialog."),
|
||||
},
|
||||
{
|
||||
title: "Congratulation",
|
||||
element: 'a[id=content-menu-button]',
|
||||
waitNot: '.modal',
|
||||
element: '#content-menu-button',
|
||||
placement: 'bottom',
|
||||
content: _t("This tour is finished. You can continue discovering features with the <em>'Content'</em> menu."),
|
||||
popover: { fixed: true, next: _t("Close Tutorial") },
|
||||
title: _t("Add new pages and menus"),
|
||||
content: _t("The 'Content' menu allows you to add pages or add the top menu."),
|
||||
popover: { next: _t("Close Tutorial") },
|
||||
},
|
||||
];
|
||||
return this._super();
|
||||
|
|
|
@ -77,7 +77,11 @@ website.Tour = openerp.Class.extend({
|
|||
|
||||
website.Tour.busy = true;
|
||||
|
||||
this.localStorage.setItem("tour-"+this.id+"-test-automatic", automatic);
|
||||
if (automatic) {
|
||||
this.localStorage.setItem("tour-"+this.id+"-test-automatic", true);
|
||||
} else {
|
||||
this.localStorage.removeItem("tour-"+this.id+"-test-automatic");
|
||||
}
|
||||
this.automatic = automatic;
|
||||
|
||||
if (this.path) {
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
</div>
|
||||
</t>
|
||||
<t t-name="website.tour_popover_title">
|
||||
<t t-esc="title"/><button title="Close Tutorial" type="button" class="close" data-role="end">×</button>
|
||||
<t t-esc="title"/><button title="End This Tutorial" type="button" class="close" data-role="end">×</button>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
|
@ -224,7 +224,7 @@
|
|||
<xpath expr="//body" position="attributes">
|
||||
<attribute name="style">padding-top: 51px;</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//body/*[1]" position="before">
|
||||
<xpath expr="//body" position="inside">
|
||||
<div id="website-top-navbar-placeholder" class="navbar navbar-inverse navbar-fixed-top hidden-xs">
|
||||
<div class="navbar-header">
|
||||
<form class="navbar-form navbar-left">
|
||||
|
|
Loading…
Reference in New Issue