openerp domain filters how to compare 2 fields in object? - filter

In Odoo/OpenERP I want to make a filter to compare field1 and field2 of the same object like below.
Plz let me know how to make this filter work, adding filter on partners search form:
<field name="credit_limit"/>
<field name="credit"/>
<filter name="credit limit" domain="[('credit','>',credit_limit)]"/>
Applying this filter gives below error:
Uncaught Error: Failed to evaluate search criterions:
{"code":400,"message":"Evaluation Error","data":{"type":"local_exception","debug":"Local evaluation failure\nNameError: name 'credit_limit' is not defined\n\n{\"domains\":[[],\"[('customer','=',1)]\",\"[('credit','=',credit_limit)]\"],\"contexts\":[{\"lang\":\"en_US\",\"tz\":\"Africa/Cairo\",\"uid\":1,\"search_default_customer\":1}],\"group_by_seq\":[]}"}}
I googled many times to find a solution without finding anyone .
the simple form [('credit_limit','<',credit)] always returns the error "can not convert string to float" where string is credit and float is credit_limit.
is there any way to say [('credit_limit','<',valueof(credit))] or [('field1','=',valueof(field2))] ??
Regards,

You need to create a function field with a search function to do that.
Here is an example, using the 'old api' syntax:
class SomeModel(orm.Model):
_name = 'some.model'
def _func_credit_limit_exceeded(self, cr, uid, ids,
field_name, arg, context):
"""compute the value of the function field"""
res = {}
for record in self.browse(cr, uid, ids, context=context):
res[record.id] = record.credit > record.credit_limit
return res
def _func_search_credit_limit_exceeded(self, cr, uid, obj,
name, criterion, context):
"""we only support a search on the form
('column_name', '=', boolean) or ('column_name', '!=', boolean)
"""
match_ids = []
field, op, value = criterion
# argument processing
if op == '!=':
value = not value
elif op != '=':
raise ValueError('Unsupported operator')
# build the search query
if value = True:
comparison = '>'
else:
comparison = '<='
query = 'SELECT id FROM some_model ' \
'WHERE credit %s credit_limit' % comparison
# get the ids matching the search
# and return the corresponding domain
cr.execute(query)
for row in cr.fetchall():
match_ids.append(row[0])
if match_ids:
# return domain matching the selected ids
return [('id', 'in', match_ids)]
else:
# return a domain which will never yield a result
return [('id', '=', 0)]
_columns = {'credit': fields.float('Credit'),
'credit_limit': fields.float('Credit Limit'),
'credit_limit_exceeded':
fields.function(_func_credit_limit_exceeded,
fnct_search=_func_search_credit_limit_exceeded,
string='Credit Limit Exceeded',
type='boolean'),
}

For numeric fields, you can create a computed field which counts the difference of the two field. if the result is 0 they are equal, if negative the 2nd is greater if positive the first is greater.

Related

operator.itemgetter(*item) giving error TypeError: '<' not supported between instances of 'NoneType' and 'int'

I am using a recursive function for Grouping data list which I am getting by executing database query and the below function worked fine. But since yesterday it started throwing error as below:
in _group_data data_list.sort(key=itemgetter(*filter_key))
TypeError: '<' not supported between instances of 'NoneType' and 'int'
def _group_data(data_list, key_list, previous_key=[]):
"""
:param data_list: A list of dictionary got from executing sql query.
:param key_list: Group by list of keys.
:param previous_key: The earlier key to do grouping at the root level. Default is an empty list.
:return: Grouped Data list.
"""
# Base case
if len(key_list) == 1:
filter_key = key_list[0]
data_list.sort(key=itemgetter(*filter_key))
dl = list()
for _, group in groupby(data_list, key=itemgetter(*filter_key)):
d_dict = {'details': []}
for g in group:
if previous_key is not None:
d_dict['details'].append(
{key: value for key, value in g.items() if key not in (filter_key + previous_key)}
)
d_dict.update({key: value for key, value in g.items() if key in filter_key})
else:
d_dict['details'].append({key: value for key, value in g.items() if key not in filter_key})
d_dict.update({key: value for key, value in g.items() if key in filter_key})
dl.append(d_dict)
return dl
# Recursive block
else:
filter_key = key_list[0]
dl = list()
p_key = previous_key + filter_key
data_list.sort(key=itemgetter(*filter_key)) #getting error here
for _, group in groupby(data_list, key=itemgetter(*filter_key)):
group_list = list(group)
print('key_list[1:] ',key_list[1:])
print('p_key ',p_key)
d_list = _group_data(group_list, key_list[1:], p_key)
p_dict = {key: value for key, value in group_list[0].items() if key in filter_key}
p_dict['details'] = d_list
dl.append(p_dict)
return dl
I am trying to Identify the problem but not getting any clue, Also tried few things from the google search but nothing helped for example sorted() but got the same error. Thanks in advance for the help.
Issue was resolved. I was getting data as null for a key, but it was supposed to be integer that's why it was throwing error. so, from the dB side value of that key is set to 0 as a default.

How to Sort List of Objects Based on a Property Value

