I need help to set default value of purchase_ok field at product_template class in purchase module
thanks
You can simply set the default attribute like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=True,
)
Or you can use a lambda function like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=lambda self: self._get_default_purchase_ok(),
)
#api.model
def _get_default_purchase_ok(self):
value = True
# some operations
return value
Related
I have created a parent model, which has a Selection field.
This pattern must be inherited from classes that offer a service, so in the child classes I use fields.Selection(selection_add = ....). Is it possible to create, in the parent class, an "empty" selection that will only fill with the selection fields of the models that inherit it?
Ex
class GenericService(models.Model):
_name = 'generic.service'
selection_type = fields.Selection(
[('select_type', _("Select an Account")),],default='select_type',
string=_("Service Type"),
required=True
class SpecificService(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('sftp','SFTP')],
)
I would like to avoid adding a default field on the generic model selection, my alternative is to create a method that controls the insertion, but I would like to know if it could be avoided.
If you inherit like that _inherit without _name. Then you end up only with 1 model generic.service And all selection_add=[] added selections.
If you add
class GenericService(models.Model):
_name = 'generic.service'
selection_types = fields.Selection([], string="Service Type")
class SpecificServiceA(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('sftp','SFTP')], required=True
)
class SpecificServiceB(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('https','HTTPS')], required=True
)
you end up with model named "generic.service" and selections [('sftp','SFTP'), ('https','HTTPS')]
I believe strings and selection names are added automatically to translation list. no need for _()
You can also use Odoo's mixin feature, which is a bit like abstract types/classes. Following an example in context of your requirments:
class ServiceMixin(models.AbstractModel):
_name = "service.mixin"
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field
Meant to be extended by inheriting models."""
return []
type_selection = fields.Selection(
selection="_get_type_selection", string="Type")
class ServiceA(models.Model):
_name = "service.a"
_inherit = ["service.mixin"]
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field"""
return [('a', 'A'), ('b', 'B')]
class ServiceB(models.Model):
_name = "service.b"
_inherit = ["service.mixin"]
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field"""
return [('a', 'A'), ('c', 'C')]
In database that will lead to 2 new tables: service_a and service_b. So you have really 2 new Odoo models, which aren't dependend on eachother.
I need applay domain on field product_id in purchase.order.line model, after call onchange method in purchase.order model.
Example:
_inherit = "purchase.order"
custom_id = fields.Many2one('custom.model', string='Custom')
#api.onchange('custom_id')
def change_product(self):
lst = [1,2,3]
return {'domain': {'order_id.product_id': [('id', 'in', lst)]}}
This is original field where I want add my domain
product_id = fields.Many2one('product.product', string='Product',domain=[('purchase_ok', '=', True)], change_default=True, required=True)
I don't get any error but in product_id field show all data from database, not product where id 1,2,3 from above example.
write onchange function for product_id, instead of custom_id and return domain.
#api.onchange('product_id')
def change_product(self):
lst = [1,2,3]
return {'domain': {'product_id': [('id', 'in', lst)]}}
inside the onchange function consider the custom_id.
You have a little problem here: you can't set a domain for child relations IIRC.
What you can do is to create a related field on the child relation (here purchase.order.line and trigger the onchange on that.
class PurchaseOrder(models.Model):
_inherit = "purchase.order"
custom_id = fields.Many2one(
comodel_name='custom.model', string='Custom')
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
#api.onchange('custom_id')
def onchange_custom_id(self):
lst = [1,2,3]
return {'domain': {'product_id': [('id', 'in', lst)]}}
And some more information. Let me presume you have set custom_id on product variants (a) or on product categories (b). Just change the domain of product_id and use the domain operator '=?'. You won't need an onchange method for this solution, but you have to define custom_id in the view (invisible is possible, this is also a must have for the complete first solution)!
(a)
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
product_id = fields.Many2one(
domain="[('purchase_ok', '=', True), ('custom_id', '=?', custom_id)]")
(b)
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
product_id = fields.Many2one(
domain="[('purchase_ok', '=', True), ('categ_id.custom_id', '=?', custom_id)]")
If no custom_id is set the domain will read: product has to be purchasable AND True.
I have a class named detail_base, and two other classes name flight_detail and tour_detail, the last two classes inherits from the first one, like this:
class DetailBase(models.Model):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherits = 'detail_base'
passport = fields.Char('Passport')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherits = 'detail_base'
age = fields.Integer('Tourist Age')
The problem is when I call the flight_detail and tour_detail in the same view, the browser can't handle the common attributes of both classes, If I assign 5 to tour_detail.fee, that number will be stored into flight_detail.fee.
It seems the problem is related to the attributes with the same name of different objects being siblings.
I will appreciate any help.
You should either use _inherit
class DetailBase(models.AbstractModel):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherit = 'detail_base'
passport = fields.Char('Passport')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherit = 'detail_base'
age = fields.Integer('Tourist Age')
which should either create 3 database tables (detail_base as Model) or 2 database tables (AbstractModel).
Or you use _inherits like:
class DetailBase(models.Model):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherits = {'detail_base': 'base_id'}
passport = fields.Char('Passport')
base_id = fields.Many2one('detail_base', required=True, ondelete='cascade')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherit = {'detail_base': 'base_id'}
age = fields.Integer('Tourist Age')
base_id = fields.Many2one('detail_base', required=True, ondelete='cascade')
That will create 3 tables, and fee and passenger will be stored in detail_base table. Odoo will get it from there, because it is a sort of delegation inheritence.
use inherit:
1- inherit without _name :
inherit = 'model.name'
new_field = fields...
this add this field to the model.name
2- inherit with _name:
inherit = 'model.name'
_name = 'new.model'
here will create a new tabel in database with the same structure of model.name.
inherits: The delegation inheritance.
best example is res.users and res.partners user is a partener so when we create a res.users record we must create a res.partener that hold commun field like name, email, address ... and information related to users like passowrd and login are stored in res.users model and with type of inheritence you can access field of res.partener directly without having to create a related field. you can do user_record.name or .email or .address this will not be a problem.
i like to think of it as one2one relation.
_inherits = {model.name : many2one_field_id }
_name = 'new.model'
# m2o field should be required and ondelete = cascade
many2one_field_id = fields.Many2one('model.name', string='Label', required=True, ondelete="cascade")
so when you create a record of new.model all field that are in model.name will be stored in model.name.
I have a field that call a function to get default value (in module project_forecast):
def default_user_id(self):
return self.env.user if ("default_user_id" not in self.env.context) else self.env.context["default_user_id"]
user_id = fields.Many2one('res.users', string="User", required=True,
default=default_user_id)
I create another module to inherit it and change default value of field user_id but it's not working without any error in log, how can I resolve this ?
def default_user_id(self):
return False
You're linking a method directly on field definition. So overriding the method isn't enough anymore. Just define the field user_id again with default as the only parameter and ofc your new method:
The original model:
class MyModel(models.Model):
_name = "my.model"
def default_user_id(self):
return self.env.context.get("default_user_id", self.env.user)
user_id = fields.Many2one(
comodel_name='res.users', string="User", required=True,
default=default_user_id)
The inherited model:
class MyModelInherit(models.Model):
_inherit = "my.model"
def default_user_id(self):
return self.env['res.users']
user_id = fields.Many2one(default=default_user_id)
Please check this
user_id = fields.Many2one('res.users', string='User',readonly=True, default=lambda self: self.env.user)
I have model contains many to many assign_to_id, I want to modify that field in wizard form through escalte_to method when user trigger escalate button
Model:
class Incident(models.Model):
_name = 'itmangement.incident'
assigned_to_id = fields.Many2one('hr.employee', string="Assigned To",domain="[('department_id', '=', dep_id)]",required=True)
Wizard model
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
incident_obj = self.env['itmangement.incident']
record = incident_obj.browse(self._context.get('active_ids'))
record.write({'state': 'escalated'})
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
object_id = self.env.context.get('active_id')
for object in self.env['itmangement.incident'].browse(object_id) and self.escalated_to:
object.assigned_to_id = self.escalated_to.id