I am having issues with getting a function field to display a string returned by a function in a custom module I am using to extend the stock.picking.out form. Ideally I would like to have a specific string from a field stored in the database displayed but that's an issue for another time because I can't even get a generic string to display..
Here is my field definition within my custom class:
_columns = {
'my_field_name': fields.function(_my_func, type='char', string='description', store=True, method=True, readonly=True),
}
Here is my definition for '_my_func':
def _my_func(self, cr, uid, ids, field_name, arg, context=None):
str="some string to be displayed"
return str
Here is the XML for the field:
<field name="my_field_name" string="Here is my string:" class="oe_inline"/>
I have searched the OpenERP dev book as well as their forums and these forums, and believe I have followed all of the proper syntax for this field so any help is greatly appreciated.
You need to improve your function/method like,
def _my_func(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for rec in self.browse(cr, uid, ids, context=context):
res[rec.id] = 'Some string'
return res
while writing functional field(up to v7) make sure you return a dictionary like
{17: "some string"}
if you have multiple field it can be like
{17: {'field_one': 'value 1', 'field_two': 'value 1'}}
EDIT:
Also In _columns please remove readonly=True like
_columns = {
'my_field_name': fields.function(_my_func, type='char', string='description', store=True, method=True),
}
Hope this helps.
Just you must have to improve your function login
you can do some things like this.
def _my_func(self, cr, uid, ids, field_name, arg, context=None)
v={}
if field_name:
v['my_field_name'] = " some string to be displayed "
return {'value': v}
Then finally your function logic working like a charm.
I hope this should helpful for you :)
Try following,
def _my_func(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for obj in self.browse(cr, uid, ids, context=context):
###Set your string here
str="some string to be displayed"
res[obj.id]['my_field_name'] = str
return res
If you are a little confused with OpenERP v7, you always can try with Odoo(OpenERP v8) It's much more easiest to work.
from openerp import models, fields,api
class my_class(models.Model):
_name="my.class"
my_field_name=fields.Text(string="description", compute=_my_func, store=True, readonly=True)
def _my_func(self):
self.my_field_name = "some string to be displayed"
I hope this can help you!
try this,
def _my_func(self, cr, uid, ids, field_name, arg, context=None):
result = {}
for record in self.browse(cr, uid, ids):
str="some string to be displayed"
result[record.id] = str
return result
and if you use store = True on a functional-field then it will be accessed for the first time and it will store the result in database, and from next time it wont be called.
To access functional field every time for store = True , refer sale.py [amount_total] field. We have to write some addtional code
You can give like this also :
without using browse method..
def _my_func(self, cr, uid, ids, field_name, arg, context=None):
result = {}
str="some string to be displayed"
result[ids[0]] = str
return result
Make sure, in model field type should be char/text.
Related
I am assigning a default value to analytic distribution field in account.invoice.line by below code
def _get_default_account(self, cr, uid, context=None):
res = self.pool.get('account.analytic.plan.instance').search(cr, uid, [('code','=','LAL')], context=context)
return res and res[0] or False
_defaults = {
'analytics_id': _get_default_account,
}
but now i want to set default value for specific group of user. I want to set one value for a group and other value for other group. Means I want to set two different default values for different users.
Someone please give me some idea about it. I'll be very thankful...
Easiest way to approach that is using has_group method. You should do it like:
if self.env['res.users'].has_group('base.group1'):
res = self.pool.get('account.analytic.plan.instance').search(cr, uid, [('code','=','LAL')], context=context)
return res and res[0] or False
elif self.env['res.users'].has_group('base.group2'):
res = self.pool.get('account.analytic.plan.instance').search(cr, uid, [('code','=','SAS')], context=context)
return res and res[0] or False
And so on and so forth.
how could i trigger a function after i click save in OpenERP 7?
In my custom module, i wish to auto increase the "version_number" parameter where every time the user click save it will trigger a function to execute the logic of "ver=ver+1" and write back to the "version_number" fields. How could i do that?
I tried use "def write()" but not sure exactly how it could be done. Appreciate your kind help. Thanks!
You need to override write method.
def write(self, cr, uid, ids, vals, context=None):
res = super(your_model, self).write(cr, uid, ids, vals, context)
self._increment_version(cr, uid, ids)
return res
def _increment_version(self, cr, uid, ids):
for record in self.browse(cr, uid, ids):
cr.execute('update table_name set version_number=%s where id=%s' % (record.version_number + 1, record.id))
Here is the write method work for me
def write(self, cr, uid, ids, vals, context=None):
res = super(your_model, self).write(cr, uid, ids, vals, context)
self._increment_version(cr, uid, ids)
return res
def _increment_version(self, cr, uid, ids):
res = {}
reads = self.read(cr, uid, ids, ['version'], context=context)
ver_num = reads.get('version')
ver_id = reads.get('id')
if ver_num:
cr.execute('update table_name set version_number=%s where id=%s' % (ver_num + 1, ver_id))
return res
you are right you should use write function as.
_columns={...,
'ver':fields.integer(),
...}
def write(self, cr, uid, ids, vals, context=None)
vals['ver']= trigger_func()
return self.super(your_class_name).write(cr, uid, vals, context)
EDIT
It looks like my answer was not clear enough sorry if I didn't check the comments at the time. But because the problem and solutions are the same in newer versions of odoo/openerp, I am adding more description here.
The trigger_func must not write any value to the db (no self.write or self.some_field=some_value). It should simply return the new value for version.
def trigger_func(self):
return self.ver + 1
for newer version of Odoo (V8+), use the same format for trigger function and:
#api.multi
def write(self,vals):
vals['ver'] = self.trigger_func()
return super(YourClassName, self).write(vals)
Please note that this will set the same version for all records, You should use self.ensure_one() at the beginning of the trigger_func if you plan to change versions record by record. If you want a solution that works for multi writes (which I do recommend change your code to avoid it) you can use this slower code:
#api.multi
def write(self,vals):
if len(self)>1:
for rec in self:
rec.write(vals)
return self
else:
vals['ver'] = self.trigger_func()
return super(YourClassName, self).write(vals)
Another solution if you want to add version number to all models, would be patching the Abstract class and adding an auto increase magic field but it looks very overkill for this purpose.
Anyway, I think the direct use of the cursor should be the last resort.
I just create a module. After adding values and got the problem IndexError: list assignment index out of range. How to fix it. Re Edit code please.
Here is my code:
class calculator(osv.osv):
_name = 'calculator.calculator'
def get_total(self, cr, uid, ids, field_name, arg, context):
res = []
perfos = self.browse(cr, uid, ids, context)
for perfo in perfos:
res[perfo.id] = perfo.p + perfo.b
return res
_columns = {
'p':fields.selection(((1,'Outstanding'), (2,'Well Above Expectations'), (3,'As Expected'), (4,'Below Expectations'), (5,'VeryPoor'), (0,'N/A')),'title'),
'b':fields.selection(((1,'Outstanding'), (2,'Well Above Expectations'), (3,'As Expected'), (4,'Below Expectations'), (5,'Very Poor'), (0,'N/A')),'title'),
'total' : fields.function(get_total, method=True, string='Total Mark'),
}
You need to return a dictionary of dictionary for functional fields. You defined res as list and tried to assign as the dictionary. res[perfo.id] is considered as list and index value perfo.id is not found in the res list. That is what the error says. Now the code will be
class calculator(osv.osv):
_name = 'calculator.calculator'
def get_total(self, cr, uid, ids, field_name, arg, context):
res = {}
for perfos in self.browse(cr, uid, ids, context):
res[perfos.id] = perfos.p + perfos.b
return res
_columns = {
'p':fields.selection(((1,'Outstanding'), (2,'Well Above Expectations'), (3,'As Expected'), (4,'Below Expectations'), (5,'VeryPoor'), (0,'N/A')),'title'),
'b':fields.selection(((1,'Outstanding'), (2,'Well Above Expectations'), (3,'As Expected'), (4,'Below Expectations'), (5,'Very Poor'), (0,'N/A')),'title'),
'total' : fields.function(get_total, method=True, string='Total Mark'),
}
For the above code you probably get this js error Error: [_.sprintf] expecting number but found string
I don't get the point adding up two selection fields. The key will get added up like 1+1 in a unicode format.
This following code will give you the basic idea of functional fields.
class calculator(osv.osv):
_name = 'calculator.calculator'
def get_total(self, cr, uid, ids, field_name, arg, context):
res = {}
for perfos in self.browse(cr, uid, ids, context):
res[perfos.id] = perfos.p + perfos.b
return res
_columns = {
'p':fields.integer('A'),
'b':fields.integer('B'),
'total' : fields.function(get_total, method=True, string='Total Mark'),
}
You may need to look at
How to set store trigger for computed fields in Odoo 8?
Function field is not working in OpenERP
I have a function field, but I don't know what should the function return.
Here's my code:
the function:
def _property_expense_preset_expenses(self, cr, uid, ids, expenses, arg, context):
spus = self.browse(cr, uid, ids)
_spu = False
for spu in spus:
_spu = spu
if(_spu):
expenses_acc = {}
property_expense_presets = _spu.property_expense_presets
for property_expense_preset in property_expense_presets:
expenses = property_expense_preset.expense_preset.expenses
for expense in expenses:
expenses_acc[expense.id] = expense
return expenses_acc
else:
return {}
The field definition:
'expenses' : fields.function(
_property_expense_preset_expenses,
type='one2many',
obj="property.expense",
method=True,
string='Expenses'
),
The code above doesn't work, it raises an error : KeyError: 788
Like all function fields, it must return a dictionary with an entry and value for every ID you get passed in ids, although your value can be False, None, []
In your case your functional field is declared as a one2many type which means your functional field must return a dictionary with an entry per id and the value, a list of integers that represent the ids of the related table, in your case, property.expense.
A very common pattern is:
def _property_expense_preset_expenses(self, cr, uid, ids, field, arg, context = None):
res = {}
for spu in self.browse(cr, uid, ids, context = context):
res[spu.id] = []
for preset in spu.property_expense_presets:
res[spu.id].extend([x.id for x in preset.expense_preset.expenses])
return res
Assuming ids contains 1,2,3 you will get a result of
{1: [...], 2: [...], 3: []}
Where each list contains the integer ids of the expenses or an empty list if there are none.
As a general comment, I note your code doesn't default the context argument to None or pass the context as a named argument to the browse method - it is important to do both.
What is Function Field? What return this functional field function?
In OpenERP functional field is a field that return the calculated/logical value that value store into table. That value you can not get directly. that's why we want to use function field and return some value.
When you inserting data into object model functional field call every time defined function and that function logic code whatever you made and return that functional field value.
Example
class me.branch(osv.osv):
_name = "me.branch"
_order = 'name'
def _get_branch_name(self, cr, uid, ids, field_name, arg, context=None):
r = {}
for branch in self.browse(cr, uid, ids, context=context):
r[branch.id] = branch.name.split('/')[-1]
return r
_columns = {
'name': fields.char('Name', required=True),
'branch_name': fields.function(_get_branch_name, type='char', string='Branch', readonly=1, store=True),
}
Above example code branch name (eg. saas/demo/rarone ) already exist in another table.
But I want to get that branch name only last slash (/) after string (rarone) and store into this table only.
I have a function field that doesn't give any errors but then also doesn't set any values even when it should.
code:
class stock_move_custom(osv.osv):
_name = 'stock.move'
_inherit = 'stock.move'
def _penalty(self, cr, uid, ids, field_name, arg, context=None):
if not ids: return {}
res = {}
for id in ids:
res[id] = 20.0
for line in self.browse(cr, uid, ids, context=context):
if line.picking_id:
if line.picking_id.purchase_id:
if line.picking_id.purchase_id.penalty_id:
res[line.id] = 10.0
return res
_columns = {
'value_forpenalty': fields.float('Value', digits=(16,2)),
'actual_penalty': fields.function(_penalty, type='float', digits=(16,2), string='Penalty', store=True, select=True)
}
stock_move_custom()
Note: penalty_id is a many2one added to a custom child of purchase.order.
Q1. All I get is a 0 for penalty. Neither 20 nor 10. What could be wrong? If it is because of ids being blank, how do I get around that?
Q2. How do I pass the value_forpenalty to the the function as I will eventually need it to calculate the penalty? So when a user enters value for the value_forpenalty field in the form (and press a calculate button, or ideally without that), the value should get passed to the function for calculation.
Thanks
I your code work as you accepted, no problem in your code.
Can you restart your server and check again.
for line in self.browse(cr, uid, ids, context=context):
if line.picking_id and line.picking_id.purchase_id and line.picking_id.purchase_id.penalty_id:
res[line.id] = 10.0
And passing your argument value_forpenalty, you can get this value in you function from line
like
res[line.id] = line.value_forpenalty
Hope this helpful to you