I am using a CriteraBuilder to return a list of objects. I want to sort this list (hopefully in the query) by a property value in the object if it equals status "PENDING". The statuses on the object can be "Valid, Expired, or Pending". The objects with status "Pending" I want to place first in the returned list. Note I want to be able to paginate this list.
CRITERIA
def getAllIds(Map opts = [:]) {
def max = opts.max ?: 10
def offset = opts.offset ?: 0
def c = Identification.createCriteria()
List<Identification> ids = c.list(max: max, offset: offset) {
//sort here if status == "PENDING"
}
return ids
}
You can use 'withCriteria' instead of 'createCrkteria'+'list' and use 'order' into it
See http://docs.grails.org/3.1.1/ref/Domain%20Classes/withCriteria.html

How to make result from one odoo field to affect the result of another field

I have a time difference field
time_diff = fields.Char(string="Time Difference", required=False, )
and a sla field in odoo
sla_state = fields.Selection(string="SLA", selection=[('past sla', 'Past SLA'), ('within sla', 'Within SLA'), ], required=False, )
i want to set a condition where if time difference is greater than 1
the sla state automatically populates to Past SLA
Below is my function
#api.onchange('time_diff')
def get_sla(self):
if self.time_diff >= 1:
self.sla_state == 'past sla'
else:
self.sla_state == 'within sla'
But its not working what might be the issue
Please help.
The problem is you are comparing the string with integer. Data type of 'time_diff' is string. So string can not be compared with integer. Convert the string to integer using int()
#api.onchange('time_diff')
def get_sla(self):
if self.time_dif:
if int(self.time_diff) >= 1:
self.sla_state == 'past sla'
else:
self.sla_state == 'within sla'

ODOO - How to filter Many2Many field containing zero items

How can I filter an Odoo Many2Many field for containing zero items.
Example: I'm trying to filter tasks that have 0 followers (message_follower_ids).
[['message_follower_ids','=',False]] Returns no results, but there should be many.
Odoo version: 8.0
Frank
message_follower_ids is a compute field.
If you want to search by any compute field you have to write the search method of it in old api it is fnct_search and in that method you can return domain.
In your case message_follower_ids is compute one and also having the fnct_search method. so, whenever you search for follower in search bar in top right corner that method will call and return the domain and you will get your filtered list.
But in that fnct_search You need to change to accomplish your need.
Like this.
class mail_thread(osv.AbstractModel):
_inherit = 'mail.thread'
def _get_followers(self, cr, uid, ids, name, arg, context=None):
fol_obj = self.pool.get('mail.followers')
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids)])
res = dict((id, dict(message_follower_ids=[], message_is_follower=False)) for id in ids)
user_pid = self.pool.get('res.users').read(cr, uid, [uid], ['partner_id'], context=context)[0]['partner_id'][0]
for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids):
res[fol.res_id]['message_follower_ids'].append(fol.partner_id.id)
if fol.partner_id.id == user_pid:
res[fol.res_id]['message_is_follower'] = True
return res
def _search_followers(self, cr, uid, obj, name, args, context):
"""Search function for message_follower_ids
Do not use with operator 'not in'. Use instead message_is_followers
"""
fol_obj = self.pool.get('mail.followers')
res = []
for field, operator, value in args:
assert field == name
# TOFIX make it work with not in
assert operator != "not in", "Do not search message_follower_ids with 'not in'"
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('partner_id', operator, value)])
if not fol_ids and operator == '=' and value==False:
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('partner_id', '!=', value)])
res_ids = [fol.res_id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids)]
res.append(('id', 'not in', res_ids))
else:
res_ids = [fol.res_id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids)]
res.append(('id', 'in', res_ids))
return res
_columns = {
'message_follower_ids': fields.function(_get_followers,fnct_search=_search_followers),
}
Also need to add mail module in dependency list.

Rewrite an OpenERP 7 method to Odoo 8 syntax?

I have the following OpenERP 7 method:
# Function to get the vat number (CIF/NIF) and then show it on invoice form view
def _get_vat_num(self, cr, uid, ids, field_name, args=None, context=None):
partner_pool = self.pool.get('res.partner')
invoice_pool = self.pool.get('account.invoice')
res = {}
for inv in self.browse(cr, uid, ids, context=context):
invoice = invoice_pool.browse(cr,uid, inv.id, context=None)
partner = partner_pool.browse(cr, uid, invoice.partner_id.id, context=None)
res[inv.id] = partner.vat
return res
inv_vat = fields.Char(compute='_get_vat_num', string="CIF/NIF")
I need to rewrite it to Odoo v8 syntax. I have tried but it doesn't work:
def _get_vat_num(self):
partner_pool = self.env['res.partner']
invoice_pool = self.env['account.invoice']
res = {}
for inv in self.browse(self.id):
invoice = invoice_pool.browse(inv.id)
partner = partner_pool.browse(invoice.partner_id.id)
res[inv.id] = partner.vat
return res
What should be the correct code?
It looks like you're setting a functional field. You should instead be able to define the field as a related field like so:
inv_vat = fields.Char(string="VAT", related="partner_id.vat")
If you really want it as a functional field, this is how you would do it
inv_vat = fields.Char(string="VAT", compute="_get_vat_num")
def _get_vat_num(self):
# self is a recordset of account.invoice records
for invoice in self:
# to set a functional field, you just assign it
invoice.inv_vat = invoice.partner_id.vat
Check out the recordset documentation: https://www.odoo.com/documentation/8.0/reference/orm.html#recordsets
And the computed fields documentation:
https://www.odoo.com/documentation/8.0/reference/orm.html#computed-fields

Resources