I'm inherit purchase.order.line and try change value in field. For product_qty I can change value but for price_unit I can't change value.
My custom .py file:
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
#api.onchange('product_id')
def my_fucn(self):
for rec in self:
rec.product_qty = 10 #WORKING
rec.price_unit = 1 #NOT WORKING
Maybe is problem because in original purcahase.py odoo file also have #api.onchange('product_id').
Any solution?
You can't predict which onchange method will be triggered first or last, but the original onchange method for product_id changes in purchase.order.line is setting the price_unit field, but not the product_qty field.
So it seems your method is called before the other one, because price_unit is overwritten. You can check that by debugging both methods.
What to do now? I would prefer the extension of the original method:
#api.onchange('product_id')
def the_original_method(self):
res = super(PurchaseOrderLine, self).the_original_method()
# your logic here
return res
In your case a product_qty change will trigger another onchange event. Always have in mind, that field changes can trigger onchange events and field recomputations.
Try to extend both methods:
#api.onchange('product_id')
def onchange_product_id(self):
res = super(PurchaseOrderLine, self).onchange_product_id()
# your logic here
for rec in self:
rec.product_qty = 10 # will trigger _onchange_quantity() on return
return res
#api.onchange('product_qty', 'product_uom')
def _onchange_quantity(self):
res = super(PurchaseOrderLine, self)._onchange_quantity()
# your logic here
for rec in self:
rec.price_unit = 1.0
return res
Related
class SunOrder(models.Model):
_name = 'sun.order'
manufacture_id = fields.Many2one(
'product.product',
#api.model
def create(self, vals):
Sequence = self.env['ir.sequence']
vals['name'] = Sequence.next_by_code('sun.order')
return super(SunOrder, self).create(vals)
here is simple create method that i use when creating data in my module.
the goal is to create quotation with same CREATE method with same name and samemanufacture_id.I mean when i creat sun.order i need that the same time quotation would be created. So maybe some 1 can give me example or general idea how it can be done. because i have no clue.
class pos_quotation(models.Model):
_name = "pos.quotation"
name = fields.Char('Name')
manufacture_id = fields.Many2one(
'product.product',
You can rewrite your create method as follows:
#api.model
def create(self, vals):
Sequence = self.env['ir.sequence']
vals['name'] = Sequence.next_by_code('sun.order')
#set your pos_quotation dictionary
vals_quot = {'manufacture_id': vals['manufacture_id'],
#... other fields for pos.quotation model
}
self.env['pos.quotation'].create(vals_quot)
return super(SunOrder, self).create(vals)
I hope this help you.
How can i get selection fields value in odoo 10?
def compute_default_value(self):
return self.get_value("field")
I tried this,
def compute_default_value(self):
return dict(self._fields['field'].selection).get(self.type)
Also tried this,but it is not working.
Please help me, i could not find the solution.
Thank you.
You can do this in a following manner:
self._fields['your_field']._desription_selection(self.env)
This will return the selection list of pairs (value, label).
If you just need possible values, you can use get_values method.
self._fields['your_field'].get_values(self.env)
But it's not a common way. Most of the time people define selections differently and then use those definitions. For example, I commonly use classes for those.
class BaseSelectionType(object):
""" Base abstract class """
values = None
#classmethod
def get_selection(cls):
return [(x, cls.values[x]) for x in sorted(cls.values)]
#classmethod
def get_value(cls, _id):
return cls.values.get(_id, False)
class StateType(BaseSelectionType):
""" Your selection """
NEW = 1
IN_PROGRESS = 2
FINISHED = 3
values = {
NEW: 'New',
IN_PROGRESS: 'In Progress',
FINISHED: 'Finished'
}
You can use this class wherever you want, just import it.
state = fields.Selection(StateType.get_selection(), 'State')
And it's really handy to use those in the code. For example, if you want to do something on a specific state:
if self.state == StateType.NEW:
# do your code ...
I don't get the question fully, but let me try to answer. Why not just define the selection as method and use it for both situations:
from datetime import datetime
from odoo import models, fields
class MyModel(models.Model):
_name = 'my.model'
def month_selection(self):
return [(1, 'Month1'), (2, 'Month2')]
def compute_default_value(self):
selection = self.month_selection()
# do whatever you want here
month = fields.Selection(
selection=month_selection, string='Month',
default=datetime.now().month, required=True)
I added the part number field in product template model
partnumber = fields.Char(
'Part Number', compute='_compute_partnumber',
inverse='_set_partnumber', store=True)
I write the function like internal reference code
#api.depends('product_variant_ids', 'product_variant_ids.partnumber')
def _compute_partnumber(self):
unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1)
for template in unique_variants:
template.partnumber = template.product_variant_ids.partnumber
for template in (self - unique_variants):
template.partnumber = ''
#api.one
def _set_partnumber(self):
if len(self.product_variant_ids) == 1:
self.product_variant_ids.partnumber = self.partnumber
I successfully added part number in product form.I used above methods for name get(to get part number in product description)
My problem is the part number could not saved in create method.
the field only saved in edit mode.
As "dccdany" already said in his comment, the creation order is a bit tricky on templates. You can see it in the code. First the template will be created. The partnumber won't be set, because there is no variant existing at that point.
After template creation, the variants will be created (one line later) without partnumber, so there will be no partnumber after template creation.
What can you do? Just overwrite product.template create(), like:
#api.model
def create(self, vals):
template = super(ProductTemplate, self).create(vals)
if 'partnumber' in vals and len(template.product_varient_ids) == 1:
template.partnumber = vals.get('partnumber')
return template
I have added this fields under account.invoice in order to get an autoincrement number but it doesn't work.
Help me please to figure out my error
Example Code
class invoice(osv.osv):
_inherit = 'account.invoice'
def _get_increment(self, cr, uid, ids, fields, arg, context=None):
if context is None: context = {}
res = {}
if type == 'out_invoice':
ids = self.search(cr,uid,[('id','!=',False),('type','in',('out_invoice','out_refund'))])
if ids:
last_id = ids and max(ids)
print 'last_id',last_id
for invoice in self.browse(cr, uid, last_id, context):
print 'invoice', invoice
if invoice.name1:
res[invoice.id] = invoice.name1
else :
res[invoice.id] = invoice.name1 + 1
return res
_columns={
'name1':fields.function(_get_increment, type='integer', string='Name1'),
}
First of all. Your function never returns a value since type is never set.
Which means the if condition is never triggered.
At second. I'd suggest that you'd use the new Odoo API.
function fields are replaced by the compute attribute on fields and the declaration no longer takes place in the _columns dictionary.
New API
instead of importing from openerp.osv you should import the following:
from openerp import fields, models, api
The code would look like this:
from openerp import fields, models, api
class invoice(models.Model):
_inherit = 'account.invoice'
name1 = fields.Integer('Name1', compute='_get_increment')
#api.one
def _get_increment(self):
self.name1 = 1 + 1 #This value should be the value that you've calculated
the only thing you need to do in the method _get_increment is set self.name1.
In the new API self is a record. So self.id would get you the id of the record and so on.
In Odoo 8, is there a preferred method for standardizing field values on create or write? Several methods come to mind, but this functionality seems like it belongs in the API. Essentially, I am wanting to create a field that specifies a standardize function, somewhat like a compute field that only specifies an inverse function. Does this already exist somewhere in the API?
Method 0: Create a field that specifies a standardize function.
The only flaw that I can see with this method is that the API does not exist.
import openerp
class Model(openerp.models.Model):
_name = 'addon.model'
field = openerp.fields.Text(
required=True,
standardize='_standardize_field',
)
#openerp.api.one
def _standardize_field(self):
self.field = self.field.upper()
Method 1: Override the create and write methods to insert a call to standardize the field.
This works, but seems rather verbose for what could be done with a single function, above. Note that the constraint is required if required=True and the standardization might yield an empty field.
import openerp
class Model(openerp.models.Model):
_name = 'addon.model'
field = openerp.fields.Text(
required=True,
)
#openerp.api.one
#openerp.api.constrains('field')
def _constrains_field(self):
if len(self.field) == 0:
raise openerp.exceptions.ValidationError('Field must be valid.')
def _standardize(self, args):
if 'field' in args:
# Return standardized field or empty string.
args['field'] = args['field'].upper()
#openerp.api.model
def create(self, args):
self._standardize(args)
return super(Model, self).create(args)
#openerp.api.multi
def write(self, args):
self._standardize(args)
super(Model, self).write(args)
return True
Method 2: Use a computed field and a bit of magic.
This works but feels a bit contrived. In addition, this method requires that the standardization function is deterministic, or this may create an infinite loop. Note that the standardization function may be called twice, which could be a concern if standardization is an expensive operation.
import openerp
class Model(openerp.models.Model):
_name = 'addon.model'
field = openerp.fields.Text(
compute=lambda x: x,
inverse='_inverse_field',
required=True,
store=True,
)
#openerp.api.one
#openerp.api.constrains('field')
def _constrains_field(self):
if self._standardize_field() is None:
raise openerp.exceptions.ValidationError('Field must be valid.')
def _inverse_field(self):
field = self._standardize_field()
# If the field is updated during standardization, this function will
# run a second time, so use this check to prevent an infinite loop.
if self.field != field:
self.field = field
def _standardize_field(self):
# Return the standardized field.
return self.field.upper()
Method 3: Use a regular field and a computed field, with only the computed field being exposed in the view.
The readonly flag and the constraints help to protect the underlying field, but I am not certain that this method would maintain data integrity, and the method as a whole feels contrived.
import openerp
class Model(openerp.models.Model):
_name = 'addon.model'
field = openerp.fields.Text(
readonly=True,
required=True,
)
field_for_view = openerp.fields.Text(
compute='_compute_field_for_view',
inverse='_inverse_field_for_view',
required=True,
)
#openerp.api.one
#openerp.api.depends('field')
def _compute_field_for_view(self):
self.field_for_view = self.field
#openerp.api.one
#openerp.api.constrains('field', 'field_for_view')
def _constrains_field(self):
if self._standardize_field() is None:
raise openerp.exceptions.ValidationError('Field must be valid.')
def _inverse_field(self):
self.field = self._standardize_field()
def _standardize_field(self):
# Return the standardized field.
return self.field_for_view.upper()
Maybe the 'default' attribute is an implementation of your approach #1?
Here's the example taken from the Odoo8 documentation at https://www.odoo.com/documentation/8.0/reference/orm.html#creating-models
a_field = fields.Char(default=compute_default_value)
def compute_default_value(self):
return self.get_value()
Another option is to override the write() method in your subclass to add your call like so:
def write(self, vals):
for record in self:
# do the cleanup here for each record, storing the result in
# vals again
# call the super:
res = super(extendedProject, self).write(vals)
return res
vals is a dictionary with the modified values to store; self is a recordset with all records to store the values to. Note that the transaction in Odoo may still be rolled back after returning from your call to write.