[MERGE] from trunk

bzr revid: rco@openerp.com-20120928124403-aht90hi49yxwrcmz
bzr revid: rco@openerp.com-20121001073112-xbxdturd27bwscg1
This commit is contained in:
Raphael Collet 2012-10-01 09:31:12 +02:00
commit a6e30d305c
15 changed files with 135 additions and 94 deletions

View File

@ -8,6 +8,7 @@
<field name="symbol">$</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field name="position">before</field>
<field name="company_id" ref="main_company"/>
</record>
<record id="rateUSD" model="res.currency.rate">

View File

@ -1442,6 +1442,7 @@
<field name="name"/>
<field name="model_id"/>
<field name="group_id"/>
<field name="active"/>
</group>
<group string="Access" col="4">
<field name="perm_read"/>
@ -1493,8 +1494,9 @@
<sheet>
<group>
<group string="General">
<field colspan="4" name="name"/>
<field name="name"/>
<field name="model_id"/>
<field name="active"/>
</group>
<group col="4" string="Access Rights">
<field name="perm_read"/>

View File

@ -468,6 +468,7 @@ class ir_model_access(osv.osv):
_name = 'ir.model.access'
_columns = {
'name': fields.char('Name', size=64, required=True, select=True),
'active': fields.boolean('Active', help='If you uncheck the active field, it will disable the ACL without deleting it (if you delete a native ACL, it will be re-created when you reload the module.'),
'model_id': fields.many2one('ir.model', 'Object', required=True, domain=[('osv_memory','=', False)], select=True, ondelete='cascade'),
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade', select=True),
'perm_read': fields.boolean('Read Access'),
@ -475,6 +476,9 @@ class ir_model_access(osv.osv):
'perm_create': fields.boolean('Create Access'),
'perm_unlink': fields.boolean('Delete Access'),
}
_defaults = {
'active': True,
}
def check_groups(self, cr, uid, group):
grouparr = group.split('.')
@ -499,14 +503,16 @@ class ir_model_access(osv.osv):
cr.execute("SELECT perm_" + mode + " "
" FROM ir_model_access a "
" JOIN ir_model m ON (m.id = a.model_id) "
" WHERE m.model = %s AND a.group_id = %s", (model_name, group_id)
" WHERE m.model = %s AND a.active IS True "
" AND a.group_id = %s", (model_name, group_id)
)
r = cr.fetchone()
if r is None:
cr.execute("SELECT perm_" + mode + " "
" FROM ir_model_access a "
" JOIN ir_model m ON (m.id = a.model_id) "
" WHERE m.model = %s AND a.group_id IS NULL", (model_name, )
" WHERE m.model = %s AND a.active IS True "
" AND a.group_id IS NULL", (model_name, )
)
r = cr.fetchone()
@ -531,6 +537,7 @@ class ir_model_access(osv.osv):
LEFT JOIN ir_module_category c ON (c.id=g.category_id)
WHERE
m.model=%s AND
a.active IS True AND
a.perm_''' + access_mode, (model_name,))
return [('%s/%s' % x) if x[0] else x[1] for x in cr.fetchall()]
@ -560,6 +567,7 @@ class ir_model_access(osv.osv):
' JOIN res_groups_users_rel gu ON (gu.gid = a.group_id) '
' WHERE m.model = %s '
' AND gu.uid = %s '
' AND a.active IS True '
, (model_name, uid,)
)
r = cr.fetchone()[0]
@ -571,6 +579,7 @@ class ir_model_access(osv.osv):
' JOIN ir_model m ON (m.id = a.model_id) '
' WHERE a.group_id IS NULL '
' AND m.model = %s '
' AND a.active IS True '
, (model_name,)
)
r = cr.fetchone()[0]

View File

@ -75,6 +75,7 @@ class ir_rule(osv.osv):
_columns = {
'name': fields.char('Name', size=128, select=1),
'active': fields.boolean('Active', help="If you uncheck the active field, it will disable the record rule without deleting it (if you delete a native record rule, it may be re-created when you reload the module."),
'model_id': fields.many2one('ir.model', 'Object',select=1, required=True, ondelete="cascade"),
'global': fields.function(_get_value, string='Global', type='boolean', store=True, help="If no group is specified the rule is global and applied to everyone"),
'groups': fields.many2many('res.groups', 'rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
@ -89,6 +90,7 @@ class ir_rule(osv.osv):
_order = 'model_id DESC'
_defaults = {
'active': True,
'perm_read': True,
'perm_write': True,
'perm_create': True,
@ -114,6 +116,7 @@ class ir_rule(osv.osv):
FROM ir_rule r
JOIN ir_model m ON (r.model_id = m.id)
WHERE m.model = %s
AND r.active is True
AND r.perm_""" + mode + """
AND (r.id IN (SELECT rule_group_id FROM rule_group_rel g_rel
JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid)

View File

@ -25,25 +25,25 @@
</record>
<record model="ir.module.category" id="module_category_sales_management">
<field name="name">Sales Management</field>
<field name="name">Sales</field>
<field name="description">Helps you handle your quotations, sale orders and invoicing.</field>
<field name="sequence">2</field>
</record>
<record model="ir.module.category" id="module_category_project_management">
<field name="name">Project Management</field>
<field name="name">Project</field>
<field name="description">Helps you manage your projects and tasks by tracking them, generating plannings, etc...</field>
<field name="sequence">3</field>
</record>
<record model="ir.module.category" id="module_category_knowledge_management">
<field name="name">Knowledge Management</field>
<field name="name">Knowledge</field>
<field name="description">Lets you install addons geared towards sharing knowledge with and between your employees.</field>
<field name="sequence">4</field>
</record>
<record model="ir.module.category" id="module_category_warehouse_management">
<field name="name">Warehouse Management</field>
<field name="name">Warehouse</field>
<field name="description">Helps you manage your inventory and main stock operations: delivery orders, receptions, etc.</field>
<field name="sequence">5</field>
</record>
@ -67,7 +67,7 @@
</record>
<record model="ir.module.category" id="module_category_purchase_management">
<field name="name">Purchase Management</field>
<field name="name">Purchases</field>
<field name="description">Helps you manage your purchase-related processes such as requests for quotations, supplier invoices, etc...</field>
<field name="sequence">9</field>
</record>

View File

@ -90,8 +90,8 @@
<form string="Bank account" version="7.0">
<group col="4">
<field name="state"/>
<field name="acc_number"/>
<field name="company_id" on_change="onchange_company_id(company_id)"
<field name="acc_number" placeholder="Account Number"/>
<field name="company_id" groups="base.group_multi_company" on_change="onchange_company_id(company_id)"
invisible="context.get('company_hide', True)" widget="selection"/>
<field name="footer" invisible="context.get('footer_hide', True)"/>
</group>
@ -113,7 +113,7 @@
<group name="bank" string="Information About the Bank">
<field name="bank" on_change="onchange_bank_id(bank)"/>
<field name="bank_name" attrs="{'required': [('company_id','&lt;&gt;',False)]}"/>
<field name="bank_bic" placeholder="[Identifier code]" />
<field name="bank_bic" placeholder="e.g. GEBABEBB" />
</group>
</group>

View File

@ -195,7 +195,7 @@ class res_company(osv.osv):
]
ids = proxy.search(cr, uid, args, context=context)
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
for rule in proxy.browse(cr, uid, ids, context):
if eval(rule.expression, {'context': context, 'user': user}):
return rule.company_dest_id.id

View File

@ -22,6 +22,7 @@
import math
import openerp
from osv import osv, fields
from openerp import SUPERUSER_ID
import re
import tools
from tools.translate import _
@ -33,7 +34,7 @@ from lxml import etree
class format_address(object):
def fields_view_get_address(self, cr, uid, arch, context={}):
user_obj = self.pool.get('res.users')
fmt = user_obj.browse(cr, uid, uid,context).company_id.country_id
fmt = user_obj.browse(cr, SUPERUSER_ID, uid, context).company_id.country_id
fmt = fmt and fmt.address_format
layouts = {
'%(city)s %(state_code)s\n%(zip)s': """
@ -189,24 +190,27 @@ class res_partner(osv.osv, format_address):
'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'),
'ref': fields.char('Reference', size=64, select=1),
'lang': fields.selection(_lang_get, 'Language',
help="If the selected language is loaded in the system, all documents related to this partner will be printed in this language. If not, it will be english."),
help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."),
'tz': fields.selection(_tz_get, 'Timezone', size=64,
help="The partner's timezone, used to output proper date and time values inside printed reports. "
"It is important to set a value for this field. You should use the same timezone "
"that is otherwise used to pick and render date and time values: your computer's timezone."),
'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this partner if any.'),
'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if the partner is subjected to taxes. Used by the some of the legal statements."),
'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this contact if any.'),
'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements."),
'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
'website': fields.char('Website', size=64, help="Website of Partner or Company"),
'comment': fields.text('Notes'),
'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'), # should be removed in version 7, but kept until then for backward compatibility
'address': fields.one2many('res.partner.address', 'partner_id', 'Addresses',
deprecated="The address information is now directly stored on each Partner record. "\
"Multiple contacts with their own address can be added via the child_ids relationship. "\
"This field will be removed as of OpenERP 7.1."),
'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'),
'credit_limit': fields.float(string='Credit Limit'),
'ean13': fields.char('EAN13', size=13),
'active': fields.boolean('Active'),
'customer': fields.boolean('Customer', help="Check this box if the partner is a customer."),
'supplier': fields.boolean('Supplier', help="Check this box if the partner is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."),
'employee': fields.boolean('Employee', help="Check this box if the partner is an Employee."),
'customer': fields.boolean('Customer', help="Check this box if this contact is a customer."),
'supplier': fields.boolean('Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."),
'employee': fields.boolean('Employee', help="Check this box if this contact is an Employee."),
'function': fields.char('Job Position', size=128),
'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'),
('delivery', 'Delivery'), ('contact', 'Contact'),
@ -218,7 +222,8 @@ class res_partner(osv.osv, format_address):
'city': fields.char('City', size=128),
'state_id': fields.many2one("res.country.state", 'State'),
'country_id': fields.many2one('res.country', 'Country'),
'country': fields.related('country_id', type='many2one', relation='res.country', string='Country'), # for backward compatibility
'country': fields.related('country_id', type='many2one', relation='res.country', string='Country',
deprecated="This field will be removed as of OpenERP 7.1, use country_id instead"),
'email': fields.char('Email', size=240),
'phone': fields.char('Phone', size=64),
'fax': fields.char('Fax', size=64),
@ -228,13 +233,13 @@ class res_partner(osv.osv, format_address):
'use_parent_address': fields.boolean('Use Company Address', help="Select this if you want to set company's address information for this contact"),
# image: all image fields are base64 encoded and PIL-supported
'image': fields.binary("Image",
help="This field holds the image used as avatar for the partner, limited to 1024x1024px"),
help="This field holds the image used as avatar for this contact, limited to 1024x1024px"),
'image_medium': fields.function(_get_image, fnct_inv=_set_image,
string="Medium-sized image", type="binary", multi="_get_image",
store={
'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Medium-sized image of the partner. It is automatically "\
help="Medium-sized image of this contact. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views."),
'image_small': fields.function(_get_image, fnct_inv=_set_image,
@ -242,7 +247,7 @@ class res_partner(osv.osv, format_address):
store={
'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Small-sized image of the partner. It is automatically "\
help="Small-sized image of this contact. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required."),
'company_id': fields.many2one('res.company', 'Company', select=1),
@ -392,7 +397,7 @@ class res_partner(osv.osv, format_address):
- otherwise: default, everything is set as the name """
match = re.search(r'([^\s,<@]+@[^>\s,]+)', text)
if match:
email = match.group(1)
email = match.group(1)
name = text[:text.index(email)].replace('"','').replace('<','').strip()
else:
name, email = text, ''
@ -440,7 +445,7 @@ class res_partner(osv.osv, format_address):
def find_or_create(self, cr, uid, email, context=None):
""" Find a partner with the given ``email`` or use :py:method:`~.name_create`
to create one
:param str email: email-like string, which should contain at least one email,
e.g. ``"Raoul Grosbedon <r.g@grosbedon.fr>"``"""
assert email, 'an email is required for find_or_create to work'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -47,7 +47,7 @@
-->
<record id="action_partner_title_partner" model="ir.actions.act_window">
<field name="name">Partner Titles</field>
<field name="name">Titles</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.title</field>
<field name="view_type">form</field>

View File

@ -52,7 +52,7 @@ class groups(osv.osv):
else:
res[g.id] = g.name
return res
def _search_group(self, cr, uid, obj, name, args, context=None):
operand = args[0][2]
operator = args[0][1]
@ -64,7 +64,7 @@ class groups(osv.osv):
group_name = values[1]
where = ['|',('category_id.name', operator, application_name)] + where
return where
_columns = {
'name': fields.char('Name', size=64, required=True, translate=True),
'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
@ -138,7 +138,7 @@ class res_users(osv.osv):
def _get_password(self, cr, uid, ids, arg, karg, context=None):
return dict.fromkeys(ids, '')
_columns = {
'id': fields.integer('ID'),
'login_date': fields.date('Latest connection', select=1),
@ -193,21 +193,6 @@ class res_users(osv.osv):
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
return self.pool.get('res.partner').onchange_address(cr, uid, partner_ids, use_parent_address, parent_id, context=context)
def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'):
def override_password(o):
if 'password' in o and ( 'id' not in o or o['id'] != uid ):
o['password'] = '********'
return o
result = super(res_users, self).read(cr, uid, ids, fields, context, load)
canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False)
if not canwrite:
if isinstance(ids, (int, long)):
result = override_password(result)
else:
result = map(override_password, result)
return result
def _check_company(self, cr, uid, ids, context=None):
return all(((this.company_id in this.company_ids) or not this.company_ids) for this in self.browse(cr, uid, ids, context))
@ -276,8 +261,34 @@ class res_users(osv.osv):
return self.pool.get('res.partner').fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
return super(res_users, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
# User can write to a few of her own fields (but not her groups for example)
SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small']
# User can write on a few of his own fields (but not his groups for example)
SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz']
# User can read a few of his own fields
SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id', '__last_update']
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
def override_password(o):
if 'password' in o and ('id' not in o or o['id'] != uid):
o['password'] = '********'
return o
if fields and (ids == [uid] or ids == uid):
for key in fields:
if not (key in self.SELF_READABLE_FIELDS or key.startswith('context_')):
break
else:
# safe fields only, so we read as super-user to bypass access rights
uid = SUPERUSER_ID
result = super(res_users, self).read(cr, uid, ids, fields=fields, context=context, load=load)
canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False)
if not canwrite:
if isinstance(ids, (int, long)):
result = override_password(result)
else:
result = map(override_password, result)
return result
def write(self, cr, uid, ids, values, context=None):
if not hasattr(ids, '__iter__'):
@ -495,14 +506,14 @@ class res_users(osv.osv):
"""
assert group_ext_id and '.' in group_ext_id, "External ID must be fully qualified"
module, ext_id = group_ext_id.split('.')
cr.execute("""SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN
cr.execute("""SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN
(SELECT res_id FROM ir_model_data WHERE module=%s AND name=%s)""",
(uid, module, ext_id))
return bool(cr.fetchone())
#
# Extension of res.groups and res.users with a relation for "implied" or
# Extension of res.groups and res.users with a relation for "implied" or
# "inherited" groups. Once a user belongs to a group, it automatically belongs
# to the implied groups (transitively).
#

View File

@ -45,7 +45,9 @@
<form string="Access Controls" version="7.0">
<group col="4">
<field name="name"/>
<field name="active"/>
<field name="model_id"/>
<newline/>
<field name="perm_read"/>
<field name="perm_write"/>
<field name="perm_create"/>
@ -202,8 +204,6 @@
</h1>
<group name="preferences" col="4">
<field name="lang" readonly="0"/>
<field name="company_id" readonly="0"
groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/>
<field name="tz" readonly="0"/>
<field name="company_id" widget="selection" readonly="0"
groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/>

View File

@ -11,7 +11,7 @@
<field name="name">Access Rights</field>
</record>
<record model="res.groups" id="group_system">
<field name="name">Configuration</field>
<field name="name">Settings</field>
<field name="implied_ids" eval="[(4, ref('group_erp_manager'))]"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>

View File

@ -1552,24 +1552,16 @@ def field_to_dict(model, cr, user, field, context=None):
res['fnct_search'] = field._fnct_search and field._fnct_search.func_name or False
res['fnct_inv'] = field._fnct_inv and field._fnct_inv.func_name or False
res['fnct_inv_arg'] = field._fnct_inv_arg or False
res['func_obj'] = field._obj or False
if isinstance(field, many2many):
(table, col1, col2) = field._sql_names(model)
res['related_columns'] = [col1, col2]
res['third_table'] = table
for arg in ('string', 'readonly', 'states', 'size', 'required', 'group_operator',
'change_default', 'translate', 'help', 'select', 'selectable', 'groups'):
if getattr(field, arg):
res[arg] = getattr(field, arg)
for arg in ('digits', 'invisible', 'filters'):
res['m2m_join_columns'] = [col1, col2]
res['m2m_join_table'] = table
for arg in ('string', 'readonly', 'states', 'size', 'group_operator', 'required',
'change_default', 'translate', 'help', 'select', 'selectable', 'groups',
'deprecated', 'digits', 'invisible', 'filters'):
if getattr(field, arg, None):
res[arg] = getattr(field, arg)
if field.string:
res['string'] = field.string
if field.help:
res['help'] = field.help
if hasattr(field, 'selection'):
if isinstance(field.selection, (tuple, list)):
res['selection'] = field.selection