[MERGE] forward port of branch saas-6 up to df95b1f

The changes in `l10n_es` [1] have been ignored. They will be ported to
the new accouting later.

[1] See 730890f369 and e3e5cfe82c
This commit is contained in:
Christophe Simonis
2016-06-14 19:22:21 +02:00
10 changed files with 116 additions and 57 deletions
+4 -2
View File
@@ -396,9 +396,11 @@ var DataImport = Widget.extend(ControlPanelMixin, {
var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) { var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) {
return $(el).select2('val') || false; return $(el).select2('val') || false;
}).get(); }).get();
var tracking_disable = 'tracking_disable' in kwargs ? kwargs.tracking_disable : !this.$('#oe_import_tracking').prop('checked')
delete kwargs.tracking_disable
kwargs.context = _.extend( kwargs.context = _.extend(
{}, this.parent_context, {}, this.parent_context,
{tracking_disable: !this.$('#oe_import_tracking').prop('checked')} {tracking_disable: tracking_disable}
); );
return this.Import.call('do', [this.id, fields, this.import_options()], kwargs) return this.Import.call('do', [this.id, fields, this.import_options()], kwargs)
.then(undefined, function (error, event) { .then(undefined, function (error, event) {
@@ -414,7 +416,7 @@ var DataImport = Widget.extend(ControlPanelMixin, {
}) ; }) ;
}, },
onvalidate: function () { onvalidate: function () {
return this.call_import({ dryrun: true }) return this.call_import({ dryrun: true, tracking_disable: true })
.done(this.proxy('validated')); .done(this.proxy('validated'));
}, },
onimport: function () { onimport: function () {
+6 -4
View File
@@ -609,21 +609,23 @@ class hr_payslip(osv.osv):
if context is None: if context is None:
context = {} context = {}
#delete old worked days lines #delete old worked days lines
worked_days_ids_to_remove=[]
old_worked_days_ids = ids and worked_days_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False old_worked_days_ids = ids and worked_days_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False
if old_worked_days_ids: if old_worked_days_ids:
worked_days_obj.unlink(cr, uid, old_worked_days_ids, context=context) worked_days_ids_to_remove = map(lambda x: (2, x,),old_worked_days_ids)
#delete old input lines #delete old input lines
input_line_ids_to_remove=[]
old_input_ids = ids and input_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False old_input_ids = ids and input_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False
if old_input_ids: if old_input_ids:
input_obj.unlink(cr, uid, old_input_ids, context=context) input_line_ids_to_remove = map(lambda x: (2,x,), old_input_ids)
#defaults #defaults
res = {'value':{ res = {'value':{
'line_ids':[], 'line_ids':[],
'input_line_ids': [], 'input_line_ids': input_line_ids_to_remove,
'worked_days_line_ids': [], 'worked_days_line_ids': worked_days_ids_to_remove,
#'details_by_salary_head':[], TODO put me back #'details_by_salary_head':[], TODO put me back
'name':'', 'name':'',
'contract_id': False, 'contract_id': False,
+64 -47
View File
@@ -22,6 +22,13 @@ except ImportError:
_logger.error('Odoo module hw_scanner depends on the evdev python module') _logger.error('Odoo module hw_scanner depends on the evdev python module')
evdev = None evdev = None
class ScannerDevice():
def __init__(self, path):
self.evdev = evdev.InputDevice(path)
self.evdev.grab()
self.barcode = []
self.shift = False
class Scanner(Thread): class Scanner(Thread):
def __init__(self): def __init__(self):
@@ -29,6 +36,7 @@ class Scanner(Thread):
self.lock = Lock() self.lock = Lock()
self.status = {'status':'connecting', 'messages':[]} self.status = {'status':'connecting', 'messages':[]}
self.input_dir = '/dev/input/by-id/' self.input_dir = '/dev/input/by-id/'
self.open_devices = []
self.barcodes = Queue() self.barcodes = Queue()
self.keymap = { self.keymap = {
2: ("1","!"), 2: ("1","!"),
@@ -109,25 +117,33 @@ class Scanner(Thread):
elif status == 'disconnected' and message: elif status == 'disconnected' and message:
_logger.info('Disconnected Barcode Scanner: %s', message) _logger.info('Disconnected Barcode Scanner: %s', message)
def get_device(self): def get_devices(self):
try: try:
if not evdev: if not evdev:
return None return None
devices = [ device for device in listdir(self.input_dir)]
keyboards = [ device for device in devices if ('kbd' in device) and ('keyboard' not in device.lower())] new_devices = [device for device in listdir(self.input_dir)
scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower())] if join(self.input_dir, device) not in [dev.evdev.fn for dev in self.open_devices]]
if len(scanners) > 0: scanners = [device for device in new_devices
self.set_status('connected','Connected to '+scanners[0]) if (('kbd' in device) and ('keyboard' not in device.lower()))
return evdev.InputDevice(join(self.input_dir,scanners[0])) or ('barcode' in device.lower()) or ('scanner' in device.lower())]
elif len(keyboards) > 0:
self.set_status('connected','Connected to '+keyboards[0]) for device in scanners:
return evdev.InputDevice(join(self.input_dir,keyboards[0])) _logger.debug('opening device %s', join(self.input_dir,device))
self.open_devices.append(ScannerDevice(join(self.input_dir,device)))
if self.open_devices:
self.set_status('connected','Connected to '+ str([dev.evdev.name for dev in self.open_devices]))
else: else:
self.set_status('disconnected','Barcode Scanner Not Found') self.set_status('disconnected','Barcode Scanner Not Found')
return None
return self.open_devices
except Exception as e: except Exception as e:
self.set_status('error',str(e)) self.set_status('error',str(e))
return None return []
def release_device(self, dev):
self.open_devices.remove(dev)
def get_barcode(self): def get_barcode(self):
""" Returns a scanned barcode. Will wait at most 5 seconds to get a barcode, and will """ Returns a scanned barcode. Will wait at most 5 seconds to get a barcode, and will
@@ -150,6 +166,11 @@ class Scanner(Thread):
self.lockedstart() self.lockedstart()
return self.status return self.status
def _get_open_device_by_fd(self, fd):
for dev in self.open_devices:
if dev.evdev.fd == fd:
return dev
def run(self): def run(self):
""" This will start a loop that catches all keyboard events, parse barcode """ This will start a loop that catches all keyboard events, parse barcode
sequences and put them on a timestamped queue that can be consumed by sequences and put them on a timestamped queue that can be consumed by
@@ -160,49 +181,45 @@ class Scanner(Thread):
barcode = [] barcode = []
shift = False shift = False
device = None devices = None
while True: # barcodes loop while True: # barcodes loop
if device: # ungrab device between barcodes and timeouts for plug & play devices = self.get_devices()
try:
device.ungrab()
except Exception as e:
device = None
self.set_status('error',str(e))
else:
time.sleep(5) # wait until a suitable device is plugged
device = self.get_device()
if not device:
continue
try: try:
device.grab()
shift = False
barcode = []
while True: # keycode loop while True: # keycode loop
r,w,x = select([device],[],[],5) r,w,x = select({dev.fd: dev for dev in [d.evdev for d in devices]},[],[],5)
if len(r) == 0: # timeout if len(r) == 0: # timeout
break break
events = device.read()
for event in events: for fd in r:
if event.type == evdev.ecodes.EV_KEY: device = self._get_open_device_by_fd(fd)
#_logger.debug('Evdev Keyboard event %s',evdev.categorize(event))
if event.value == 1: # keydown events if not evdev.util.is_device(device.evdev.fn):
if event.code in self.keymap: _logger.info('%s disconnected', str(device.evdev))
if shift: self.release_device(device)
barcode.append(self.keymap[event.code][1]) break
else:
barcode.append(self.keymap[event.code][0]) events = device.evdev.read()
elif event.code == 42 or event.code == 54: # SHIFT
shift = True for event in events:
elif event.code == 28: # ENTER, end of barcode if event.type == evdev.ecodes.EV_KEY:
self.barcodes.put( (time.time(),''.join(barcode)) ) # _logger.debug('Evdev Keyboard event %s',evdev.categorize(event))
barcode = [] if event.value == 1: # keydown events
elif event.value == 0: #keyup events if event.code in self.keymap:
if event.code == 42 or event.code == 54: # LEFT SHIFT if device.shift:
shift = False device.barcode.append(self.keymap[event.code][1])
else:
device.barcode.append(self.keymap[event.code][0])
elif event.code == 42 or event.code == 54: # SHIFT
device.shift = True
elif event.code == 28: # ENTER, end of barcode
_logger.debug('pushing barcode %s from %s', ''.join(device.barcode), str(device.evdev))
self.barcodes.put( (time.time(),''.join(device.barcode)) )
device.barcode = []
elif event.value == 0: #keyup events
if event.code == 42 or event.code == 54: # LEFT SHIFT
device.shift = False
except Exception as e: except Exception as e:
self.set_status('error',str(e)) self.set_status('error',str(e))
@@ -37,7 +37,7 @@ class fiche_paye_parser(report_sxw.rml_parse):
category_total = 0 category_total = 0
if cate_ids: if cate_ids:
line_ids = payslip_line.search(self.cr, self.uid, [('slip_id', '=', obj.id),('category_id.id', '=', cate_ids[0] )]) line_ids = payslip_line.search(self.cr, self.uid, [('slip_id', '=', obj.id), ('category_id', 'child_of', cate_ids)])
for line in payslip_line.browse(self.cr, self.uid, line_ids): for line in payslip_line.browse(self.cr, self.uid, line_ids):
category_total += line.total category_total += line.total
+1 -1
View File
@@ -136,7 +136,7 @@ class procurement_order(osv.osv):
unlink_ids.append(s['id']) unlink_ids.append(s['id'])
else: else:
raise UserError(_('Cannot delete Procurement Order(s) which are in %s state.') % s['state']) raise UserError(_('Cannot delete Procurement Order(s) which are in %s state.') % s['state'])
return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) return super(procurement_order, self).unlink(cr, uid, unlink_ids, context=context)
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
context = context or {} context = context or {}
+1
View File
@@ -217,6 +217,7 @@ class sale_order(osv.osv):
'website_description': line.website_description, 'website_description': line.website_description,
'state': 'draft', 'state': 'draft',
'customer_lead': self._get_customer_lead(cr, uid, line.product_id.product_tmpl_id), 'customer_lead': self._get_customer_lead(cr, uid, line.product_id.product_tmpl_id),
'delay': line.product_id.sale_delay
}) })
lines.append((0, 0, data)) lines.append((0, 0, data))
options = [] options = []
+11
View File
@@ -0,0 +1,11 @@
UAE, 07 May 2016
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Jordan Vrtanoski jordan.vrtanoski@gmail.com https://github.com/jordanvrtanoski
+12
View File
@@ -0,0 +1,12 @@
Sweden, 2016-06-09
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Patrik Lermon patrik.lermon@gmail.com https://github.com/kler
+11
View File
@@ -0,0 +1,11 @@
India, 2016/06/08
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Shelton Freddy sheltonfreddy141@gmail.com https://github.com/sheltonfreddy141
+5 -2
View File
@@ -140,8 +140,11 @@ def local_redirect(path, query=None, keep_hash=False, forward_debug=True, code=3
url = path url = path
if not query: if not query:
query = {} query = {}
if forward_debug and request and request.debug: if request and request.debug:
query['debug'] = None if forward_debug:
query['debug'] = ''
else:
query['debug'] = None
if query: if query:
url += '?' + werkzeug.url_encode(query) url += '?' + werkzeug.url_encode(query)
if keep_hash: if keep_hash: