How to use 'like' operator in the attrs attribute to hide or show a button - odoo

I need to hide or show a button depending on whether or not a Char field has a specific string in it. It seems that the 'like' operator would be perfect. In my xml, I have:
<record model="ir.ui.view" id="my_view">
<field name="name">my.form</field>
<field name="model">mymodule.my</field>
<field name="arch" type="xml">
<form string="My Form">
<header>
<button name="test_like_1" type="object"
string="Should not appear"
attrs="{'invisible':[('state2','like','measure')]}"
/>
<button name="test_like_2" type="object"
string="Should appear"
attrs="{'invisible':[('state2','not like','measure')]}"
/>
...
State2 contains 'measure,prelien', so I expect that the first button will be invisible and the second visible. However, both are invisible.
What am I missing?
Edit
I ran the query that I think Odoo would create from this domain -
select id, description, state2 from mymodule_my where state2 like '%measure%';
It runs as expected, returning the records that have "measure" as a substring. Somehow, this SQL isn't being generated/used. My next step is to dig through the Odoo code & see what's happening.
Can anyone provide insight to what's going on?

I found the problem - available operators for attrs in a view describes it best and outlines one possible solution. The gist is that the domains specified in attrs are evaluated in javascript on the client. The 'like' & 'ilike' operators aren't implemented.
You can verify this by viewing the console. In my case, I got a ton of these warnings -
Unsupported operator ilike in domain [["state2","ilike","measure"]]
I'm looking into either extending the compute_domain function in odoo/addons/web/static/src/js/framework/data.js as suggested1 or simply working-around the limitation.

You could try
attrs="{'invisible':[('state2','in',['Measure','MEASURE','measure'])]}"
And
attrs="{'invisible':[('state2','not in',['Measure','MEASURE','measure'])]}"
You may have to add more items to your lists. I am not sure if like and not like are supported but this is a method I see used in other addons.

You're comparing the string 'state2' instead of the value of the field state2 also you should be comparing the other way around, this isn't exactly the best example but you should get what i mean.
>>> 'measure,prelien' in 'measure'
False
>>> 'measure' in 'measure,prelien'
True
>>>
The first condition will never evaluate to true. you should do this instead
define a char field named default, and set it's default value to 'measure' and make it hidden on the view
measure = fields.Char('Measure', default='measure', store=False)
Then your view should look like this
<field name="measure" invisible="1" />
<button name="test_like_1" type="object"
string="Should not appear"
attrs="{'invisible':[('measure', 'like', state2)]}"
/>
<button name="test_like_2" type="object"
string="Should appear"
attrs="{'invisible':[('measure', 'not like', state2)]}"
/>

Related

How to not allow Many2many to be able to remove its element in form view?

I have a many2many field that represents a list of student. I want to only add student to that list but not remove any students from that list (in form view). Is it possible to implement that?
I think it's possible to do it. You need to override the #write method. Each time that an update will be made on your object, you need the compare the actual length of your many2many field current_length and the new length of students made by the update new_length.
If new_length > current_length, it's means that the update is an adding, so you can consider the changes. Otherwise, it's means that the update is a removing, so you just need to ignore the changes.
Please find below, an exemple of implementation :
#api.multi
def write(self, values):
current_length = len(self.student_list)
new_length = len(values['student_list'])
if current_length > new_length:
\* Removing of students *\
values['student_list'] = self.student_list
res = super(Object, self).write(values)
return res
Note that you can go further by making another comparaison between the ids of the current and new list, in order to be sure that the students are the same.
It s not possible using the many2many_tags widget, but using the xml tree view as part of your Form view, you can add the delete-attribute on the tree-node inside the scope of your own field:
<form>
<notebook>
<sheet>
<page string="Graduated" name="gratuated_students">
<field name="students_ids" >
<tree string="Students" editable="bottom" delete="0" >
<field name="name"/>
<field name="birthday"/>
<field name="score" readonly="1"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
If this view comes from an odoo's module (no custom module): you'd rather inherit this view and add the attribute "delete=0" to the existing student_ids field:
<xpath expr="//form[1]/sheet[1]/notebook[1]/page[1]/field[#name='students_ids']/tree[1]" position="attributes">
<attribute name="delete">0</attribute>
</xpath>
Otherwise, if you really want to use the many2many_tags widget and if your are experienced with odoo's js-framework, you could develop your own option "no_delete" on the basis of the following OCA module:
https://odoo-community.org/shop/web-m2x-options-2661#attr=10772

Invisible field on condition in odoo

