diff --git a/openerp/addons/base/base.sql b/openerp/addons/base/base.sql index eb9966bddcd..f2cb77709ed 100644 --- a/openerp/addons/base/base.sql +++ b/openerp/addons/base/base.sql @@ -347,6 +347,39 @@ CREATE TABLE ir_model_data ( res_id integer, primary key(id) ); +-- Records foreign keys and constraints installed by a module (so they can be +-- removed when the module is uninstalled): +-- - for a foreign key: type is 'f', +-- - for a constraint: type is 'u' (this is the convention PostgreSQL uses). +CREATE TABLE ir_model_constraint ( + id serial NOT NULL, + create_uid integer, + create_date timestamp without time zone, + write_date timestamp without time zone, + write_uid integer, + date_init timestamp without time zone, + date_update timestamp without time zone, + module integer NOT NULL references ir_module_module on delete restrict, + model integer NOT NULL references ir_model on delete restrict, + type character varying(1) NOT NULL, + name character varying(128) NOT NULL +); + +-- Records relation tables (i.e. implementing many2many) installed by a module +-- (so they can be removed when the module is uninstalled). +CREATE TABLE ir_model_relation ( + id serial NOT NULL, + create_uid integer, + create_date timestamp without time zone, + write_date timestamp without time zone, + write_uid integer, + date_init timestamp without time zone, + date_update timestamp without time zone, + module integer NOT NULL references ir_module_module on delete restrict, + model integer NOT NULL references ir_model on delete restrict, + name character varying(128) NOT NULL +); + --------------------------------- -- Users --------------------------------- diff --git a/openerp/addons/base/base_menu.xml b/openerp/addons/base/base_menu.xml index abba27b7ed7..90c7dd348e6 100644 --- a/openerp/addons/base/base_menu.xml +++ b/openerp/addons/base/base_menu.xml @@ -1,23 +1,22 @@ - + - + - + - - - + + + + - - diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index 83c982e76b9..b4d28052ba8 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -467,7 +467,7 @@ msgstr "" #. module: base #: field:res.bank,email:0 #: field:res.partner.address,email:0 -msgid "E-Mail" +msgid "Email msgstr "" #. module: base @@ -544,16 +544,16 @@ msgid "\n" "==========================================================================\n" "\n" "You can define your multiple levels of recall through the menu:\n" -" Accounting/Configuration/Miscellaneous/Follow-Ups\n" +" Accounting/Configuration/Miscellaneous/Follow-ups\n" "\n" "Once it is defined, you can automatically print recalls every day through simply clicking on the menu:\n" -" Accounting/Periodical Processing/Billing/Send followups\n" +" Accounting/Periodical Processing/Billing/Send follow-ups\n" "\n" "It will generate a PDF with all the letters according to the the\n" "different levels of recall defined. You can define different policies\n" "for different companies. You can also send mail to the customer.\n" "\n" -"Note that if you want to check the followup level for a given partner/account entry, you can do from in the menu:\n" +"Note that if you want to check the follow-up level for a given partner/account entry, you can do from in the menu:\n" " Accounting/Reporting/Generic Reporting/Partners/Follow-ups Sent\n" "\n" "" @@ -7592,7 +7592,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_email_template -msgid "E-Mail Templates" +msgid "Email Templates msgstr "" #. module: base @@ -9455,7 +9455,7 @@ msgstr "" #. module: base #: field:res.partner,email:0 -msgid "E-mail" +msgid "Email msgstr "" #. module: base @@ -12688,7 +12688,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_account_followup -msgid "Followup Management" +msgid "Follow-up Management" msgstr "" #. module: base diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index a2a4b999ed8..bc4f3eecfbf 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -20,6 +20,8 @@ ############################################################################## import ir_model +import ir_model_constraint +import ir_model_relation import ir_sequence import ir_needaction import ir_ui_menu diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 6d5da0fc47a..88843b207f9 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -328,7 +328,7 @@ - + @@ -1127,6 +1127,65 @@ + + ir.model.constraint.form + ir.model.constraint + form + +
+ + + + + + + + + +
+ + + ir.model.constraint.list + ir.model.constraint + tree + + + + + + + + + + + + ir.model.relation.form + ir.model.relation + form + +
+ + + + + + + + +
+ + + ir.model.relation.list + ir.model.relation + tree + + + + + + + + Models @@ -1156,6 +1215,24 @@ + + Model Constraints + ir.model.constraint + form + + + + + + ManyToMany Relations + ir.model.relation + form + + + + diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index fbe3f71e024..1d91ab823db 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -222,9 +222,10 @@ class act_window(osv.osv): help="Optional domain filtering of the destination data, as a Python expression"), 'context': fields.char('Context Value', size=250, required=True, help="Context dictionary as Python expression, empty by default (Default: {})"), - 'res_model': fields.char('Object', size=64, required=True, + 'res_id': fields.integer('Record ID', help="Database ID of record to open in form view, when ``view_mode`` is set to 'form' only"), + 'res_model': fields.char('Destination Model', size=64, required=True, help="Model name of the object to open in the view window"), - 'src_model': fields.char('Source Object', size=64, + 'src_model': fields.char('Source Model', size=64, help="Optional model name of the objects on which this action should be visible"), 'target': fields.selection([('current','Current Window'),('new','New Window'),('inline','Inline')], 'Target Window'), 'view_type': fields.selection((('tree','Tree'),('form','Form')), string='View Type', required=True, diff --git a/openerp/addons/base/ir/ir_config_parameter_view.xml b/openerp/addons/base/ir/ir_config_parameter_view.xml index 3df9b80551c..6b1c6c4f86e 100644 --- a/openerp/addons/base/ir/ir_config_parameter_view.xml +++ b/openerp/addons/base/ir/ir_config_parameter_view.xml @@ -40,7 +40,6 @@ - + diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index 04156411e48..6099c68a0fb 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -161,7 +161,7 @@ def encode_rfc2822_address_header(header_text): class ir_mail_server(osv.osv): - """Represents an SMTP server, able to send outgoing e-mails, with SSL and TLS capabilities.""" + """Represents an SMTP server, able to send outgoing emails, with SSL and TLS capabilities.""" _name = "ir.mail_server" _columns = { @@ -396,7 +396,7 @@ class ir_mail_server(osv.osv): MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] - assert smtp_from, "The Return-Path or From header is required for any outbound e-mail" + assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index b366d1dfb1c..beed30a2178 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -29,8 +29,7 @@ from openerp import netsvc, pooler, tools from openerp.tools.safe_eval import safe_eval as eval from openerp.tools import config from openerp.tools.translate import _ -from openerp.osv.orm import except_orm, browse_record, EXT_ID_PREFIX_FK, \ - EXT_ID_PREFIX_M2M_TABLE, EXT_ID_PREFIX_CONSTRAINT +from openerp.osv.orm import except_orm, browse_record _logger = logging.getLogger(__name__) @@ -864,7 +863,7 @@ class ir_model_data(osv.osv): cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name)) return True - def _module_data_uninstall(self, cr, uid, ids, context=None): + def _module_data_uninstall(self, cr, uid, modules_to_remove, context=None): """Deletes all the records referenced by the ir.model.data entries ``ids`` along with their corresponding database backed (including dropping tables, columns, FKs, etc, as long as there is no other @@ -875,6 +874,8 @@ class ir_model_data(osv.osv): This step is performed as part of the full uninstallation of a module. """ + ids = self.search(cr, uid, [('module', 'in', modules_to_remove)]) + if uid != 1 and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"): raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module'))) @@ -884,7 +885,6 @@ class ir_model_data(osv.osv): ids_set = set(ids) wkf_todo = [] to_unlink = [] - to_drop_table = [] ids.sort() ids.reverse() for data in self.browse(cr, uid, ids, context): @@ -893,42 +893,6 @@ class ir_model_data(osv.osv): model_obj = self.pool.get(model) name = tools.ustr(data.name) - if name.startswith(EXT_ID_PREFIX_FK) or name.startswith(EXT_ID_PREFIX_M2M_TABLE)\ - or name.startswith(EXT_ID_PREFIX_CONSTRAINT): - # double-check we are really going to delete all the owners of this schema element - cr.execute("""SELECT id from ir_model_data where name = %s and res_id IS NULL""", (data.name,)) - external_ids = [x[0] for x in cr.fetchall()] - if (set(external_ids)-ids_set): - # as installed modules have defined this element we must not delete it! - continue - - if name.startswith(EXT_ID_PREFIX_FK): - name = name[len(EXT_ID_PREFIX_FK):] - # test if FK exists on this table (it could be on a related m2m table, in which case we ignore it) - cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid) - WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table)) - if cr.fetchone(): - cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),) - _logger.info('Dropped FK CONSTRAINT %s@%s', name, model) - continue - - if name.startswith(EXT_ID_PREFIX_M2M_TABLE): - name = name[len(EXT_ID_PREFIX_M2M_TABLE):] - cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name=%s", (name,)) - if cr.fetchone() and not name in to_drop_table: - to_drop_table.append(name) - continue - - if name.startswith(EXT_ID_PREFIX_CONSTRAINT): - name = name[len(EXT_ID_PREFIX_CONSTRAINT):] - # test if constraint exists - cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid) - WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table)) - if cr.fetchone(): - cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),) - _logger.info('Dropped CONSTRAINT %s@%s', name, model) - continue - pair_to_unlink = (model, res_id) if pair_to_unlink not in to_unlink: to_unlink.append(pair_to_unlink) @@ -948,17 +912,12 @@ class ir_model_data(osv.osv): except: _logger.info('Unable to force processing of workflow for item %s@%s in order to leave activity to be deleted', res_id, model) - # drop m2m relation tables - for table in to_drop_table: - cr.execute('DROP TABLE %s CASCADE'% (table),) - _logger.info('Dropped table %s', table) - def unlink_if_refcount(to_unlink): for model, res_id in to_unlink: external_ids = self.search(cr, uid, [('model', '=', model),('res_id', '=', res_id)]) if (set(external_ids)-ids_set): # if other modules have defined this record, we must not delete it - return + continue _logger.info('Deleting %s@%s', res_id, model) try: self.pool.get(model).unlink(cr, uid, [res_id], context=context) @@ -970,11 +929,18 @@ class ir_model_data(osv.osv): if model not in ('ir.model','ir.model.fields')) unlink_if_refcount((model, res_id) for model, res_id in to_unlink if model == 'ir.model.fields') + + ir_model_relation = self.pool.get('ir.model.relation') + relation_ids = ir_model_relation.search(cr, uid, [('module', 'in', modules_to_remove)]) + ir_model_relation._module_data_uninstall(cr, uid, relation_ids, context) + unlink_if_refcount((model, res_id) for model, res_id in to_unlink if model == 'ir.model') cr.commit() + self.unlink(cr, uid, ids, context) + def _process_end(self, cr, uid, modules): """ Clear records removed from updated module data. This method is called at the end of the module loading process. diff --git a/openerp/addons/base/ir/ir_model_constraint.py b/openerp/addons/base/ir/ir_model_constraint.py new file mode 100644 index 00000000000..4a69bc2f0a7 --- /dev/null +++ b/openerp/addons/base/ir/ir_model_constraint.py @@ -0,0 +1,79 @@ +import logging + +import openerp +from openerp import SUPERUSER_ID +from openerp.osv import fields +from openerp.osv.orm import Model + +_logger = logging.getLogger(__name__) + +class ir_model_constraint(Model): + """ + This model tracks PostgreSQL foreign keys and constraints used by OpenERP + models. + """ + _name = 'ir.model.constraint' + _columns = { + 'name': fields.char('Constraint', required=True, size=128, select=1, + help="PostgreSQL constraint or foreign key name."), + 'model': fields.many2one('ir.model', string='Model', + required=True, select=1), + 'module': fields.many2one('ir.module.module', string='Module', + required=True, select=1), + 'type': fields.char('Constraint Type', required=True, size=1, select=1, + help="Type of the constraint: `f` for a foreign key, " + "`u` for other constraints."), + 'date_update': fields.datetime('Update Date'), + 'date_init': fields.datetime('Initialization Date') + } + + _sql_constraints = [ + ('module_name_uniq', 'unique(name, module)', + 'Constraints with the same name are unique per module.'), + ] + + def _module_data_uninstall(self, cr, uid, ids, context=None): + """ + Delete PostgreSQL foreign keys and constraints tracked by this model. + """ + + if uid != SUPERUSER_ID and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"): + raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module'))) + + context = dict(context or {}) + + ids_set = set(ids) + ids.sort() + ids.reverse() + to_unlink = [] + for data in self.browse(cr, uid, ids, context): + model = data.model.model + model_obj = self.pool.get(model) + name = openerp.tools.ustr(data.name) + typ = data.type + + # double-check we are really going to delete all the owners of this schema element + cr.execute("""SELECT id from ir_model_constraint where name=%s""", (data.name,)) + external_ids = [x[0] for x in cr.fetchall()] + if (set(external_ids)-ids_set): + # as installed modules have defined this element we must not delete it! + continue + + if typ == 'f': + # test if FK exists on this table (it could be on a related m2m table, in which case we ignore it) + cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid) + WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table)) + if cr.fetchone(): + cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),) + _logger.info('Dropped FK CONSTRAINT %s@%s', name, model) + + if typ == 'u': + # test if constraint exists + cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid) + WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table)) + if cr.fetchone(): + cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),) + _logger.info('Dropped CONSTRAINT %s@%s', name, model) + + to_unlink.append(data.id) + self.unlink(cr, uid, to_unlink, context) diff --git a/openerp/addons/base/ir/ir_model_relation.py b/openerp/addons/base/ir/ir_model_relation.py new file mode 100644 index 00000000000..eede6eae44f --- /dev/null +++ b/openerp/addons/base/ir/ir_model_relation.py @@ -0,0 +1,65 @@ +import logging + +import openerp +from openerp import SUPERUSER_ID +from openerp.osv import fields +from openerp.osv.orm import Model + +_logger = logging.getLogger(__name__) + +class ir_model_relation(Model): + """ + This model tracks PostgreSQL tables used to implement OpenERP many2many + relations. + """ + _name = 'ir.model.relation' + _columns = { + 'name': fields.char('Relation Name', required=True, size=128, select=1, + help="PostgreSQL table name implementing a many2many relation."), + 'model': fields.many2one('ir.model', string='Model', + required=True, select=1), + 'module': fields.many2one('ir.module.module', string='Module', + required=True, select=1), + 'date_update': fields.datetime('Update Date'), + 'date_init': fields.datetime('Initialization Date') + } + + def _module_data_uninstall(self, cr, uid, ids, context=None): + """ + Delete PostgreSQL many2many relations tracked by this model. + """ + + if uid != SUPERUSER_ID and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"): + raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module'))) + + ids_set = set(ids) + to_drop_table = [] + ids.sort() + ids.reverse() + to_unlink = [] + for data in self.browse(cr, uid, ids, context): + model = data.model + model_obj = self.pool.get(model) + name = openerp.tools.ustr(data.name) + + # double-check we are really going to delete all the owners of this schema element + cr.execute("""SELECT id from ir_model_relation where name = %s""", (data.name,)) + external_ids = [x[0] for x in cr.fetchall()] + if (set(external_ids)-ids_set): + # as installed modules have defined this element we must not delete it! + continue + + cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name=%s", (name,)) + if cr.fetchone() and not name in to_drop_table: + to_drop_table.append(name) + + to_unlink.append(data.id) + + self.unlink(cr, uid, to_unlink, context) + + # drop m2m relation tables + for table in to_drop_table: + cr.execute('DROP TABLE %s CASCADE'% (table),) + _logger.info('Dropped table %s', table) + + cr.commit() diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 75a6c6cb523..0f28c33ded9 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -24,16 +24,16 @@ from operator import itemgetter from osv import osv, fields from tools.translate import _ -class ir_needaction_users_rel(osv.osv): - ''' - ir_needaction_users_rel holds data related to the needaction - mechanism inside OpenERP. A row in this model is characterized by: +class ir_needaction_users_rel(osv.Model): + ''' ir_needaction_users_rel holds data related to the needaction + mechanism inside OpenERP. A row in this model is characterized + by: - res_model: model of the record requiring an action - res_id: ID of the record requiring an action - - user_id: foreign key to the res.users table, to the user that - has to perform the action - This model can be seen as a many2many, linking (res_model, res_id) to - users (those whose attention is required on the record).''' + - user_id: foreign key to the res.users table, to the user that has to + perform the action + This model can be seen as a many2many, linking (res_model, res_id) to users + (those whose attention is required on the record). ''' _name = 'ir.needaction_users_rel' _description = 'Needaction relationship table' @@ -78,50 +78,47 @@ class ir_needaction_users_rel(osv.osv): return True -class ir_needaction_mixin(osv.osv): +class ir_needaction_mixin(osv.Model): '''Mixin class for objects using the need action feature. - Need action feature can be used by objects willing to be able to - signal that an action is required on a particular record. If in the - business logic an action must be performed by somebody, for instance - validation by a manager, this mechanism allows to set a list of - users asked to perform an action. + Need action feature can be used by objects having to be able to + signal that an action is required on a particular record. If in + the business logic an action must be performed by somebody, for + instance validation by a manager, this mechanism allows to set a + list of users asked to perform an action. - This class wraps a class (ir.ir_needaction_users_rel) that behaves - like a many2many field. However, no field is added to the model - inheriting from this mixin class. This class handles the low-level - considerations of updating relationships. Every change made on the - record calls a method that updates the relationships. + This class wraps a class (ir.ir_needaction_users_rel) that + behaves like a many2many field. This class handles the low-level + considerations of updating relationships. Every change made on + the record calls a method that updates the relationships. - Objects using the 'need_action' feature should override the - ``get_needaction_user_ids`` method. This methods returns a dictionary - whose keys are record ids, and values a list of user ids, like - in a many2many relationship. Therefore by defining only one method, - you can specify if an action is required by defining the users - that have to do it, in every possible situation. + Objects using the 'need_action' feature should override the + ``get_needaction_user_ids`` method. This methods returns a + dictionary whose keys are record ids, and values a list of user + ids, like in a many2many relationship. Therefore by defining + only one method, you can specify if an action is required by + defining the users that have to do it, in every possible + situation. - This class also offers several global services,: + This class also offers several global services: - ``needaction_get_record_ids``: for the current model and uid, get - all record ids that ask this user to perform an action. This - mechanism is used for instance to display the number of pending - actions in menus, such as Leads (12) + all record ids that ask this user to perform an action. This + mechanism is used for instance to display the number of pending + actions in menus, such as Leads (12) - ``needaction_get_action_count``: as ``needaction_get_record_ids`` - but returns only the number of action, not the ids (performs a - search with count=True) - - ``needaction_get_user_record_references``: for a given uid, get all - the records that ask this user to perform an action. Records - are given as references, a list of tuples (model_name, record_id) + but returns only the number of action, not the ids (performs a + search with count=True) - The ``ir_needaction_mixin`` class adds a function field on models inheriting - from the class. This field allows to state whether a given record has - a needaction for the current user. This is usefull if you want to customize - views according to the needaction feature. For example, you may want to - set records in bold in a list view if the current user has an action to - perform on the record. This makes the class not a pure abstract class, - but allows to easily use the action information.''' + The ``ir_needaction_mixin`` class adds a calculated field + ``needaction_pending``. This function field allows to state + whether a given record has a needaction for the current user. + This is usefull if you want to customize views according to the + needaction feature. For example, you may want to set records in + bold in a list view if the current user has an action to perform + on the record. ''' _name = 'ir.needaction_mixin' - _description = '"Need action" mixin' + _description = 'Need action mixin' def get_needaction_pending(self, cr, uid, ids, name, arg, context=None): res = {} @@ -129,13 +126,19 @@ class ir_needaction_mixin(osv.osv): for id in ids: res[id] = uid in needaction_user_ids[id] return res + + def search_needaction_pending(self, cr, uid, self_again, field_name, criterion, context=None): + ids = self.needaction_get_record_ids( + cr, uid, uid, limit=1024, context=context) + return [('id', 'in', ids)] _columns = { - 'needaction_pending': fields.function(get_needaction_pending, type='boolean', - string='Need action pending', - help='If True, this field states that users have to perform an action. \ - This field comes from the needaction mechanism. Please refer \ - to the ir.needaction_mixin class.'), + 'needaction_pending': fields.function( + get_needaction_pending, type='boolean', + fnct_search=search_needaction_pending, + string='Need action pending', + help="If True, this field states that users have to perform an " \ + "action This field comes from the ir.needaction_mixin class."), } #------------------------------------------------------ @@ -146,7 +149,7 @@ class ir_needaction_mixin(osv.osv): """ Returns the user_ids that have to perform an action :return: dict { record_id: [user_ids], } """ - return dict.fromkeys(ids, []) + return dict((id,list()) for id in ids) def create(self, cr, uid, values, context=None): rel_obj = self.pool.get('ir.needaction_users_rel') @@ -191,14 +194,5 @@ class ir_needaction_mixin(osv.osv): get the number of actions it has to perform""" rel_obj = self.pool.get('ir.needaction_users_rel') return rel_obj.search(cr, uid, [('res_model', '=', self._name), ('user_id', '=', user_id)], limit=limit, count=True, context=context) - - def needaction_get_record_references(self, cr, uid, user_id, offset=None, limit=None, order=None, context=None): - """For a given user_id, get all the records that asks this user to - perform an action. Records are given as references, a list of - tuples (model_name, record_id). - This method is trans-model.""" - rel_obj = self.pool.get('ir.needaction_users_rel') - rel_ids = rel_obj.search(cr, uid, [('user_id', '=', user_id)], offset=offset, limit=limit, order=order, context=context) - return map(itemgetter('res_model', 'res_id'), rel_obj.read(cr, uid, rel_ids, ['res_model', 'res_id'], context=context)) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/wizard/wizard_menu_view.xml b/openerp/addons/base/ir/wizard/wizard_menu_view.xml index a9c841a6d69..58bd98ef785 100644 --- a/openerp/addons/base/ir/wizard/wizard_menu_view.xml +++ b/openerp/addons/base/ir/wizard/wizard_menu_view.xml @@ -8,8 +8,9 @@
-
diff --git a/openerp/addons/base/ir/workflow/workflow_view.xml b/openerp/addons/base/ir/workflow/workflow_view.xml index bda98b7c8c0..89809d327ae 100644 --- a/openerp/addons/base/ir/workflow/workflow_view.xml +++ b/openerp/addons/base/ir/workflow/workflow_view.xml @@ -317,7 +317,7 @@ {'search_default_active':1} - +