Restrict write permissions for a field - Odoo 15 - odoo

How can I restrict the write permissions for a field to a specific group ?
I want to check if a user is in a specific group with id 46. If the user is in this group, he should be allowed to write in this field. If he is not in this group, he should not be allowed to write.
The field is a custom field, editing the domain with the studio app I think I should avoid.
My field:
<field name="customer_codename" placeholder="Codename" attrs="{'invisible':['|',('customer_rank','=', 0),('is_company','=', False)]}"/>
I tried the following, but it did not work:
I created a new field using the studio app. Field type is boolean.
In the advanced properties I wanted to define the compute for the field. In dependencies I gave "user_id" and in the compute field I gave
for record in self:
user_id.has_group('__export__.res_groups_46_eff9dc52')
The boolean field should be set to true if the user is in a certain group.

Not sure if I can give you the best answer there is.
But for me, I'd personally create a Boolean field in the view's associated model, with its default field a lambda function checking if the user belongs to the groups you mentioned.
Assuming groups_id is the name of the user groups in model res.users, we have:
class ResUsers(models.Model):
_inherit = "res.users"
can_write_codename = fields.Boolean(default=lambda self: self.groups_id in ("model_name.group_name"))
Then in your xml file, you can include can_write_codename inside attrs, like this:
<field name="customer_codename" placeholder="Codename" attrs="{'invisible':['|',('customer_rank','=', 0),('is_company','=', False)], 'readonly': [('can_write_codename', '=', 'True')]}"}"/>

Related

How to store logged user in Odoo14

I am trying to store the currently logged user into a many2one field using compute method. It's working fine if i define the Mnay2one field without the store="True" parameter. Actually, i need to save it.
Here is the code:
def get_logged_user(self):
for rec in self:
print('inside get_logged_user---------------',rec.env.user.name)
rec.logged_user_id = rec.env.user.id
logged_user_id = fields.Many2one('res.users',string="Logged user",store=True,compute="get_logged_user")
EDIT:
If you only need to control visibility of a field/button inside QWeb view you could archive this without dedicated field. You could use context.get('uid') to get current user like this:
<button ... invisible="context.get('uid') == assigned_user_id">
But if you need to store logged-in user inside a field you could use default instead of compute.
Something like this:
logged_user_id = fields.Many2one('res.users', string="Logged user", default=lambda self: self.env.user)
Note usage of lambda function.
If you really need to use compute field with store=True you need to specify when to compute it. By using api.depends decorator you can trigger it when your_field is changed.
#api.depends('your_field')
def get_logged_user(self):
But I would ask a question why do you need to store logged-in user inside a field? If you could provide more context maybe we could suggest different solution.

Show a many2many field as a many2one

I have a field many2many and in a specific view I need to show it as a many2one, or imitate the behavior of the many2one fields (restrict that only one record can be added and if the user select another record, the one that had previously selected will be deleted). In the view I declared:
<field name="employee_ids" widget="many2one" />
but it gave me the following error:
TypeError: 'int' object is not iterable
Is there any way to achieve this?
I think you can force the user to select only one record by
using onchange decorator:
#api.onchange('employee_ids')
def force_one_selection(self):
"""Force the user to select only one record"""
if self.employee_ids and len(self.employee_ids) > 1:
# user has added a new record
self.employee_ids = [(6, 0, self.employee_ids[0].id)] # you can change the index to 1
# and you can return a warning here to tell the user that he should not select more than
# one record

Shall I record the user name who modify a certain field by Odoo?

.py file:
….
namex=fields.Text()
moifier=fields.Many2one(‘res.users’, string=”Modifier”)
…
When some user modify “namex”, his/her name should be recorded on field “modifier” automatically; what code should I make? I try “onchange/depends”, but failed; maybe modifier could be a “text field/ char field”?
in addition, shall I set "access_rule" to set users just see the records created by the members in his/her own group?
Odoo already has that for you. Every model has those fields, which are automatically created and updated each time you create, or write:
create_date (datetime): when record is created
create_uid (many2one): user who created this record
write_date (datetime): last time record is updated
write_uid (many2one): last user updated this record
Go to Settings > Technical > Database Structure > Models for more details.
While Odoo will keep for you a track of the last user which has modified a record, a modifier per field is not kept. I can see the interest of such a functionality in many cases.
To do that for a particular model one possibility is to redefine the write method of this model. In your .py file you may want to add something like this:
#api.model
def write(self):
if self.namex in values:
values.update({'modifier': uid})
super().write(cr, uid, ids, values, context)
Another way to do that in a more flexible way is to use the #onchange decorator:
#onchange('your_sensible_field_name'):
def set_modifier(self):
self.modifer = self.env.user
You may also want to take a look at the #depends decorator.

Odoo Filter many2one field on load

In my module I have a many2one field to select workers for a particular task. According to the requirement that field should only display the workers in the current user's department. Simply this is the code,
_columns = {
'employee_id': fields.many2one('hr.employee', 'Employee'),
}
My problem is how to perform such filteration for a field on load? I tried using functional field in a domain in view xml. but It seems functional field gets its value when saving the particular record.
Also I tried adding domain to the field itself, here get_current_user_department is a function returns the department id
_columns = {
'employee_id': fields.many2one('hr.employee', 'Employee',domain=[('department_id.id','=',get_current_user_department)]),
}
This generates following error,
TypeError: is not JSON serializable
Any suggestion to make this work? Thanks
Also you can take one field for storing current user department you can set default value of current user department.
default_department_id = fields.Many2one('employee.department',
string='My User',
default='get_department')
Now you need to create function for set default department.
After that you need to write in XML:
<field name="default_department_id" invisible="1"/>
<field name="employee_id"
domain="
[('department_id','=',default_department_id)]
"/>
You have to define a new many2one field to save the current user department ID and put the value of the department at loading with default_get() method.
Then after, you can put this field on a domain to filter employee that are in the same department than the user.

How to retrieve the current user in OpenERP module

I'm developing an OpenERP 7 module and I need to add a field that logs the user who created each record. How do I retrieve the current user object?
this kind of field is already available in openerp, as create_uid and write_uid.
In OpenERP Python code, functions generally take cr, the database pointer, and uid, the user id, as arguments. If all you need is the id of the current res.users object (for instance, to write into the one2many field), you can use uid as is. If you need to access the object (to see fields, etc.), something like:
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
should work.