diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index d489bc49474..496a25bc9ab 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -396,9 +396,11 @@ var DataImport = Widget.extend(ControlPanelMixin, { var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) { return $(el).select2('val') || false; }).get(); + var tracking_disable = 'tracking_disable' in kwargs ? kwargs.tracking_disable : !this.$('#oe_import_tracking').prop('checked') + delete kwargs.tracking_disable kwargs.context = _.extend( {}, 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) .then(undefined, function (error, event) { @@ -414,7 +416,7 @@ var DataImport = Widget.extend(ControlPanelMixin, { }) ; }, onvalidate: function () { - return this.call_import({ dryrun: true }) + return this.call_import({ dryrun: true, tracking_disable: true }) .done(this.proxy('validated')); }, onimport: function () { diff --git a/addons/hr_payroll/hr_payroll.py b/addons/hr_payroll/hr_payroll.py index f7d6cefe4c8..0b612cac04c 100644 --- a/addons/hr_payroll/hr_payroll.py +++ b/addons/hr_payroll/hr_payroll.py @@ -609,21 +609,23 @@ class hr_payslip(osv.osv): if context is None: context = {} #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 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 + input_line_ids_to_remove=[] old_input_ids = ids and input_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False 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 res = {'value':{ 'line_ids':[], - 'input_line_ids': [], - 'worked_days_line_ids': [], + 'input_line_ids': input_line_ids_to_remove, + 'worked_days_line_ids': worked_days_ids_to_remove, #'details_by_salary_head':[], TODO put me back 'name':'', 'contract_id': False, diff --git a/addons/hw_scanner/controllers/main.py b/addons/hw_scanner/controllers/main.py index 8e5e8f6af18..ad0f47a2cda 100644 --- a/addons/hw_scanner/controllers/main.py +++ b/addons/hw_scanner/controllers/main.py @@ -22,6 +22,13 @@ except ImportError: _logger.error('Odoo module hw_scanner depends on the evdev python module') evdev = None +class ScannerDevice(): + def __init__(self, path): + self.evdev = evdev.InputDevice(path) + self.evdev.grab() + + self.barcode = [] + self.shift = False class Scanner(Thread): def __init__(self): @@ -29,6 +36,7 @@ class Scanner(Thread): self.lock = Lock() self.status = {'status':'connecting', 'messages':[]} self.input_dir = '/dev/input/by-id/' + self.open_devices = [] self.barcodes = Queue() self.keymap = { 2: ("1","!"), @@ -109,25 +117,33 @@ class Scanner(Thread): elif status == 'disconnected' and message: _logger.info('Disconnected Barcode Scanner: %s', message) - def get_device(self): + def get_devices(self): try: if not evdev: 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())] - 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])) + + new_devices = [device for device in listdir(self.input_dir) + if join(self.input_dir, device) not in [dev.evdev.fn for dev in self.open_devices]] + scanners = [device for device in new_devices + if (('kbd' in device) and ('keyboard' not in device.lower())) + or ('barcode' in device.lower()) or ('scanner' in device.lower())] + + for device in scanners: + _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: self.set_status('disconnected','Barcode Scanner Not Found') - return None + + return self.open_devices except Exception as e: self.set_status('error',str(e)) - return None + return [] + + def release_device(self, dev): + self.open_devices.remove(dev) def get_barcode(self): """ 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() 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): """ 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 @@ -160,49 +181,45 @@ class Scanner(Thread): barcode = [] shift = False - device = None + devices = None while True: # barcodes loop - if device: # ungrab device between barcodes and timeouts for plug & play - 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 + devices = self.get_devices() try: - device.grab() - shift = False - barcode = [] - 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 break - events = device.read() - for event in events: - if event.type == evdev.ecodes.EV_KEY: - #_logger.debug('Evdev Keyboard event %s',evdev.categorize(event)) - if event.value == 1: # keydown events - if event.code in self.keymap: - if shift: - barcode.append(self.keymap[event.code][1]) - else: - barcode.append(self.keymap[event.code][0]) - elif event.code == 42 or event.code == 54: # SHIFT - shift = True - elif event.code == 28: # ENTER, end of barcode - self.barcodes.put( (time.time(),''.join(barcode)) ) - barcode = [] - elif event.value == 0: #keyup events - if event.code == 42 or event.code == 54: # LEFT SHIFT - shift = False + for fd in r: + device = self._get_open_device_by_fd(fd) + + if not evdev.util.is_device(device.evdev.fn): + _logger.info('%s disconnected', str(device.evdev)) + self.release_device(device) + break + + events = device.evdev.read() + + for event in events: + if event.type == evdev.ecodes.EV_KEY: + # _logger.debug('Evdev Keyboard event %s',evdev.categorize(event)) + if event.value == 1: # keydown events + if event.code in self.keymap: + if device.shift: + 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: self.set_status('error',str(e)) diff --git a/addons/l10n_fr_hr_payroll/report/fiche_paye.py b/addons/l10n_fr_hr_payroll/report/fiche_paye.py index 77402772ad7..4b39afb9544 100644 --- a/addons/l10n_fr_hr_payroll/report/fiche_paye.py +++ b/addons/l10n_fr_hr_payroll/report/fiche_paye.py @@ -37,7 +37,7 @@ class fiche_paye_parser(report_sxw.rml_parse): category_total = 0 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): category_total += line.total diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 6c53bd5d545..f403565f3a0 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -136,7 +136,7 @@ class procurement_order(osv.osv): unlink_ids.append(s['id']) else: 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): context = context or {} diff --git a/addons/website_quote/models/order.py b/addons/website_quote/models/order.py index 8af74a76149..188045831f5 100644 --- a/addons/website_quote/models/order.py +++ b/addons/website_quote/models/order.py @@ -217,6 +217,7 @@ class sale_order(osv.osv): 'website_description': line.website_description, 'state': 'draft', '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)) options = [] diff --git a/doc/cla/individual/jordanvrtanoski.md b/doc/cla/individual/jordanvrtanoski.md new file mode 100644 index 00000000000..670933470a9 --- /dev/null +++ b/doc/cla/individual/jordanvrtanoski.md @@ -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 diff --git a/doc/cla/individual/kler.md b/doc/cla/individual/kler.md new file mode 100644 index 00000000000..54b72a9ca23 --- /dev/null +++ b/doc/cla/individual/kler.md @@ -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 + diff --git a/doc/cla/individual/sheltonfreddy.md b/doc/cla/individual/sheltonfreddy.md new file mode 100644 index 00000000000..d333e90fb24 --- /dev/null +++ b/doc/cla/individual/sheltonfreddy.md @@ -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 diff --git a/openerp/http.py b/openerp/http.py index 07100e7444c..73fd66fc087 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -140,8 +140,11 @@ def local_redirect(path, query=None, keep_hash=False, forward_debug=True, code=3 url = path if not query: query = {} - if forward_debug and request and request.debug: - query['debug'] = None + if request and request.debug: + if forward_debug: + query['debug'] = '' + else: + query['debug'] = None if query: url += '?' + werkzeug.url_encode(query) if keep_hash: