Christophe Simonis 2013-09-12 17:06:16 +02:00
commit e13ffe7e11
11 changed files with 132 additions and 24 deletions

View File

@ -37,7 +37,6 @@ There are two types of views:
.. note:: Since OpenERP 4.1, form views can also contain graphs.
Form views
----------
@ -388,6 +387,33 @@ The easiest method to compute real statistics on objects is:
You can get en example in all modules of the form: report\_.... Example: report_crm.
Controlling view actions
------------------------
When defining a view, the following attributes can be added on the
opening element of the view (i.e. ``<form>``, ``<tree>``...)
``create``
set to ``false`` to hide the link / button which allows to create a new
record.
``delete``
set to ``false`` to hide the link / button which allows to remove a
record.
``edit``
set to ``false`` to hide the link / button which allows to
edit a record.
These attributes are available on form, tree, kanban and gantt
views. They are normally automatically set from the access rights of
the users, but can be forced globally in the view definition. A
possible use case for these attributes is to define an inner tree view
for a one2many relation inside a form view, in which the user cannot
add or remove related records, but only edit the existing ones (which
are presumably created through another way, such as a wizard).
Calendar Views
--------------
@ -680,6 +706,7 @@ toolbar
its descendants will be displayed in the main tree. The value is ignored
for flat lists.
Grouping Elements
+++++++++++++++++

View File

@ -110,7 +110,7 @@ class report_xml(osv.osv):
kwargs = {}
new_report = report_sxw('report.'+r['report_name'], r['model'],
opj('addons',r['report_rml'] or '/'), header=r['header'], register=False, **kwargs)
elif r['report_xsl']:
elif r['report_xsl'] and r['report_xml']:
new_report = report_rml('report.'+r['report_name'], r['model'],
opj('addons',r['report_xml']),
r['report_xsl'] and opj('addons',r['report_xsl']), register=False)

View File

@ -404,7 +404,8 @@ class ir_mail_server(osv.osv):
# The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters.
from_rfc2822 = extract_rfc2822_addresses(smtp_from)
assert len(from_rfc2822) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters"
assert len(set(from_rfc2822)) == 1, ("Malformed 'Return-Path' or 'From' address: %r - "
"It should contain one plain ASCII email") % smtp_from
smtp_from = from_rfc2822[0]
email_to = message['To']
email_cc = message['Cc']

View File

@ -125,11 +125,15 @@ class view(osv.osv):
try:
fvg = self.pool[view.model].fields_view_get(cr, uid, view_id=view.id, view_type=view.type, context=context)
return fvg['arch']
except:
except Exception:
_logger.exception("Can't render view %s for model: %s", view.xml_id, view.model)
return False
def _check_xml(self, cr, uid, ids, context=None):
if context is None:
context = {}
context['check_view_ids'] = ids
for view in self.browse(cr, uid, ids, context):
# Sanity check: the view should not break anything upon rendering!
view_arch_utf8 = self._check_render_view(cr, uid, view, context=context)
@ -175,13 +179,15 @@ class view(osv.osv):
:rtype: list of tuples
:return: [(view_arch,view_id), ...]
"""
user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
if self.pool._init:
# Module init currently in progress, only consider views from modules whose code was already loaded
check_view_ids = context and context.get('check_view_ids') or (0,)
query = """SELECT v.id FROM ir_ui_view v LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id)
WHERE v.inherit_id=%s AND v.model=%s AND (md.module IS NULL or md.module in %s)
WHERE v.inherit_id=%s AND v.model=%s AND (md.module in %s OR v.id in %s)
ORDER BY priority"""
query_params = (view_id, model, tuple(self.pool._init_modules))
query_params = (view_id, model, tuple(self.pool._init_modules), tuple(check_view_ids))
else:
# Modules fully loaded, consider all views
query = """SELECT v.id FROM ir_ui_view v

View File

@ -508,6 +508,16 @@ class res_partner(osv.osv, format_address):
def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
#res.partner must only allow to set the company_id of a partner if it
#is the same as the company of all users that inherit from this partner
#(this is to allow the code from res_users to write to the partner!) or
#if setting the company_id to False (this is compatible with any user company)
if vals.get('company_id'):
for partner in self.browse(cr, uid, ids, context=context):
if partner.user_ids:
user_companies = set([user.company_id.id for user in partner.user_ids])
if len(user_companies) > 1 or vals['company_id'] not in user_companies:
raise osv.except_osv(_("Warning"),_("You can not change the company as the partner/user has multiple user linked with different companies."))
result = super(res_partner,self).write(cr, uid, ids, vals, context=context)
for partner in self.browse(cr, uid, ids, context=context):
self._fields_sync(cr, uid, partner, vals, context)
@ -608,14 +618,15 @@ class res_partner(osv.osv, format_address):
if operator in ('=ilike', '=like'):
operator = operator[1:]
query_args = {'name': search_name}
limit_str = ''
query = ('''SELECT id FROM res_partner
WHERE email ''' + operator + ''' %(name)s
OR display_name ''' + operator + ''' %(name)s
ORDER BY display_name
''')
if limit:
limit_str = ' limit %(limit)s'
query += ' limit %(limit)s'
query_args['limit'] = limit
cr.execute('''SELECT partner.id FROM res_partner partner
LEFT JOIN res_partner company ON partner.parent_id = company.id
WHERE partner.email ''' + operator +''' %(name)s OR
partner.display_name ''' + operator + ' %(name)s ' + limit_str, query_args)
cr.execute(query, query_args)
ids = map(lambda x: x[0], cr.fetchall())
ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
if ids:

