This question has been flagged
4 Replies
15944 Views

I am trying to achieve that all the users that are Hr managers should be allowed to see the records. I have created a Functional Field:

def list_HRM(self, cr, uid, ids, field_name, arg, context):
         attribute = {}
        hr_managers = self.pool.get('hr.employee').search(cr, uid, ['&', ('department_id.name', '=', 'Human Resources'), ('manager', '=', True)], context=context)
        hr_managers_uid = []
        for record in hr_managers:
            hr_managers_uid.append(self.pool.get('hr.employee').browse(cr, uid, record, context=context).user_id.id)
        record = self.browse(cr, uid, ids)[0]
        attribute[record.id] = str(uid in hr_managers_uid or uid==1)
        return attribute

    _columns={
    'hr_managers_func' : fields.function(list_HRM, type='char', method=True, string='List of HR Managers'),
    'always_true':fields.boolean()
     }
   _defaults={
      'always_true':True
      }

In .xml file:

<field name="always_true" invisible="1"/>
<field name="hr_managers_func" invisible="1"/>

In Record Rule:

['&','|',('state','=','hod_depart'),('state','=','hr_review'),('always_true','=',eval(hr_managers_func))]

I used field 'always_true' because of the record rule condition format i.e. [('field_name','operator',values)]. I thought that rule will evaluate the functional field using eval but unfortunately eval is not working on the record rule , I am getting this error:

NameError: name 'eval' is not defined

I could not think of more than this. I saw few forum somewhat similar to my problem, they were using the related field to avoid the functional field in the record, but here I have to check whether the current user belong to hr managers or not . I have tried explaining this in the best possible way, Looking forward for some reply.

Avatar
Discard
Best Answer

You could see another example of using a function field in the record rules here:

https://www.odoo.com/forum/help-1/question/how-to-show-different-task-stages-to-different-users-depending-on-other-model-90009#answer-90031 

 

Avatar
Discard

thx for comment, I didn't read this before, I'll check it.

Best Answer

I found out another method to call a function from ir.rule.

Here it is.

    <record id="manager_asterisk_cdr_rule" model="ir.rule">
        <field name="name">Manager Asterisk CDR rule</field>
        <field name="perm_write" eval="1"/>
        <field name="perm_read" eval="1"/>
        <field name="perm_create" eval="1"/>
        <field name="perm_unlink" eval="1"/>
        <field name="groups" eval="[(6,0, [ref('group_barrier_manager')])]"/>
        <field name="model_id" ref="asterisk_base.model_asterisk_cdr"/>
        <field name="domain_force">user.manager.get_cdr_domain()</field>
    </record>

The main part is:

    <field name="domain_force">user.manager.get_cdr_domain()</field>

And here is the function:

    @api.multi
    def get_cdr_domain(self):
        # Used from facility_manager/security.xml to filter CDR records
        facility_ids = [f.id for f in self.facilities]
        barriers = self.env['barrier.barrier'].search(
                                            [('facility', 'in', facility_ids)])
        numbers = []
        for b in barriers:
            # Add barrier access phones
            numbers.extend([a.number for a in b.access_phones])
            # Add panels GSM number
            numbers.extend(
                [p.gsm_number for p in b.call_panels if p.gsm_number])
            # Add panels SIP number
            numbers.extend(
                [p.sip_number for p in b.call_panels if p.sip_number])
        # Add keys of type=phone
        key_numbers = [k.number for k in self.env[
            'barrier.resident_key'].search([
                                           ('facility', 'in', facility_ids),
                                           ('key_type', '=', 'phone')])]
        numbers.extend(key_numbers)
        domain = ['|', ('src', 'in', numbers), ('dst', 'in', numbers)]
        return domain

Also when you add new records to the models requested from the function you need to clear cache:

    self.env['ir.rule'].clear_cache()

Avatar
Discard

this worked good, but you have to use user.your_function in domain_force, it have to be user, company_id, company_ids or else, it will causing error.
also, you need to write your_function() when inherit "res.users".

Best Answer

Your request is to allow only managers to see the states hod_depart, hr_review