I have one field which i want to hide when specific journal selected.
<field name="any_field" attrs="{'invisible':[('journal_id','=',10])]}"/>
And For that above code is working fine.
I sure it is not a way to check condition.So, i tried this way.
<field name="any_field" attrs="{'invisible':[('journal_id','=',ref('my_module.account_journal_10'))]}"/>
It's working then i tried by using the static field on the journal eg. code.
<field name="any_field" attrs="{'invisible':[('journal_id.code','=','CARD')]}"/>
But still not working and getting error from view.
I am thinking if i can return the attrs from .py like i do for domain.
eg.
return {'domain':
{
'any_field':[('journal_id','=',self.env.ref('my_module.account_journal_10').id)]
}
}
Can anybody help me in this?
Thank you.
As far as i know these attrs domains/filters are client-side so you can't use something like journal_id.code or partner_id.customer, because the client doesn't know about such data.
A possible workaround is to define a related field on the model you're trying to do this. Let's assume the model is my.model and already has this Many2one field journal_id:
journal_code = fields.Char(string="Journal Code", related="journal_id.code")
Now you need to extend the view of my.model:
<field name="journal_code" invisible="1" />
<field name="any_field" attrs="{'invisible':[('journal_code','=','CARD')]}"/>

How does one link to other defined entities using their id?

When writing XML files I will occasionally need to reference another entity, such as a group, a category, or an action.
How can I accomplish this?
There are two different methods to do this, and which one you use depends on where you are in the record:
in the type="xml" or type="html" portions (such as tree and form views)
everywhere else
Inside the type=["xml" | "html"] portions you need to use %-interpolation:
<button string="..." name="%(fnx_pd.action_add_cleaning_order)d" type="action" />
<field name="item_id" domain="[('categ_id','=',%(fnx_pd.pd_cleaning)d)]" />
The thing you are linking to needs to be inside a %()d or %()s construct: %(module.id_name)d.
If not inside an xml or html segment, then you can use the OpenERP-provided ref() function to get the id:
<field name="value" eval="'ir.actions.server,' + str(ref('action_release'))"/>
<field name="context" eval="{'default_pos_categ_id': ref('point_of_sale.categ_others')}"/>
In both of the above methods, OpenERP will look up the actual value associated with the id given and substitute it into the record.

make a page tab dynamic invisible with domain in inherited view

I try to make a page tab in a view dynamicly visible based on the value of a field of the model. A field that is availble on the screen.
I need to change this is an inherited view
I tried:
<xpath expr="//page[#string='Functions']" position="attributes">
<attribute name="invisible">[('org_type_id','!=',0)]</attribute>
</xpath>
But now the page tab function is always hidden. even for the org_type_id that are 0.
Is it not possible to use xpath to add a dynamic invisible attritbute?
You are totally going on wrong way to do that job.
Just you can do with the the following way to do your job
some thing like this.
<xpath expr="//page[#string='Functions']" position="attributes">
<attribute name="attrs">{'invisible':[('org_type_id','!=',0)]}</attribute>
I hope this should helpful for you :)
You should also try this,
<page string="Functions" position="attributes">
<attribute name="attrs">{'invisible':[('org_type_id','!=',0)]}</attribute>
</page>

OpenERP, error while creating a view filter

Im having problems with creating a filter on stock.picking object. Just recently i build a simple "privilege relay" - in each stock location you can define "Assigned User Group", thanks to that users that are in particular group can or cannot confirm moves for or out of the location.
Stock.picking:location_id -> assigned_user_group -> users
Now I would like to create a filter (later to be set default) on stock picking tree view that will show only the moves which locations (source location and destination location; i use them in stock.picking object) can be managed by a viewing user.
By far I wrote a filter that looks like that:
<record id="view_picking_internal_search_pl" model="ir.ui.view">
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
<filter icon="terp-dialog-close" name="done" string="Done" domain="[('state','=','done')]" help="Pickings already processed" position="after">
<filter icon="terp-check" name="locgroup" string="Location Group" domain="[('user_id','in',[user.id for user in location_id.user_group.users])]" context="{'group_by':'date'}"/>
</filter>
</field>
</record>
I also added field location_id to the tree view.
But Im still getting an error (after choosing the filter) that even google doesnt know anything about:
TypeError: results.group_by is undefined
My questions are:
By looking on domain in filter field - what am i doing wrong?
Is something like that even possible?
I will gladly welcome any help.
Firstly, i think your domain is not correct, it could have been :
[('user_group.users.id', '=', uid)]
(because the first element of the tuple is a field on the model; and uid is a special value supplied in search views)
Next, This error :
TypeError: results.group_by is undefined
Seems to be a Javascript Error (coming from openerp-web interface), it often throws error like that when it receives unexpected values (when we make a mistake defining a view for example).
can you tell us if using the domain above solved your problem ?
NB: does your field user_group is a required field ? If not, i think the domain above won't display picking where user_group is not set, if you want to display picking where user_group is not set too, you can set a domain like that:
['|',('user_group.users.id', '=', uid), ('user_group','=',False)]
Regards