View File

@ -280,6 +280,13 @@ class res_users(osv.osv):
return result
def create(self, cr, uid, vals, context=None):
user_id = super(res_users, self).create(cr, uid, vals, context=context)
user = self.browse(cr, uid, user_id, context=context)
if user.partner_id.company_id:
user.partner_id.write({'company_id': user.company_id.id})
return user_id
def write(self, cr, uid, ids, values, context=None):
if not hasattr(ids, '__iter__'):
ids = [ids]
@ -294,7 +301,11 @@ class res_users(osv.osv):
uid = 1 # safe fields only, so we write as super-user to bypass access rights
res = super(res_users, self).write(cr, uid, ids, values, context=context)
if 'company_id' in values:
for user in self.browse(cr, uid, ids, context=context):
# if partner is global we keep it that way
if user.partner_id.company_id and user.partner_id.company_id.id != values['company_id']:
user.partner_id.write({'company_id': user.company_id.id})
# clear caches linked to the users
self.pool['ir.model.access'].call_cache_clearing_methods(cr)
clear = partial(self.pool['ir.rule'].clear_cache, cr)

View File

@ -110,9 +110,7 @@
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
"access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
"access_ir_filter all","ir_filters all","model_ir_filters",,1,0,0,0
"access_ir_filter employee","ir_filters employee","model_ir_filters","group_user",1,1,1,1
"access_ir_filters","ir_filters_all","model_ir_filters",,1,1,1,1
"access_ir_filter all","ir_filters all","model_ir_filters",,1,1,1,1
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
110 access_res_bank_user res_bank user model_res_bank group_user 1 0 0 0
111 access_multi_company_default user multi_company_default all model_multi_company_default 1 0 0 0
112 access_multi_company_default manager multi_company_default Manager model_multi_company_default group_erp_manager 1 1 1 1
113 access_ir_filter all ir_filters all model_ir_filters 1 0 1 0 1 0 1
access_ir_filter employee ir_filters employee model_ir_filters group_user 1 1 1 1
access_ir_filters ir_filters_all model_ir_filters 1 1 1 1
114 access_ir_config_parameter ir_config_parameter model_ir_config_parameter 1 0 0 0
115 access_ir_mail_server ir_mail_server model_ir_mail_server group_system 1 1 1 1
116 access_ir_actions_client ir_actions_client all model_ir_actions_client 1 0 0 0

View File

@ -6,6 +6,7 @@ import test_menu
import test_res_config
import test_res_lang
import test_search
import test_views
checks = [
test_base,
@ -16,4 +17,5 @@ checks = [
test_res_config,
test_res_lang,
test_search,
test_views,
]

View File

@ -0,0 +1,44 @@
import unittest2
import openerp.tests.common as common
from openerp.osv.orm import except_orm
from openerp.tools import mute_logger
class test_views(common.TransactionCase):
@mute_logger('openerp.osv.orm', 'openerp.addons.base.ir.ir_ui_view')
def test_00_init_check_views(self):
Views = self.registry('ir.ui.view')
self.assertTrue(Views.pool._init)
error_msg = "Invalid XML for View Architecture"
# test arch check is call for views without xmlid during registry initialization
with self.assertRaisesRegexp(except_orm, error_msg):
Views.create(self.cr, self.uid, {
'name': 'Test View #1',
'model': 'ir.ui.view',
'arch': """<?xml version="1.0"?>
<tree>
<field name="test_1"/>
</tree>
""",
})
# same for inherited views
with self.assertRaisesRegexp(except_orm, error_msg):
# Views.pudb = True
Views.create(self.cr, self.uid, {
'name': 'Test View #2',
'model': 'ir.ui.view',
'inherit_id': self.browse_ref('base.view_view_tree').id,
'arch': """<?xml version="1.0"?>
<xpath expr="//field[@name='name']" position="after">
<field name="test_2"/>
</xpath>
""",
})
if __name__ == '__main__':
unittest2.main()

View File

@ -329,13 +329,21 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# they are part of the "currently installed" modules. They will
# be dropped in STEP 6 later, before restarting the loading
# process.
states_to_load = ['installed', 'to upgrade', 'to remove']
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
processed_modules.extend(processed)
if update_module:
states_to_load = ['to install']
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
processed_modules.extend(processed)
# IMPORTANT 2: We have to loop here until all relevant modules have been
# processed, because in some rare cases the dependencies have
# changed, and modules that depend on an uninstalled module
# will not be processed on the first pass.
# It's especially useful for migrations.
previously_processed = -1
while previously_processed < len(processed_modules):
previously_processed = len(processed_modules)
processed_modules += load_marked_modules(cr, graph,
['installed', 'to upgrade', 'to remove'],
force, status, report, loaded_modules, update_module)
if update_module:
processed_modules += load_marked_modules(cr, graph,
['to install'], force, status, report,
loaded_modules, update_module)
# load custom models
cr.execute('select model from ir_model where state=%s', ('manual',))

View File

@ -2189,7 +2189,7 @@ class BaseModel(object):
are applied
"""
sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name)
sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name, context=context)
for (view_arch, view_id) in sql_inherit:
source = apply_inheritance_specs(source, view_arch, view_id)
source = apply_view_inheritance(cr, user, source, view_id)