I'll achieved this differently, using the idea of the search function related to the function field. 

I don't have your status list, so I applied my logic on crm_lead table with the condition that employees in sales dep. can see all priorities, while others can see up to priority 3.

I replaced the word 'manager' with 'sales' to agree with the example I'm describing, the logic is the same. I created a module for this example and tested it, here is the module:

__init__.py: 
import community
__openerp__.py: 
{
"name" : "Community Examples",
"author" : "Tarek Mohamed Ibrahim",
"category" : "Examples",
"licence" : "AGPL-3",
"depends" : ['hr','crm'
],
"data" : [
'security/community_security.xml',
],
"demo" : [],
"installable": True,
"auto_install": False,
"application": False,
}

community.py

class crm_lead(osv.osv): 
     _inherit = 'crm.lead'
     #changing this method , but actually it works like a dummy function, the one which is really works is the search method
     def _get_list_sales(self, cr, uid, ids, field_name, arg, context):
         attribute = {}
         hr_sales = self.pool.get('hr.employee').search(cr, uid, [('department_id.name', '=', 'Sales')], context=context)
         hr_sales_uid = []
         for record in hr_sales:
             hr_sales_uid.append(self.pool.get('hr.employee').browse(cr, uid, record, context=context).user_id.id)
        
         record = self.browse(cr, uid, ids)[0]
         attribute[record.id] = str(uid in hr_sales_uid or uid==1)
         return attribute


     def list_sales_search(self, cr, uid, obj, name, args, context=None):
         if not args:
             return []

         #get the uid from the passed value
         uid = args[0][2]

         #get some code from lst_HRM to evaluate the current uid
         hr_sales = self.pool.get('hr.employee').search(cr, uid, [('department_id.name', '=', 'Sales')], context=context)
         hr_sales_uid = []
         for record in hr_sales:
             hr_sales_uid.append(self.pool.get('hr.employee').browse(cr, uid, record, context=context).user_id.id)
        
         is_sales = uid in hr_sales_uid or uid==1

         #build a query
         if is_sales:
             query = "select id from crm_lead"
         else:
             query = "select id from crm_lead where priority<'4'"

         #execute the query
         cr.execute(query)
         res = cr.fetchall()
         if not res:
             return [('id','=','0')]
         else:
             return [('id','in', [x[0] for x in res])]

         _columns = {
                 'list_sales' : fields.function(_get_list_sales, type='char', method=True, string='List of HR Sales',fnct_search=list_sales_search),
         }

crm_lead()

I defined the function field in crm_lead as the rule is going to be applied on this class

here is the rule

<?xml version="1.0" encoding="utf-8"?> 
<openerp>
     <data noupdate="0">
         <record model="ir.rule" id="ir_rule_sales_crm_leads">
             <field name="name">filter leadss</field>
             <field name="model_id" ref="crm.model_crm_lead"/>
             <field name="domain_force">[('list_sales','=',user.id)]</field>
             <field name="perm_read" eval="True"/>
             <field name="perm_write" eval="True"/>
             <field name="perm_unlink" eval="True"/>
             <field name="perm_create" eval="True"/>
         </record>
     </data>
</openerp>

The thing that one can say it is not logical is the expression

('list_sales','=',user.id) 

which indicates that I'm going to equate the user.id value with the result of the function field list_sales, but the point is that I used a feature in the search function related to the function field to return a list of records ids based on the input sent to the function, which in our case is the user.id.

This could be generalized by sending any tuple, or even a dictionary, to the search function and doing any calculations. This could be achieved by replacing the user.id parameter with any tuple, or dictionary and receiving all needed values in the search function body by indexes

One more thing, I can use the 'operator' placeholder also to send any other parameters, as I didn't use the operator in the function.

Pls copy the code and create a module to test it and then you can borrow the logic to your own case, you need to adjust the indentation.

I think this idea is new, my first knowledge of the search function got from the link:  https://www.odoo.com/nl_NL/forum/help-1/question/how-to-implement-fnct-search-29984

I hope this search is useful.


Avatar
Discard