diff --git a/addons/point_of_sale/wizard/pos_payment.py b/addons/point_of_sale/wizard/pos_payment.py index 02223153290..9ce9c2f4c87 100644 --- a/addons/point_of_sale/wizard/pos_payment.py +++ b/addons/point_of_sale/wizard/pos_payment.py @@ -124,7 +124,7 @@ class pos_make_payment(osv.osv_memory): } _defaults = { 'journal_id' : _default_journal, - 'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'), + 'payment_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'amount': _default_amount, } diff --git a/addons/project_timesheet/project_timesheet.py b/addons/project_timesheet/project_timesheet.py index 767cb4893b5..31a396369e2 100644 --- a/addons/project_timesheet/project_timesheet.py +++ b/addons/project_timesheet/project_timesheet.py @@ -198,7 +198,8 @@ class project_work(osv.osv): if amount_unit and 'amount' in amount_unit.get('value',{}): vals_line['amount'] = amount_unit['value']['amount'] - self.pool.get('hr.analytic.timesheet').write(cr, uid, [line_id.id], vals_line, context=context) + if vals_line: + self.pool.get('hr.analytic.timesheet').write(cr, uid, [line_id.id], vals_line, context=context) return super(project_work,self).write(cr, uid, ids, vals, context) diff --git a/addons/report_webkit/webkit_report.py b/addons/report_webkit/webkit_report.py index c442ea32549..53fe353f898 100644 --- a/addons/report_webkit/webkit_report.py +++ b/addons/report_webkit/webkit_report.py @@ -37,6 +37,7 @@ from openerp import report import tempfile import time import logging +from functools import partial from report_helper import WebKitHelper import openerp @@ -119,7 +120,6 @@ class WebKitParser(report_sxw): """ def __init__(self, name, table, rml=False, parser=rml_parse, header=True, store=False, register=True): - self.parser_instance = False self.localcontext = {} report_sxw.__init__(self, name, table, rml, parser, header, store, register=register) @@ -230,16 +230,16 @@ class WebKitParser(report_sxw): _logger.error('cannot remove file %s: %s', f_to_del, exc) return pdf - def translate_call(self, src): + def translate_call(self, parser_instance, src): """Translate String.""" ir_translation = self.pool['ir.translation'] name = self.tmpl and 'addons/' + self.tmpl or None - res = ir_translation._get_source(self.parser_instance.cr, self.parser_instance.uid, - name, 'report', self.parser_instance.localcontext.get('lang', 'en_US'), src) + res = ir_translation._get_source(parser_instance.cr, parser_instance.uid, + name, 'report', parser_instance.localcontext.get('lang', 'en_US'), src) if res == src: # no translation defined, fallback on None (backward compatibility) - res = ir_translation._get_source(self.parser_instance.cr, self.parser_instance.uid, - None, 'report', self.parser_instance.localcontext.get('lang', 'en_US'), src) + res = ir_translation._get_source(parser_instance.cr, parser_instance.uid, + None, 'report', parser_instance.localcontext.get('lang', 'en_US'), src) if not res : return src return res @@ -264,14 +264,14 @@ class WebKitParser(report_sxw): if report_xml.report_type != 'webkit': return super(WebKitParser,self).create_single_pdf(cursor, uid, ids, data, report_xml, context=context) - self.parser_instance = self.parser(cursor, - uid, - self.name2, - context=context) + parser_instance = self.parser(cursor, + uid, + self.name2, + context=context) self.pool = pool objs = self.getObjects(cursor, uid, ids, context) - self.parser_instance.set_context(objs, data, ids, report_xml.report_type) + parser_instance.set_context(objs, data, ids, report_xml.report_type) template = False @@ -299,21 +299,22 @@ class WebKitParser(report_sxw): if not css : css = '' + translate_call = partial(self.translate_call, parser_instance) body_mako_tpl = mako_template(template) helper = WebKitHelper(cursor, uid, report_xml.id, context) - self.parser_instance.localcontext['helper'] = helper - self.parser_instance.localcontext['css'] = css - self.parser_instance.localcontext['_'] = self.translate_call + parser_instance.localcontext['helper'] = helper + parser_instance.localcontext['css'] = css + parser_instance.localcontext['_'] = translate_call # apply extender functions additional = {} if xml_id in _extender_functions: for fct in _extender_functions[xml_id]: - fct(pool, cr, uid, self.parser_instance.localcontext, context) + fct(pool, cr, uid, parser_instance.localcontext, context) if report_xml.precise_mode: - ctx = dict(self.parser_instance.localcontext) - for obj in self.parser_instance.localcontext['objects']: + ctx = dict(parser_instance.localcontext) + for obj in parser_instance.localcontext['objects']: ctx['objects'] = [obj] try : html = body_mako_tpl.render(dict(ctx)) @@ -324,7 +325,7 @@ class WebKitParser(report_sxw): raise except_osv(_('Webkit render!'), msg) else: try : - html = body_mako_tpl.render(dict(self.parser_instance.localcontext)) + html = body_mako_tpl.render(dict(parser_instance.localcontext)) htmls.append(html) except Exception, e: msg = u"%s" % e @@ -332,22 +333,21 @@ class WebKitParser(report_sxw): raise except_osv(_('Webkit render!'), msg) head_mako_tpl = mako_template(header) try : - head = head_mako_tpl.render(dict(self.parser_instance.localcontext, _debug=False)) + head = head_mako_tpl.render(dict(parser_instance.localcontext, _debug=False)) except Exception, e: raise except_osv(_('Webkit render!'), u"%s" % e) foot = False if footer : foot_mako_tpl = mako_template(footer) try : - foot = foot_mako_tpl.render(dict({}, - **self.parser_instance.localcontext)) + foot = foot_mako_tpl.render(dict(parser_instance.localcontext)) except Exception, e: msg = u"%s" % e _logger.error(msg) raise except_osv(_('Webkit render!'), msg) if report_xml.webkit_debug : try : - deb = head_mako_tpl.render(dict(self.parser_instance.localcontext, _debug=tools.ustr("\n".join(htmls)))) + deb = head_mako_tpl.render(dict(parser_instance.localcontext, _debug=tools.ustr("\n".join(htmls)))) except Exception, e: msg = u"%s" % e _logger.error(msg) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index c59fbc31da1..384bb3d362e 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1126,13 +1126,13 @@ class stock_picking(osv.osv): if not inv_type: inv_type = self._get_invoice_type(picking) + invoice_vals = self._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context) if group and partner.id in invoices_group: invoice_id = invoices_group[partner.id] invoice = invoice_obj.browse(cr, uid, invoice_id) invoice_vals_group = self._prepare_invoice_group(cr, uid, picking, partner, invoice, context=context) invoice_obj.write(cr, uid, [invoice_id], invoice_vals_group, context=context) else: - invoice_vals = self._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context) invoice_id = invoice_obj.create(cr, uid, invoice_vals, context=context) invoices_group[partner.id] = invoice_id res[picking.id] = invoice_id @@ -2188,12 +2188,12 @@ class stock_move(osv.osv): done.append(move.id) pickings[move.picking_id.id] = 1 r = res.pop(0) - product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, ids, move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty'] + product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, [move.id], move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty'] cr.execute('update stock_move set location_id=%s, product_qty=%s, product_uos_qty=%s where id=%s', (r[1], r[0],product_uos_qty, move.id)) while res: r = res.pop(0) - product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, ids, move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty'] + product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, [move.id], move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty'] move_id = self.copy(cr, uid, move.id, {'product_uos_qty': product_uos_qty, 'product_qty': r[0], 'location_id': r[1]}) done.append(move_id) if done: diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 38eb78e6ad8..b645db41eaa 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4572,7 +4572,8 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in pop.select_element( this.model, { - title: _t("Add: ") + this.m2m_field.string + title: _t("Add: ") + this.m2m_field.string, + no_create: this.m2m_field.options.no_create, }, new instance.web.CompoundDomain(this.m2m_field.build_domain(), ["!", ["id", "in", this.m2m_field.dataset.ids]]), this.m2m_field.build_context() diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index bda1a2b8fc3..1fa1c544845 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1418,8 +1418,9 @@ + - or Cancel + or Cancel diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 4c53ed8ec8d..6090f52dbf6 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -93,6 +93,9 @@ .openerp .oe_kanban_view .oe_kanban_groups { height: inherit; } +.openerp .oe_kanban_view .oe_kanban_groups_records { + height: 100%; +} .openerp .oe_kanban_view.oe_kanban_grouped_by_m2o .oe_kanban_group_title { cursor: move; } @@ -160,10 +163,7 @@ padding: 0px; background: white; } -.openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_column_cards { - height: 100%; -} -.openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_column_cards { +.openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_column, .openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_column_cards { height: 100%; } .openerp .oe_kanban_view .oe_kanban_aggregates { diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index 77533c1182e..8d2174bc22e 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -119,6 +119,8 @@ // KanbanGroups {{{ .oe_kanban_groups height: inherit + .oe_kanban_groups_records + height: 100% &.oe_kanban_grouped_by_m2o .oe_kanban_group_title cursor: move .oe_kanban_header @@ -178,9 +180,9 @@ .oe_kanban_column padding: 0px background: #ffffff - - .oe_kanban_column, .oe_kanban_column_cards - height: 100% + &.oe_kanban_grouped + .oe_kanban_column, .oe_kanban_column_cards + height: 100% .oe_kanban_aggregates padding: 0 margin: 0px diff --git a/openerp/addons/base/ir/ir_cron.py b/openerp/addons/base/ir/ir_cron.py index 60a69cd6b38..e0f6e38b5ba 100644 --- a/openerp/addons/base/ir/ir_cron.py +++ b/openerp/addons/base/ir/ir_cron.py @@ -225,12 +225,21 @@ class ir_cron(osv.osv): lock_cr = db.cursor() try: # Try to grab an exclusive lock on the job row from within the task transaction + # Restrict to the same conditions as for the search since the job may have already + # been run by an other thread when cron is running in multi thread lock_cr.execute("""SELECT * FROM ir_cron - WHERE id=%s + WHERE numbercall != 0 + AND active + AND nextcall <= (now() at time zone 'UTC') + AND id=%s FOR UPDATE NOWAIT""", (job['id'],), log_exceptions=False) + locked_job = lock_cr.fetchone() + if not locked_job: + _logger.debug("Job `%s` already executed by another process/thread. skipping it", job['name']) + continue # Got the lock on the job row, run its code _logger.debug('Starting job `%s`.', job['name']) job_cr = db.cursor() diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 442dc0ce741..3101f52f2e0 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -1141,13 +1141,20 @@ class ir_model_data(osv.osv): # Remove non-model records first, then model fields, and finish with models unlink_if_refcount((model, res_id) for model, res_id in to_unlink - if model not in ('ir.model','ir.model.fields')) + if model not in ('ir.model','ir.model.fields','ir.model.constraint')) + unlink_if_refcount((model, res_id) for model, res_id in to_unlink + if model == 'ir.model.constraint') + + ir_module_module = self.pool['ir.module.module'] + ir_model_constraint = self.pool['ir.model.constraint'] + modules_to_remove_ids = ir_module_module.search(cr, uid, [('name', 'in', modules_to_remove)], context=context) + constraint_ids = ir_model_constraint.search(cr, uid, [('module', 'in', modules_to_remove_ids)], context=context) + ir_model_constraint._module_data_uninstall(cr, uid, constraint_ids, context) + unlink_if_refcount((model, res_id) for model, res_id in to_unlink if model == 'ir.model.fields') ir_model_relation = self.pool['ir.model.relation'] - ir_module_module = self.pool['ir.module.module'] - modules_to_remove_ids = ir_module_module.search(cr, uid, [('name', 'in', modules_to_remove)]) relation_ids = ir_model_relation.search(cr, uid, [('module', 'in', modules_to_remove_ids)]) ir_model_relation._module_data_uninstall(cr, uid, relation_ids, context) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index db93c12da22..45a4f086166 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -435,11 +435,7 @@ class module(osv.osv): including the deletion of all database structures created by the module: tables, columns, constraints, etc.""" ir_model_data = self.pool.get('ir.model.data') - ir_model_constraint = self.pool.get('ir.model.constraint') modules_to_remove = [m.name for m in self.browse(cr, uid, ids, context)] - modules_to_remove_ids = [m.id for m in self.browse(cr, uid, ids, context)] - constraint_ids = ir_model_constraint.search(cr, uid, [('module', 'in', modules_to_remove_ids)]) - ir_model_constraint._module_data_uninstall(cr, uid, constraint_ids, context) ir_model_data._module_data_uninstall(cr, uid, modules_to_remove, context) self.write(cr, uid, ids, {'state': 'uninstalled'}) return True diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index f60e83726c4..8f5ea710433 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1219,9 +1219,17 @@ class function(_column): return result def get(self, cr, obj, ids, name, uid=False, context=None, values=None): - result = self._fnct(obj, cr, uid, ids, name, self._arg, context) + multi = self._multi + # if we already have a value, don't recompute it. + # This happen if case of stored many2one fields + if values and not multi and name in values[0]: + result = {v['id']: v[name] for v in values} + elif values and multi and all(n in values[0] for n in name): + result = {v['id']: dict({n: v[n]} for n in name) for v in values} + else: + result = self._fnct(obj, cr, uid, ids, name, self._arg, context) for id in ids: - if self._multi and id in result: + if multi and id in result: for field, value in result[id].iteritems(): if value: result[id][field] = self.postprocess(cr, uid, obj, field, value, context) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 85558b5686b..5bd91704a65 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2769,7 +2769,7 @@ class BaseModel(object): ('numeric', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]), ('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]), ] - if f_pg_type == 'varchar' and f._type == 'char' and ((f.size is None and f_pg_size) or f_pg_size < f.size): + if f_pg_type == 'varchar' and f._type == 'char' and f_pg_size and (f.size is None or f_pg_size < f.size): try: with cr.savepoint(): cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" TYPE %s' % (self._table, k, pg_varchar(f.size)))