Odoo IndexError: list assignment index out of range - odoo

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

Related

openerp function field not working - OpenERP v7

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.

What do I return for function field value?

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.

Openerpv7: Numbeing in OrderLine

I'm using OpenERP v7 and requesting this below output in Purchase order line window
PO0001 PO0002 PO0003
Line Line Line
10 10 10
20 20 20
30 30
My code:
<field name="order_line" context="{'order_id':active_id}">
_columns={
'sequence':fields.integer('Sequence', store=True),
}
_defaults = {
lambda obj, cr, uid, context: obj._default_sequence(cr, uid, context)
}
def _default_sequence(self, cr, uid, context=None):
if context is None:
context = {}
max_sequence = 0
if context.get('order_id'):
order_line = self.search(cr, uid, [('order_id', '=', context['order_id'])])
if order_line:
max_sequence = max([line['sequence'] for line in self.read(cr, uid, order_line, ['sequence'])])
return max_sequence + 10
But im getting this kind of output . Any advice would be greatful.
PO0001 PO0002 PO0003
Line Line Line
10 10 10
10 10 10
10 10
Anyone could help me to achive the required output.
I think you are doing wrong. A record will be created only after you click on any button action(button other than adding the lines) for the first time for the record. Then only you will be able to make the search. I hope default will get the context even if we don't specify context. Still not getting the context, then try by following the answer given by Andrei Boyanov.Also please understand that field names like active, state, sequence etc have some super powers in openerp. For example if a table have a field "sequence", then the table's tree view will have a drag and drop functionality and if we do the drag and drop functionality, then a new sequence for each record in the table will be automatically calculated and saved.
So my opinion is not to use the sequence field. Use any other field name. Then write a on_change method to your one2many field and pass the one2many field name as the attribute to the on_change method. Then in the on_change method check what all values are coming when you add a new line. If the new line's value is in the format (0,0,dictionary_with_fields_as_keys_and_its_values_as_values).Then to this dictionary add the sequence_number with the value.For example:
<field name="order_line" on_change="onchange_line(order_line)">
def onchange_line(self, cr, uid, ids, lines,context=None):
result = {}
result['value'] = {}
#do the proper checking
count_dict = {}
count = 10
had_seq = 0
for index,line in enumerate(lines):
if line[0] == 0:
count_dict[index] = count
count +=10
else:
had_seq +=1
#seqnece_no is the new sequence field defined
for k in count_dict:
if had_seq:
lines[k][2]['sequence_no'] = had_seq*10 + count_dict[k]
else:
lines[k][2]['sequence_no'] = count_dict[k]
result['value'].update({'order_line':lines})
return result
Please try it.
How do you execute _default_sequence(...) ? I suppose you intend to invoke it trough the _defaults dictionary. In this case correct it as follow:
_defaults = {
'sequence': lambda obj, cr, uid, context: obj._default_sequence(cr, uid, context)
}
In your code you omitted the key sequence. In fact what you defined is not a dictionary but a set with one element - the lambda function.
Better, you can define it just like this:
_defaults = {
'sequence': _default_sequence
}
change your Python file by
def _default_sequence(self, cr, uid, context=None):
if not context: context = {}
max_sequence = 0
if context.get('order_id'):
order_line = self.search(cr, uid, [('order_id', '=', context['order_id'])])
if order_line:
max_sequence = max([line['sequence'] for line in self.read(cr, uid, order_line, ['sequence'])])
return max_sequence + 10
_columns={
'sequence':fields.integer('Sequence'),
}
_defaults = {
'sequence': _default_sequence
}
No need to put store=True in the integer field, it will always store value in the database.

openerp fields.function not affecting value

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

save into another table

oI select same field from mo.queue and I want save it into the procurement.order table
My code looks as follows:
def action_ship_create(self, cr, uid, ids, id_queue, context=None):
queue_obj = self.pool.get('mo.queue'). browse (cr, uid, id_queue, context=context)
mo_name = queue_obj.name
query_param = (mo_name)
cr.execute("select origin,create_date,product_uos_qty,product_qty,name,city from mo_queue",(query_param,))
ads = cr.fetchone()
name = ads and ads [0] or None
print "======================"
print name
print "======================"
val = { 'origin': name,
}
print "======================"
print val
print "======================"
return {'value': val }
proc_id = self.pool.get('procurement.order').create(cr, uid, {
'origin':origin,
})
proc_ids.append(proc_id)
The result of the print is:
print name = SO013
print val = {'origin': u'SO013'}
But the data is not inserted into the procurement.order table.
your code me look like this after return statement is does not executes anything do put cdeo before return and your code need lot of tuning, like do not use SQL Injection it is not good idea.
def action_ship_create(self, cr, uid, ids, id_queue, context=None):
queue_obj = self.pool.get('mo.queue'). browse (cr, uid, id_queue, context=context)
queue_model = self.poo.get(queue_obj.name)
procurement_pool = self.pool.get('procurement.order')
qsids = queue_model.search(cr, uid, )
for record in queue_model.browse(cr, uid, qsids):
if record.origin:
#this will crate a new record the table procurement.order so
#field values may be not enough so you can update logic
#and If you want to update record value you need a proc ids and you can do it.
procurement_pool.create(cr, uid, {'origin':record.origin})
return {'value': {'origin': record.origin}}
Hope this will help you let me know i I am missing.
Thank You