I tried to use api.constrain in odoo. The case is, I want to give condition to odoo if user missing one field, odoo will give some warning like alert, and user have to give some input to the previous field. This is my code :
class Provinc(models.Model):
_name = 'provinsi.model'
_rec_name ='prov'
prov = fields.Char(
string='Provinsi',
)
res_partner_ids = fields.One2many(
'res.partner',
'provinsi'
city_id = fields.One2many(
'city.model',
'provinsi_id'
)
class city(models.Model):
_name = 'kota.model'
_rec_name ='city'
city = fields.Char(
string='City',
)
res_partner_city = fields.One2many(
'res.partner',
'city'
)
provinsi_id = fields.Many2one(
'provinsi.model',
string='provinsi',
)
class Master_data(models.Model):
_inherit = 'res.partner'
provinsi = fields.Many2one(
'provinsi.model',
'provinsi',
)
city = fields.Many2one(
'city.model',
'city',
)
#api.onchange('provinsi')
def show_provinsi(self):
return {'domain': {'city': [('provinsi_id', '=', self.provinsi.id)]}}
#api.constrains('provinsi')
#api.onchange('city')
def show_kota(self):
for record in self:
if record.provinsi == False:
raise ValidationError("is gonna be error")
I have tried 2 ways. First, I put the api.constrain insode class City, and it's doesn't work,second ways I tried put the api.constrain like the code inside class master, and the result remains the same.
you only need onchang not any constrains to display warning!
#api.onchange('city')
def show_kota(self):
if self.city and not self.provinsi:
raise ValidationError("is gonna be error")
now if you select value in city field and provinsi missing value then it will display error msg
guessing field "city" and "provinsi" is in 'res.partner' form view!
If you want to check a field value is empty or not, just use required ="1" like:
<field name="provinsi" required="1"/>
Related
I have two models (parent and child) with mutual m2o filed(analytic account id). I want to filter the value of the field in the child based on the selected value in the parent ( I want the value to be the same). I have tried to do it using on change but it doesn't work so far. Here is my code:
class logistic(models.Model):
_name = 'logistic.logistic'
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
_description = 'logistic.logistic'
_order = 'id desc'
additional_services_ids = fields.One2many('additional.service.line', 'waybill_id',
string='Services lines')
analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account',
index=True,required=True)
#api.onchange('analytic_account_id')
def _analytic_account_id(self):
for rec in self:
return {'domain': {
'additional_services_ids.analytic_account_id': [('analytic_account_id', '=',
rec.analytic_account_id.id)]}}
class AdditionalServicesLine(models.Model):
_name = "additional.service.line"
_description = "Additional services"
waybill_id = fields.Many2one('logistic.logistic', string='Additional Services Entry')
analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account',
index=True,required=True)
I have two models in my odoo project. Employee and equipment, as shown bellow.
Equipment/model.py
from openerp import models, fields, api
import datetime
class equipment(models.Model):
_name = 'equipment.equipment'
name = fields.Char(string='Name', )
date_of_purchase = fields.Date(string='Date Of Purchase', default=fields.Date.today(), )
write_off_days = fields.Integer(string="Days To Write-off", required=True, )
write_off_date = fields.Date(string="Write-off Date", compute="_get_write_off_date", )
price = fields.Float(string="Price '$'", required=True, )
description = fields.Char(string="Description", required=False, )
employee_id = fields.Char(string="Owner", compute="_get_owner", )
#api.one
#api.depends('employee_id')
def _get_owner(self):
//result = self.env.['res.equipment_table'].
//get id from relation database <-------------
#api.one
#api.depends('write_off_days', 'date_of_purchase')
def _get_write_off_date(self):
date = datetime.datetime.strptime(self.date_of_purchase, "%Y-%m-%d")
self.write_off_date = date + datetime.timedelta(days=self.write_off_days)
employee/model.py
from openerp import models, fields, api
class employee(models.Model):
_name = 'employee.employee'
name = fields.Char(string='First Name')
last_name = fields.Char(string='Last Name')
birth_date = fields.Date(string='Birth Date', default=fields.Date.today(), )
equipment_ids = fields.Many2many(string="Equipment", comodel_name="equipment.equipment", relation="equipment_table", )
total_equipment_price = fields.Float(string="Total Equipment Price '$'", compute="_get_total_equipment_price", )
#api.one
#api.depends('equipment_ids')
def _get_total_equipment_price(self):
total = 0
for equipment in self.equipment_ids:
total += equipment.price
self.total_equipment_price = total
I have many2many field, which holds all equipment that employee owns. I need to update the equipment owner every time the field is changed. The reason for this is.. when a user adds new equipment to the employee, there should be shown only unowned equipment. That is why I need to check and update the owner.
I already made a domain to check if equipment already has an owner, which will be shown below. Just need to update that employee_id field somehow.
<notebook>
<page string="Equipment">
<group>
<field name="equipment_ids" domain="[('employee_id', '=', False)]"/>
</group>
</page>
</notebook>
Change the type of employee_id to Many2one:
employee_id = fields.Many2one('employee.employee', string="Owner")
Override create and write methods to set employee_id each time new equipment is added to the list:
class Employee(models.Model):
_name = 'employee.employee'
#api.model
def create(self, values):
res = super(Employee, self).create(values)
if res.equipment_ids:
res.equipment_ids.write({'employee_id': res.id})
return res
#api.multi
def write(self, values):
res = super(Employee, self).write(values)
for r in self:
equipment_ids = r.equipment_ids.filtered(lambda s: not s.employee_id)
if equipment_ids:
equipment_ids.write({'employee_id': r.id})
return res
Because an equipment can set to one owner, I suggest you to change the type of equipment_ids to One2many to be able to set a list of equipments by employee and the employee_id field value will be set automatically for you when you add equipment to the list.
If you change the value of employee_id the equipment will be automatically visible in the list of equipments of the new employee.
equipment_ids = fields.One2many("equipment.equipment", 'employee_id', string="Equipments")
Reset owner
#api.multi
def write(self, values):
removed_ids = set()
old_ids = {r.id: r.equipment_ids.ids for r in self}
res = super(Employee, self).write(values)
for r in self:
equipment_ids = r.equipment_ids.filtered(lambda s: not s.employee_id)
if equipment_ids:
equipment_ids.write({'employee_id': r.id})
removed_ids |= set(old_ids[r.id]) - set(r.equipment_ids.ids)
self.equipment_ids.browse(removed_ids).write({'employee_id': False})
return res
I will want to retrieve different values from a chosen field. Let me explain:
I have this class:
class SchoolWebServices(models.Model):
_name = 'ecole.webservices'
name = fields.Char(string='Nom')
code_produit = fields.Char(string='Produit')
code_CDG = fields.Char(string='Centre de Gestion')
code_Catalog = fields.Char(string='Catalogue Produits')
I have this other class:
class ResPartner_school(models.Model):
_name = 'ecole.partner.school'
_order = 'id desc'
half_pension_name = fields.Many2one(comodel_name="ecole.webservices",
string="Lieu")
And I have a function who is in the class: ecole.partner.school
#api.multi
def create_compte_cantine(self):
print "Inscription réussie"
get_halfpension_name = self.half_pension_name.id
if get_halfpension_name:
code_Catalog = self.env['ecole.webservices'].code_Catalog
I get the id of half_pension_name in my variable get_halfpension_name but I wish to recover the code_Catalog of the same recording too. How to do?
You just need to use dot-notation to retrieve the value:
#api.multi
def create_compte_cantine(self):
self.ensure_one()
if self.half_pension_name:
code_Catalog = self.half_pension_name.code_Catalog
Try to stay in the "rules" of the Odoo guideline. For example a Many2one relation field should be end with _id -> half_pension_id = fields.Many2one(comodel_name="ecole.webservices", string="Lieu")
I am creating a module something like call log. In that i need to search the customer number and get the Partner information or have to link the partner automatically.
the following are the codes, somebody please help me.
class model_call(models.Model):
_inherit = 'res.partner'
_name = 'model.call'
_description = 'call logs'
""" *************** Base Fields ******************* """
name = fields.Char(string='Topic')
customer_number = fields.Char(string='Customer Number', track_visiility='onchange', onchange='get_partner(customer_number)')
#-------------------------------------------------
# apis
#-------------------------------------------------
#api.onchange('customer_number')
def get_partner(self, customer_number):
if customer_number:
customer = self.env['res.partner'].search([('customer_number', '=', record.phone)])
return customer
#------------------------------------------------------
customer = fields.Many2one('res.partner', string='Customer', track_visibility='onchange',index=True, help="Linked partner (optional). Usually created when converting the lead.",)
Your onchange isn't correct. You don't need parameters and have to return a dictionary or nothing. The dictionary is only needed for field filtering changes and warning messages. Value changes like yours are made "directly":
#api.onchange('customer_number')
def get_partner(self):
if self.customer_number:
customer = self.env['res.partner'].search(
[('customer_number', '=', self.phone)]) # shouldn't it be self.customer_number?
self.customer = customer
And try to stick to the Odoo Guidelines and change the field customer to customer_id.
Consider this:
#api.multi
#api.onchange('order_lines', 'order_lines.is_book_block', '')
#api.constrains('order_lines', 'order_lines.isbn')
def check_quantity(self):
location = self.printer_book_block.property_stock_supplier.id
for rec in self:
if rec.order_lines:
for line in rec.order_lines:
if line.qty > line.isbn.with_context({ 'location': location, }).qty_available >= 0:#line.isbn.qty_available in location:
rec.write({'state': 'awaitingraw'})
else:
rec.write({'state': 'work_in_progress', 'is_book_block': True})
When there is enough product quantity (isbn) on the specified location, change state of the document to work_in_progess and also change Boolean field is_book_block to True.
The state field is on the parent model:
class bsi_print_order(models.Model):
_name = 'bsi.print.order'
#api.model
def create(self, vals):
if vals.get('name', 'New') == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('bsi.print.order') or '/'
return super(bsi_print_order, self).create(vals)
name = fields.Char('Reference', required=True, index=True, copy=False, readonly='True', default='New')
order_lines = fields.One2many('bsi.print.order.lines', 'print_order', string="Order lines")
book_block = fields.Boolean(string="Book Block", default=True)
binding = fields.Boolean(string="Binding")
edging = fields.Boolean(string="Edging")
state = fields.Selection([
('draft','Draft'),
('awaitingraw','Awaiting raw materials'),
('work_in_progress','Print in Progress'),
('delivered','Delivered'),
('cancel','Cancel'),
], string="State")
The is_book_block field is on the child class One2many order_lines field:
class bsi_print_order_lines(models.Model):
_name = 'bsi.print.order.lines'
print_order = fields.Many2one('bsi.print.order', string="Print Order")
isbn = fields.Many2one('product.product', string="ISBN", domain="[('is_isbn', '=', True)]")
qty = fields.Integer(string="Quantity")
consumed_qty = fields.Integer(string="Quantity consumed")
remaining_qty = fields.Float(string="Remaining quantity")
is_book_block = fields.Boolean(string="Is Book Block Done")
is_binding = fields.Boolean(string="Is Binding Done")
is_edging = fields.Boolean(string="Is Edging Done")
isbns = fields.Many2one('worksheets.isbns', string="Worksheet ISBNS")
There are also other two fields is_binding and is_edging.
Anyways, knowing one is sufficient to figure out the other two (I guess, lol) so, since state is on the parent class, it works nicely, the state of the record actually changes, however, while there is no syntax error with is_book_block it should change to True, but it doesn't, so, I think this is because the method is looping on order_lines but it changes things on parent class only (bsi.production.order).
Any ideas?
From what i understand the is_book_blockis in the line when you loop through lines every line is a record it self you call write if you want to set more than field or just change that field:
# when you change just one field no need for write just
rec.state = 'work_in_progress' # is enough
# because rec.state will trigger write method
# but for more than one field use write to trigger it only one time
# line is a record too you can call write also if you want
line.is_book_block = True
One thing remove order_lines.is_book_blockfrom onchange decorator because you will trigger an infinitive call for the the method :
#api.onchange('order_lines')