In my module i have the following many2one field:
'xx_insurance_type': fields.many2one('xx.insurance.type', string='Insurance')
where xx.insurance.type is the following:
class InsuranceType(osv.Model):
_name='xx.insurance.type'
_columns = {
'name' : fields.char(size=128, string = 'Name'),
'sale_ids': fields.one2many('sale.order', 'xx_insurance_type', string = 'Sale orders'),
'insurance_percentage' : fields.float('Insurance cost in %')
}
I know the many2one field takes the name field as its display name but I would like to have it use the combination of name and insurance_percentage in the form of name + " - " + insurance_percentage + "%"
I read it is best to overwrite the get_name method so I tried the following:
def get_name(self,cr, uid, ids, context=None):
if context is None:
context = {}
if isinstance(ids, (int, long)):
ids = [ids]
res = []
for record in self.browse(cr, uid, ids, context=context):
name = record.name
percentage = record.insurance_percentage
res.append(record.id, name + " - " + percentage + "%")
return res
and placed this inside the ÌnsuranceType` class.
Since nothing happened:
Do i have to place it inside the main class containing the field? If so, is there an other way to do this since that will probably also change the display ways of the other many2one fields?
If you don't want to alter the display name of the rest of the many2one related to the model xx.insurance.type, you can add a context in the XML view to the many2one whose display name you want to modify:
<field name="xx_insurance_type" context="{'special_display_name': True}"/>
And then, in your name_get function:
def name_get(self, cr, uid, ids, context=None):
if context is None:
context = {}
if isinstance(ids, (int, long)):
ids = [ids]
res = []
if context.get('special_display_name', False):
for record in self.browse(cr, uid, ids, context=context):
name = record.name
percentage = record.insurance_percentage
res.append(record.id, name + " - " + percentage + "%")
else:
# Do a for and set here the standard display name, for example if the standard display name were name, you should do the next for
for record in self.browse(cr, uid, ids, context=context):
res.append(record.id, record.name)
return res
#api.depends('name', 'insurance_percentage')
def name_get(self):
res = []
for record in self:
name = record.name
if record.insurance_percentage:
name = '[' + record.insurance_percentage+ ']' + name
res.append((record.id, name))
return res
Related
I want to override a original field function in Odoo.
According to the answer here: Odoo: How to override original function
i just have to define exactly the same method as in the original model. So here is my code:
class paiement_client_difference_montant(models.Model):
_inherit="account.voucher"
#writeoff_amount=fields.Float(compute='_get_writeoff_amount')
def _get_writeoff_amount(self, cr, uid, ids, name, args, context=None):
print '_get_writeoff_amount _inherit'
if not ids: return {}
currency_obj = self.pool.get('res.currency')
res = {}
for voucher in self.browse(cr, uid, ids, context=context):
debit = credit = 0.0
sign = voucher.type == 'payment' and -1 or 1
for l in voucher.line_dr_ids:
debit += l.amount
for l in voucher.line_cr_ids:
credit += l.amount
currency = voucher.currency_id or voucher.company_id.currency_id
res[voucher.id] = currency_obj.round(cr, uid, currency, voucher.amount - sign * (credit - debit))
return res
But that code is never reached.
Any help please. Thank you.
You have to override that field again in your class, to execute this newly created method.
I added a module "Base Candidat" in this module base.candidat I want to open the applications of a specific candidate (that have the same email as the candidate ) I added this function to base_candidat.py
class base_candidat(osv.osv):
_columns = {
'candidat_name': fields.char('Candidat', size=128, required=True),
'blacklist': fields.boolean('Blacklist'),
'email_candidat': fields.char('Email', size=32),
'mobile': fields.char('Mobile', size=32),
'priority': fields.selection(AVAILABLE_PRIORITIES, 'Appreciation'),
'user_id': fields.many2one('res.users', 'Responsable'),
'specialite': fields.many2one('base.candidat.specialite', 'Spécialité'),
}
def action_get_applications(self, cr, uid, ids, context=None):
modelDataClass = self.pool.get('ir.model.data')
hrApplicantClass = self.pool.get('hr.applicant')
model, action_id = modelDataClass.get_object_reference(cr, uid, 'hr_recruitment', 'action_hr_job_applications')
action = self.pool.get(model).read(cr, uid, action_id, context=context)
email_ids = self.browse(cr, uid, ids[0], context).email_candidat
candidature_ids = hrApplicantClass.search(cr, uid, [('email_from', '=', email_ids)], context=context)
action['context'] = {'default_res_model': self._name, 'default_res_id': ids[0]}
action['domain'] = str([('candidature_ids', 'in', email_ids)])
return action
I have no result . Any suggestions??
If I know well, 'action' is an unallowed variable name. If you use it, the program will be not consistent. (Same situation with 'active')
In my opinion, this domain expression is not correct in this line:
action['domain'] = str([('candidature_ids', 'in', email_ids)])
Because this mean you model has candidature_ids field, but the model has not, so this condition can't satisfied, so you can't see any record, when you use it.Another problem with your conception, email_ids is string (not number, so the variable name is deceptive)and candidature_ids is a list of numbers.
In my opinion, you want to write a function field. This is an example code, it may not the optimum performance, but I think it will help you understanding the essential of function field:
def _getApplications(self, cr, uid, ids):
hrApplicantClass = self.pool.get('hr.applicant')
# get all of candidate
candidateDatas = self.read(cr, uid, ids, ['email_candidat'])
# collect all of emails
emails = []
for candidate in candidateDatas:
if candidate['email_candidat'] not in emails:
emails.append(candidate['email_candidat'])
# get all of relevant applicant
applicantIds = hrApplicantClass.search(cr, uid, [('email_from', 'in', emails)])
applicantDatas = hrApplicantClass.read(cr, uid, applicantIds, ['email_from'])
# pair base_candidat id with application id
retVal = {}
for candidate in candidateDatas:
retVal[candidate['id']] = []
if not candidate['email_candidat']:
continue
else:
for applicant in applicantDatas:
if applicant['email_from'] == candidate['email_candidat']:
retVal[candidate['id']].append(applicant['id'])
return retVal
# the field definition
'application_ids': fields.function(_getApplications, method=True, type='one2many', 'Applications')
My code:
class SaleOrder(osv.Model):
_inherit = 'sale.order'
_columns = {
'xx_delivery_date': fields.date(string='Delivery date'),
'xx_payment_method': fields.many2one('xx.payment.method',
string='Payment method'),
'xx_insurance_type': fields.many2one('xx.insurance.type', string='Insurance')
}
def _amount_insurance(self, cr, uid, val1, context=None):
val = 0.0
insurance_chosen = self.pool.get('xx.insurance.type').browse(cr, uid, insurance_percentage.id,context=context)
val = val1*insurance_chosen/100
return val
class InsuranceType(osv.Model):
_name='xx.insurance.type'
_columns = {
'name' : fields.char(size=128, string = 'Name'),
'sale_ids': fields.one2many('sale.order', 'xx_insurance_type', string = 'Sale orders'),
'insurance_percentage' : fields.float('Insurance cost in %')
}
I am trying to get the float from the 'insurance_percentage' field and add this percentage to val1.
At the moment my code results in
'Global name insurance_percentage not defined,
So I have to somehow tell the function to take the variable from the InsuranceType class but I don't know how to do this.
For many2one field, we need to first take id of that record and than browse that record with id and take desire value from that.
Try with this code:
def _amount_insurance(self, cr, uid, ids, val1, context=None):
val = 0.0
for insurance in self.browse(cr, uid, ids,context=context):
if insurance.xx_insurance_type:
val = (val1 * (insurance.xx_insurance_type.insurance_percentage/100))
return val
I need to do two activities in my activity method.
one is need to return value for total_workers field.but need to return ID also because its necessary requirement in OpenERP when we override that method.
then have to return 2 things.please advice me how to implement this in my form.
with one return value this is worked for both things.but need to return both.
def create(self, cr, uid, values, context=None):
name = 'CheckRoll No = ' + str(values['checkroll_no']) + ' & Gang No = ' + str(values['gang_no'])
values.update({'name': name})
total_tea_workers = 0
offer_id = super(bpl_work_offer, self).create(cr, uid, values, context=context)
tea_worker_obj = self.browse(cr, uid, offer_id, context=context) or []
tea_worker_ids = self.pool.get('bpl.selected.tea.workers.line').search(cr, uid, [('tea_line_worker_id', '=', tea_worker_obj.id)])
for tea_worker in self.pool.get('bpl.selected.tea.workers.line').browse(cr, uid, tea_worker_ids):
if tea_worker.is_selected:
total_tea_workers += 1
return {'value': {'total_workers': total_tea_workers}}
return offer_id
EDITED
I sort it out in this way.hope this will help for others
:-)
i wrote a function for my field
def _compute_workers(self, cr, uid, ids, fieldname, arg, context=None):
total_workers = total_tea_workers = total_rubber_workers = total_sundry_workers = total_other_workers = 0
res = dict.fromkeys(ids, False)
for this in self.browse(cr, uid, ids, context=context):
tea_worker_ids = self.pool.get('bpl.selected.tea.workers.line').search(cr, uid, [('tea_line_worker_id', '=', this.id)])
for tea_worker in self.pool.get('bpl.selected.tea.workers.line').browse(cr, uid, tea_worker_ids):
if tea_worker.is_selected:
total_tea_workers += 1
rubber_worker_ids = self.pool.get('bpl.selected.rubber.workers.line').search(cr, uid, [('rubber_line_worker_id', '=', this.id)])
for rubber_worker in self.pool.get('bpl.selected.rubber.workers.line').browse(cr, uid, rubber_worker_ids):
if rubber_worker.is_selected:
total_rubber_workers += 1
sundry_worker_ids = self.pool.get('bpl.selected.sundry.workers.line').search(cr, uid, [('sundry_line_worker_id', '=', this.id)])
for sundry_worker in self.pool.get('bpl.selected.sundry.workers.line').browse(cr, uid, sundry_worker_ids):
if sundry_worker.is_selected:
total_sundry_workers += 1
other_worker_ids = self.pool.get('bpl.selected.other.workers.line').search(cr, uid, [('other_line_worker_id', '=', this.id)])
for other_worker in self.pool.get('bpl.selected.other.workers.line').browse(cr, uid, other_worker_ids):
if other_worker.is_selected:
total_other_workers += 1
total_workers = total_tea_workers + total_rubber_workers + total_sundry_workers + total_other_workers
res[this.id] = total_workers
return res
i changed my integer field to functional field
'total_workers': fields.function(_compute_workers, type="integer", string="Total Workers"),
You should never return anything else in create() except the ID of the record that was created. Usually this is done by returning the result of the call to the parent via super(myclass, self).create(...) indeed.
It's not clear what you are trying to achieve with your total_workers code. If total_workers is supposed to be a computed field, you don't have to override create at all: just declare this column as a fields.function and put the code to compute it in the corresponding function.
For example:
def _compute_workers(self, cr, uid, ids, fieldname, arg, context=None):
result = dict.fromkeys(ids, False) # default result for each id
for this in self.browse(cr, uid, ids, context=context):
# let's assume you have a one2many called worker_ids
result[this.id] = len(this.worker_ids)
return result
_columns = {
'total_workers': fields.function(_compute_workers, type="integer",
string="Total Workers")
}
At this point it would be a good idea to have a good look at the OpenERP technical memento and the OpenERP framework documentation, to get an overview of the OpenERP API and how it is supposed to be used :-)
Once you have a good understanding of the structure of models, the various field types, the CRUD methods and the inheritance patterns, you should be able to quickly browse the source code of the official modules and find examples of anything you want to accomplish. This should make your life much more easier!
I think that you're doing the counting of the workers in a very inefficient manner.
You're doing your SQL filter to obtain each of the workers matching an ID, and then testing for a single flag within them.
I think it would be much more efficient to just add another criteria to your select statement.
total_tea_workers = self.pool.get('bpl.selected.tea.workers.line').search(cr, uid, [('tea_line_worker_id', '=', id), ('is_selected', '=', True)]), count=True)
I want to calculate the value of a function field using its previous value ( = value of the record with previous id)
'testrest' : fields.function(get_reste, method=True, string='Restant',type='integer'),
def get_reste(self, cr, uid, ids, field_name, arg, context):
x = {}
for record in self.browse(cr, uid, ids ,context):
if record.statut != 'entree':
x[record.id]= a + record.entree_nbr # a should be the same field for the previous record
How can I do that? thank you
First point here about OE 6.1+ and fields.function() : it does not take a method parameter anymore [ Server rev 3495 revid odo#openerp.com-20110701232328-flgxulxva70vnyxr and addons rev 4844].So please do not use the "method" parameter anymore!
Now you want to calculate the value based on previous value so what you can do is you can use store=True param here that will store your previous value in data now in your calculation for your record you can read previous value and calculate new value and return it.
'testrest' : fields.function(get_reste, store=True, string='Restant',type='integer'),
def get_reste(self, cr, uid, ids, field_name, arg, context):
x = {}
for record in self.browse(cr, uid, ids ,context):
if record.statut != 'entree':
x[record.id]= record.testrest + record.entree_nbr
return x
Here benefit of string will be you can use this value any where out side OE or fro some external reporting tool and you can even expoer this field.
Hope this will help.
Some More Code :
'price': fields.function(_price_get, method=True, string="Price", store=True),
def get_reste(self, cr, uid, ids, field_name, arg, context):
x = {}
a = 0.0
for record in self.browse(cr, uid, ids ,context):
if record.statut != 'entree':
x[record.id]= a + record.entree_nbr
a =record.testrest
return x
If you need you can sort the list of ids by ids.sort()