From 132f1ee986f844a38d22efaa0d5be42cdcd56e4e Mon Sep 17 00:00:00 2001 From: sve-odoo Date: Fri, 6 Jun 2014 08:45:02 +0200 Subject: [PATCH 1/8] [FIX] Account analytic plan line name.. ..should not be called plan itself. --- addons/account_analytic_plans/account_analytic_plans.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account_analytic_plans/account_analytic_plans.py b/addons/account_analytic_plans/account_analytic_plans.py index 23a309c1dda..aa9844105e6 100644 --- a/addons/account_analytic_plans/account_analytic_plans.py +++ b/addons/account_analytic_plans/account_analytic_plans.py @@ -81,7 +81,7 @@ class account_analytic_plan_line(osv.osv): _order = "sequence, id" _columns = { 'plan_id': fields.many2one('account.analytic.plan','Analytic Plan',required=True), - 'name': fields.char('Plan Name', size=64, required=True, select=True), + 'name': fields.char('Axis Name', size=64, required=True, select=True), 'sequence': fields.integer('Sequence'), 'root_analytic_id': fields.many2one('account.analytic.account', 'Root Account', help="Root account of this plan.", required=False), 'min_required': fields.float('Minimum Allowed (%)'), From 4105b5f0285821d8056c721b5fd50b9cae902988 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Sat, 7 Jun 2014 00:01:52 +0200 Subject: [PATCH 2/8] [ADD] module install/uninstall hooks. Since 4ec71c74d1dcec96d764fb42aab856cb32fb5321, migration scripts are not executed at module install anymore. As this behavior was missused as "init" scripts (see [1]), this commit re-add this possiblity via hooks. There are 3 hooks that can be declared in the manifest file: - pre_init_hook: called before module installation - post_init_hook: called after module installation - uninstall_hook: called before module uninstallation Like the "post_load" manifest option, the values for these hooks must be a string containing the name of a method available at the module root. The signatures of these functions are: - (cr) for pre_init_hook - (cr, registry) for post_init_hook and uninstall_hook [1] https://bugs.launchpad.net/openobject-server/+bug/1314680 --- openerp/modules/graph.py | 24 +++++++++++------------- openerp/modules/loading.py | 27 +++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/openerp/modules/graph.py b/openerp/modules/graph.py index 74f4e0db9ce..76a9f046dc6 100644 --- a/openerp/modules/graph.py +++ b/openerp/modules/graph.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2014 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -149,7 +149,14 @@ class Graph(dict): level += 1 -class Singleton(object): +class Node(object): + """ One module in the modules dependency graph. + + Node acts as a per-module singleton. A node is constructed via + Graph.add_module() or Graph.add_modules(). Some of its fields are from + ir_module_module (setted by Graph.update_from_db()). + + """ def __new__(cls, name, graph, info): if name in graph: inst = graph[name] @@ -160,22 +167,13 @@ class Singleton(object): graph[name] = inst return inst - -class Node(Singleton): - """ One module in the modules dependency graph. - - Node acts as a per-module singleton. A node is constructed via - Graph.add_module() or Graph.add_modules(). Some of its fields are from - ir_module_module (setted by Graph.update_from_db()). - - """ - def __init__(self, name, graph, info): self.graph = graph if not hasattr(self, 'children'): self.children = [] if not hasattr(self, 'depth'): self.depth = 0 + self.info = info or {} def add_child(self, name, info): node = Node(name, self.graph, info) @@ -189,7 +187,7 @@ class Node(Singleton): return node def __setattr__(self, name, value): - super(Singleton, self).__setattr__(name, value) + super(Node, self).__setattr__(name, value) if name in ('init', 'update', 'demo'): tools.config[name][self.name] = 1 for child in self.children: diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 2b507acc0bb..2b9fca6fca9 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -148,6 +148,13 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'pre') load_openerp_module(package.name) + new_install = package.installed_version is None + if new_install: + py_module = sys.modules['openerp.addons.%s' % (module_name,)] + pre_init = package.info.get('pre_init_hook') + if pre_init: + getattr(py_module, pre_init)(cr) + models = registry.load(cr, package) loaded_modules.append(package.name) @@ -181,6 +188,11 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'post') + if new_install: + post_init = package.info.get('post_init_hook') + if post_init: + getattr(py_module, post_init)(cr, registry) + registry._init_modules.add(package.name) # validate all the views at a whole registry['ir.ui.view']._validate_module_views(cr, SUPERUSER_ID, module_name) @@ -401,10 +413,17 @@ def load_modules(db, force_demo=False, status=None, update_module=False): if update_module: # Remove records referenced from ir_model_data for modules to be # removed (and removed the references from ir_model_data). - cr.execute("SELECT id FROM ir_module_module WHERE state=%s", ('to remove',)) - mod_ids_to_remove = [x[0] for x in cr.fetchall()] - if mod_ids_to_remove: - registry['ir.module.module'].module_uninstall(cr, SUPERUSER_ID, mod_ids_to_remove) + cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s", ('to remove',)) + modules_to_remove = dict(cr.fetchall()) + if modules_to_remove: + pkgs = reversed([p for p in graph if p.name in modules_to_remove]) + for pkg in pkgs: + uninstall_hook = pkg.info.get('uninstall_hook') + if uninstall_hook: + py_module = sys.modules['openerp.addons.%s' % (pkg.name,)] + getattr(py_module, uninstall_hook)(cr, registry) + + registry['ir.module.module'].module_uninstall(cr, SUPERUSER_ID, modules_to_remove.values()) # Recursive reload, should only happen once, because there should be no # modules to remove next time cr.commit() From 37bff3b62c5c98120cf7ed772a3964d09229675f Mon Sep 17 00:00:00 2001 From: fdesmottes Date: Tue, 3 Jun 2014 23:55:01 +0200 Subject: [PATCH 3/8] Update account_analytic_default.py Fix issue #270 : account_analytic_default doesn't work with company_id condition --- .../account_analytic_default.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/account_analytic_default/account_analytic_default.py b/addons/account_analytic_default/account_analytic_default.py index ac8698ae342..3d6f1b4ace3 100644 --- a/addons/account_analytic_default/account_analytic_default.py +++ b/addons/account_analytic_default/account_analytic_default.py @@ -39,7 +39,7 @@ class account_analytic_default(osv.osv): 'date_stop': fields.date('End Date', help="Default end date for this Analytic Account."), } - def account_get(self, cr, uid, product_id=None, partner_id=None, user_id=None, date=None, context=None): + def account_get(self, cr, uid, product_id=None, partner_id=None, company_id=None, user_id=None, date=None, context=None): domain = [] if product_id: domain += ['|', ('product_id', '=', product_id)] @@ -47,6 +47,9 @@ class account_analytic_default(osv.osv): if partner_id: domain += ['|', ('partner_id', '=', partner_id)] domain += [('partner_id', '=', False)] + if company_id: + domain += ['|', ('company_id', '=', company_id)] + domain += [('company_id', '=', False)] if user_id: domain += ['|',('user_id', '=', user_id)] domain += [('user_id','=', False)] @@ -59,6 +62,7 @@ class account_analytic_default(osv.osv): index = 0 if rec.product_id: index += 1 if rec.partner_id: index += 1 + if rec.company_id: index += 1 if rec.user_id: index += 1 if rec.date_start: index += 1 if rec.date_stop: index += 1 @@ -74,7 +78,10 @@ class account_invoice_line(osv.osv): def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None): res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id=currency_id, context=context, company_id=company_id) - rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context) + if context is None: + context = {} + company_id = company_id if company_id != None else context.get('company_id',False) + rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, company_id, uid, time.strftime('%Y-%m-%d'), context=context) if rec: res_prod['value'].update({'account_analytic_id': rec.analytic_id.id}) else: @@ -88,7 +95,7 @@ class stock_picking(osv.osv): def _get_account_analytic_invoice(self, cursor, user, picking, move_line): partner_id = picking.partner_id and picking.partner_id.id or False - rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id , user, time.strftime('%Y-%m-%d'), context={}) + rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id, company_id, user, time.strftime('%Y-%m-%d'), context={}) if rec: return rec.analytic_id.id @@ -109,7 +116,7 @@ class sale_order_line(osv.osv): anal_def_obj = self.pool.get('account.analytic.default') for line in inv_line_obj.browse(cr, uid, create_ids, context=context): - rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, time.strftime('%Y-%m-%d'), context=context) + rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, False, time.strftime('%Y-%m-%d'), context=context) if rec: inv_line_obj.write(cr, uid, [line.id], {'account_analytic_id': rec.analytic_id.id}, context=context) From 46bf4db8843b88ca6034ffbc92604978efd81dcd Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 10 Jun 2014 14:31:36 +0200 Subject: [PATCH 4/8] [FIX] small fixes - set the company_id parameters at the end of the method to avoid incompatibities with calls in account_analytic_plans - instead of checking the context, actually pass the company_id argument in the product_change from uos_id_change --- addons/account/account_invoice.py | 2 +- .../account_analytic_default.py | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 9d4654c9eee..eb43830f8f6 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1546,7 +1546,7 @@ class account_invoice_line(osv.osv): context = dict(context) context.update({'company_id': company_id}) warning = {} - res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context) + res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context, company_id=company_id) if not uom: res['value']['price_unit'] = 0.0 if product and uom: diff --git a/addons/account_analytic_default/account_analytic_default.py b/addons/account_analytic_default/account_analytic_default.py index 3d6f1b4ace3..e0e8f7292ef 100644 --- a/addons/account_analytic_default/account_analytic_default.py +++ b/addons/account_analytic_default/account_analytic_default.py @@ -39,7 +39,7 @@ class account_analytic_default(osv.osv): 'date_stop': fields.date('End Date', help="Default end date for this Analytic Account."), } - def account_get(self, cr, uid, product_id=None, partner_id=None, company_id=None, user_id=None, date=None, context=None): + def account_get(self, cr, uid, product_id=None, partner_id=None, user_id=None, date=None, company_id=None, context=None): domain = [] if product_id: domain += ['|', ('product_id', '=', product_id)] @@ -78,10 +78,7 @@ class account_invoice_line(osv.osv): def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None): res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id=currency_id, context=context, company_id=company_id) - if context is None: - context = {} - company_id = company_id if company_id != None else context.get('company_id',False) - rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, company_id, uid, time.strftime('%Y-%m-%d'), context=context) + rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), company_id=company_id, context=context) if rec: res_prod['value'].update({'account_analytic_id': rec.analytic_id.id}) else: @@ -95,7 +92,7 @@ class stock_picking(osv.osv): def _get_account_analytic_invoice(self, cursor, user, picking, move_line): partner_id = picking.partner_id and picking.partner_id.id or False - rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id, company_id, user, time.strftime('%Y-%m-%d'), context={}) + rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id, user, time.strftime('%Y-%m-%d')) if rec: return rec.analytic_id.id @@ -116,7 +113,7 @@ class sale_order_line(osv.osv): anal_def_obj = self.pool.get('account.analytic.default') for line in inv_line_obj.browse(cr, uid, create_ids, context=context): - rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, False, time.strftime('%Y-%m-%d'), context=context) + rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, time.strftime('%Y-%m-%d'), context=context) if rec: inv_line_obj.write(cr, uid, [line.id], {'account_analytic_id': rec.analytic_id.id}, context=context) From e932ecb9df6988361f91d93a611a7b907c2b07d3 Mon Sep 17 00:00:00 2001 From: Franck Bret Date: Wed, 11 Jun 2014 10:40:31 +0200 Subject: [PATCH 5/8] Use encodeURIComponent in place of encodeURI for website new page title, in order to escape special chars like question mark --- addons/website/static/src/js/website.editor.newpage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website/static/src/js/website.editor.newpage.js b/addons/website/static/src/js/website.editor.newpage.js index 5fa5df7a750..eba3784a42f 100644 --- a/addons/website/static/src/js/website.editor.newpage.js +++ b/addons/website/static/src/js/website.editor.newpage.js @@ -47,7 +47,7 @@ } }).then(function (val, field, $dialog) { if (val) { - var url = '/website/add/' + encodeURI(val); + var url = '/website/add/' + encodeURIComponent(val); if ($dialog.find('input[type="checkbox"]').is(':checked')) url +="?add_menu=1"; document.location = url; } From e5379bc1a050883452fae1e71093467042e9b64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 11 Jun 2014 10:40:39 +0200 Subject: [PATCH 6/8] [IMP] project: task: added reviewer_id field, linking towards a res.users, that is the reviewer of the task. This field is automatically tracked, using a small update of the get_auto_subscribe_fields method that is weirdly implemented. --- addons/hr/hr.py | 4 +++- addons/mail/mail_thread.py | 4 +++- addons/project/project.py | 7 +++++++ addons/project/project_view.xml | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/addons/hr/hr.py b/addons/hr/hr.py index 5bb172eb082..85366adfe3b 100644 --- a/addons/hr/hr.py +++ b/addons/hr/hr.py @@ -349,10 +349,12 @@ class hr_employee(osv.osv): else: return super(hr_employee, self).get_suggested_thread(cr, uid, removed_suggested_threads, context) - def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None): + def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=None, context=None): """ Overwrite of the original method to always follow user_id field, even when not track_visibility so that a user will follow it's employee """ + if auto_follow_fields is None: + auto_follow_fields = ['user_id'] user_field_lst = [] for name, column_info in self._all_columns.items(): if name in auto_follow_fields and name in updated_fields and column_info.column._obj == 'res.users': diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 55a566880b8..dc2b98fdc93 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1699,7 +1699,7 @@ class mail_thread(osv.AbstractModel): ], context=context) return fol_obj.unlink(cr, SUPERUSER_ID, fol_ids, context=context) - def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None): + def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=None, context=None): """ Returns the list of relational fields linking to res.users that should trigger an auto subscribe. The default list checks for the fields - called 'user_id' @@ -1710,6 +1710,8 @@ class mail_thread(osv.AbstractModel): Override this method if a custom behavior is needed about fields that automatically subscribe users. """ + if auto_follow_fields is None: + auto_follow_fields = ['user_id'] user_field_lst = [] for name, column_info in self._all_columns.items(): if name in auto_follow_fields and name in updated_fields and getattr(column_info.column, 'track_visibility', False) and column_info.column._obj == 'res.users': diff --git a/addons/project/project.py b/addons/project/project.py index d98b9b03e94..a9c487be244 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -782,6 +782,7 @@ class task(osv.osv): 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), + 'reviewer_id': fields.many2one('res.users', 'Reviewer', select=True, track_visibility='onchange'), 'user_id': fields.many2one('res.users', 'Assigned to', select=True, track_visibility='onchange'), 'delegated_user_id': fields.related('child_ids', 'user_id', type='many2one', relation='res.users', string='Delegated To'), 'partner_id': fields.many2one('res.partner', 'Customer'), @@ -801,6 +802,7 @@ class task(osv.osv): 'progress': 0, 'sequence': 10, 'active': True, + 'reviewer_id': lambda obj, cr, uid, ctx=None: uid, 'user_id': lambda obj, cr, uid, ctx=None: uid, 'company_id': lambda self, cr, uid, ctx=None: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=ctx), 'partner_id': lambda self, cr, uid, ctx=None: self._get_default_partner(cr, uid, context=ctx), @@ -1090,6 +1092,11 @@ class task(osv.osv): # Mail gateway # --------------------------------------------------- + def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=None, context=None): + if auto_follow_fields is None: + auto_follow_fields = ['user_id', 'reviewer_id'] + return super(task, self)._message_get_auto_subscribe_fields(cr, uid, updated_fields, auto_follow_fields, context=context) + def message_get_reply_to(self, cr, uid, ids, context=None): """ Override to get the reply_to of the parent project. """ return [task.project_id.message_get_reply_to()[0] if task.project_id else False diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index b6a839edcf6..693e1b47f13 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -29,9 +29,11 @@ help="Show only tasks having a deadline"/> + + @@ -389,6 +391,9 @@ + From 6ed133d86dd0d12e722f21e15a3c398ce82ed1d8 Mon Sep 17 00:00:00 2001 From: sve-odoo Date: Wed, 11 Jun 2014 11:16:17 +0200 Subject: [PATCH 7/8] [IMP] Add filters in ir.model.fields search view. Add "Custom" and "Base" filters in ir.model.fields search view. --- openerp/addons/base/ir/ir_model_view.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openerp/addons/base/ir/ir_model_view.xml b/openerp/addons/base/ir/ir_model_view.xml index fb68df9b5ff..cd5ab9d2342 100644 --- a/openerp/addons/base/ir/ir_model_view.xml +++ b/openerp/addons/base/ir/ir_model_view.xml @@ -214,6 +214,13 @@ string="Readonly" domain="[('readonly', '=', True)]"/> + + + From caf661dbbb4817bac449d36eb31ab1359f900837 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 11 Jun 2014 14:53:59 +0200 Subject: [PATCH 8/8] Add runbot badge on README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a33e4c89e48..9e77856701a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + + Odoo ----