How to make functional field editable in Openerp?
When we create
'capname': fields.function(
_convert_capital, string='Display Name', type='char', store=True
),
This will be displayed has read-only and we can't able to edit the text.
How we make this field has editable?
A computed field has a function that automatically calculates it's value on some source data.
It is possible to add it the inverse operation, updating the source data based on a value manually set on it, thus making it editable.
From the documentation:
to allow setting values on a computed field, use the inverse parameter. It is the name of a function reversing the computation and setting the relevant fields:
Example code:
document = fields.Char(compute='_get_document', inverse='_set_document')
def _get_document(self):
for record in self:
with open(record.get_document_path) as f:
record.document = f.read()
def _set_document(self):
for record in self:
if not record.document: continue
with open(record.get_document_path()) as f:
f.write(record.document)
You must add a inverse function to make the field editable. This parameter is called fnct_inv in OpenERP v7. An example:
def _get_test(self, cr, uid, ids, name, args=None, context=None):
result = dict.fromkeys(ids, False)
for line in self.browse(cr, uid, ids, context=context):
if line.test:
result[line.id] = line.test
return result
def _set_test(self, cr, uid, id, field_name, field_value, args=None, context=None):
obj = self.browse(cr, uid, id)
for record in obj:
if record.test != field_value:
# The record already exists
...
cr.execute(
'UPDATE your_table '
'SET test=%s '
'WHERE id=%s', (field_value, id)
)
else:
# It is a new record
# (or the value of the field was not modified)
return True
_columns = {
'test': fields.function(
string='String for testing',
fnct=_get_test,
fnct_inv=_set_test,
type='char',
size=50,
store=True,
),
}
Related
I am trying to change the value of my selection field using on_change. I have the code below.
.xml
<field name="product_id" on_change="onchange_partner_id_override(product_id, context)"
.py
class sale_order_line(osv.osv):
_inherit = "sale.order.line"
_columns = {
'product_id': fields.many2one('product.product', "Product"),
'price_select': fields.selection(SELECT_PRICE, "Unit Price"),
}
def product_id_change_override(self, cr, uid, ids, product, context=None):
result = []
product_obj = self.pool.get('product.product')
product_obj = product_obj.browse(cr, uid, product, context=context_partner)
global SELECT_PRICE
SELECT_PRICE = [
('sale_price', product_obj.list_price),
('dist_price', product_obj.distributor_price),
('emp_price', product_obj.employee_price),
]
# How could I change the value of my selection field 'price_select'
return {'value': result}
But i don't know the syntax on how to append this data on my selection field.
Could someone help me Please !
You need to override product_id_change method and specify the value of price_select field in value dict:
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty,
uom, qty_uos, uos, name, partner_id,
lang, update_tax, date_order, packaging, fiscal_position, flag, context)
res['value'].update({'price_select': 'emp_price'})
return res
I've been trying to copy over certain fields from the hr_expenses form into my custom module, purchase_orders.
The below method was written for me to do this in the extended hr_expenses.py file:
def po_generator(self, cr, uid, ids, arg, context=None):
res = {}
for expense in self.browse(cr, uid, ids, context=context):
expense_line = self.pool.get('hr.expense.line')
purchase_orders = self.pool.get('purchase.orders')
for line in expense.line_ids:
expense_line_record = expense_line.search(cr, uid, [('id', '=', line.id)], context=context)
# pdb.set_trace()
purchase_orders.create(cr, uid,
{
'submitted_employee_name':expense.employee_id,
'dateofexpense':expense_line.date_value,
'project_id_expense':expense_line.project_id,
'Description':expense_line.name,
'netamount':expense_line.product_exc_VAT,
'raised_employee_name':expense.employee_id,
'project_id_account_type':expense_line.project_id_account_type,
},
context
)
return res
However, when I tru to execute this piece of code, OpenERP gives me an 'AttributeError' with the traceback:
File
"/opt/openerp/custom_modules/legacy_expense_po/legacy_expense.py",
line 121, in po_generator
'dateofexpense':expense_line.date_value, AttributeError: 'hr.expense.line' object has no attribute 'date_value'
I'm presuming this has something to do with the line_ids field in the Expenses form. I'm trying to get each row in the line_ids and enter these as new records in the purchase_orders table.
Thanks.
#Sagar Mohan
You are doing vary basic mistake here.
You are already looping on browse record by saying statement
for line in expense.line_ids:
When you say expense.line_ids this will already pull all related o2m record you don't need to search again by writing statement expense_line_record = expense_line.search(cr, uid, [('id', '=', line.id)], context=context) and you must know that search in v7 return then only integer id of the matching ids not recordset or browse record.
Correct code is :
def po_generator(self, cr, uid, ids, arg, context=None):
res = {}
purchase_orders = self.pool.get('purchase.orders')
for expense in self.browse(cr, uid, ids, context=context):
expense_line = self.pool.get('hr.expense.line')
purchase_orders = self.pool.get('purchase.orders')
for line in expense.line_ids:
purchase_orders.create(cr, uid,
{
'submitted_employee_name':line.employee_id.name,
'dateofexpense': line.date_value,
'project_id_expense': line.project_id.id,
'Description': line.name,
'netamount': line.product_exc_VAT,
'raised_employee_name': expense.employee_id.name,
'project_id_account_type': line.project_id_account_type,
},
context
)
return res
This code might need correction based on your need but you see that line is direct browse variable so you just need to . and access the field.
and one more note here that you never use self.pool.get inside loop that make your code heavy.
Thanks
I am trying to create a function field which will get the current membership type of a member and store it in a new field in res.partner. However this code is not getting called whenever I am creating or editing membership of a member. But if I remove the store attribute the functional field works just as expected. Note that I am reusing the membership module of openerp and using odoo8 now. I am attaching the code, please let me know where am I going wrong. I need this method to be called atleast when I am using the store attribute. Am I using the store attribute incorrectly:
from openerp.osv import osv, fields
class partner_member(osv.Model):
'''Partner'''
_inherit = 'res.partner'
def _get_membership_type(self,cr,uid,ids,context=None):
member_line_obj = self.pool.get('membership.membership_line')
partner_list = []
for line in member_line_obj.browse(cr, uid, ids, context=context):
if line.state == 'paid':
partner_list.append(line.partner.id)
return partner_list
def _current_membership(self, cr, uid, ids, field_name= None, arg=False, context=None):
res_obj = self.pool.get('res.partner')
res_data_obj = res_obj.browse(cr, uid, ids, context=context)
res=dict()
for member in res_data_obj:
if member.member_lines:
for lines in member.member_lines:
if (lines.state == 'paid'):
res[member.id] = lines.membership_id.name_template
break
else:
res[member.id] = 'None'
else:
res[member.id] = 'None'
return res
_columns = {
'current_membership':
fields.function(_current_membership,type='char',
string='Current Membership Type',
store = {
'membership.membership_line':
(_get_membership_type, ['state'], 10)
},
help="Shows the current membership of a user"),
}
You made a mistake on the _get_membership_type() method. Indeed, you return only the list of res.partner that are in a line with state == 'paid'.
I think you must return all the partner that are in lines no matter the state of the line.
def _get_membership_type(self,cr,uid,ids,context=None):
member_line_obj = self.pool.get('membership.membership_line')
partner_list = []
for line in member_line_obj.browse(cr, uid, ids, context=context):
partner_list.append(line.partner.id)
return partner_list
If you want your function _current_membership to be a method of your class (as you did) you need to add the method=True parameter to your field definition:
_columns = {
'current_membership':
fields.function(_current_membership,type='char',
string='Current Membership Type',
store = {
'membership.membership_line':
(_get_membership_type, ['state'], 10)
},
help="Shows the current membership of a user",
method=True),
}
That should resolve your problem.
Certainly you can simply use store=True to have your field recalculated on every change in whatever field of your object.
I need to change the state of a invoice using it's payment method.
def _payment_type_get(self, cr, uid, ids, field_name, arg, context={}):
result = {}
invoice_obj = self.pool.get('account.move.line')
for rec in self.browse(cr, uid, ids, context):
result[rec.id] = (0, 0)
invoice_id = invoice_obj.search(cr, uid, [(
'move_id', '=', rec.move_id.id)], context=context)
if invoice_id:
inv = invoice_obj.browse(cr, uid, invoice_id[0], context)
if inv.payment_type:
result[rec.id] = (inv.payment_type.id, self.pool.get(
'payment.type').browse(cr, uid, inv.payment_type.id, context).name)
else:
result[rec.id] = (0, 0)
return result
if result != '1':
return self.write(cr, uid, ids, {'state_cheque': 'usado'})
else:
return self.write(cr, uid, ids, {'state_cheque': 'caixa'})
I need to get the payment type at the creation of the "cheque", during the invoice closing, so I can set it to Caixa, if it's a Cheque or to Usado if it is not. I don't know if all the names are correct, since I copied it from a guy here who said it would(Shame on me if I let it pass).
The Cheque, like any payment is saved at a journal, cheque is saved at an specific journal with it's name(ChequeJournal), if I can use that to create the default state, It would be better.
Every single way I tried to do it, failed. Recently I've found that the payment type is saved as a int and not as a char or string, but changing it still give no results.
I could not use a self.write , since I'm editing the account_move_line.py, OpenERP can't find what I'm trying to add the state to. So, I need to get the invoice ID in order to change that state. A new problem arises?
Once a return statement is called, the function immediately exits, so your last 4 lines aren't being executed. (Or maybe that's a formatting error?)
I have a module that has, a creation date (of course, the day it was created) and a deadline date.
The thing is that I want to be able to set a default value to this deadline date according to the date it was created.
But I want to be able to configurate this dynamically from (lets say) res_config.
e.g.
If I configured the default values in res_config to 5 days, I want the default value for the deadline date to be populated with a date 5 days ahead of the creation date.
Is this possible?
Thank you
I managed to do this using the model ir.configure_parameter.
In res_config.py:
class my_configuration(osv.osv_memory):
_inherit = ['res.confi.settings']
_columns = {
'default_deadline' : fields.integer('Days per default', help="""Help field"""),
}
...
def set_default_deadline(self, cr, uid, ids, context=None):
config = self.browse(cr, uid, ids)
config = config and config[0]
val = '%s' %(config.default_deadline) or '10'
self.pool.geet('ir.config_parameter').set_param(cr,uid, 'key_value', val)
return True
Whit this we have created a system parameter. It is actually created as a mapping from 'key_value' to val that is a string, so we will have to cast it to the desired type when necessary.
In my case, y created a function to get the deadline date in my module:
def _get_deadline_date(self, cr, uid, context=None):
val = self.pool.get('ir.config_parameter').get_param(cr, uid, 'key_value')
try:
val = int(val)
except:
# Just in case...
val = 30
return (datetime.now() + timedelta(days=val)).strftime('%Y,%m,%d')
_defaults = {
'deadline_date': lambda s, cr, uid, c: s._get_deadline_date(self, cr, uid, context=c),
}
Thank you, hope it helps!