I want to check a boolean field, from a parent class, into a child (lines) class.
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')
date = fields.Date(string="Print Date",default=fields.Datetime.now)
production_orders = fields.Many2one('bsi.production.order', ondelete='cascade', string="Production Order")
due_date = fields.Date(string="Due Date")
journal_entry = fields.Many2one('account.move', string="Journal Entry")
stock_picking_id = fields.Many2one('stock.picking', string="Stock Picking")
order_picking = 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")
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") #, compute="_remaining_func"
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")
So, when book_block button is checked, is_book_block should be automatically checked too, same with binding and edging, they should check is_binding and is_edging respectively.
These are the methods I have:
#api.depends('book_block', 'order_picking', 'order_picking.is_book_block')
def _bool_book_block(self):
if self.book_block == True:
order_picking.is_book_block = True
else:
order_picking.is_book_block = False
#api.depends('binding', 'order_picking', 'order_picking.is_binding')
def _bool_binding(self):
if self.binding == True:
order_picking.is_binding = True
else:
order_picking.is_binding = False
#api.onchange('edging', 'order_picking', 'order_picking.is_edging')
def _bool_edging(self):
if self.edging == True:
order_picking.is_edging == True
else:
order_picking.is_edging == False
But it doesn't work, I do check edging for example, and even save the document, but no changes on the boolean fields in lines.
Any ideas?
When you use depends the field must have a compute attribute :
some_feild = fiels.SomeType(......., compute='method_name')
#api.depends('some_field_2', ...)
def method_name(self):
# and here the function will be computed.
If your field are 100% computed field, best thing in odoo that you
can listen for changing in the parent class to compute the child field:
class bsi_print_order(models.Model):
_name = 'bsi.print.order'
....
class bsi_print_order_lines(models.Model):
_name = 'bsi.print.order.lines'
is_book_block = fields.Boolean(string="Is Book Block Done", compute="compute_book_block")
#api.depends('print_order.book_block')
def compute_book_block(self):
# in depends it's always a good this to loop
# or use api.one with depends
for rec in self:
if rec.print_order:
self.is_book_block = self.print_order.book_block
But this is Ok only if this field is always a compute field, i mean the user will never
change it's value from the UI.
If your field is not computed and the user can change the value if he want than you need to use
onchange in the parent class.
class bsi_print_order(models.Model):
_name = 'bsi.print.order'
....
#api.onchange('book_block '):
def onchange_book_block(self):
# in onchange no need for loop
# because self should always have only one recod
for line in self.order_picking:
line.is_book_block = self.book_block
Related
I create sequence in customer module sale, and _inherit to res.partner but I get fill 'New' in my sequence field when I create new customer
group_id = fields.Many2one(
'group.customer',
string="Group"
)
#api.model
def create(self, value):
if self.group_id.name == 'Dealer':
if value.get('code_customer', _('New')) == _('New'):
value['code_customer'] = self.env['ir.sequence'].next_by_code('code.customer.dealer') or _('New')
result = super(res_partner, self).create(value)
return result
That is a wrong way to inherit create function. Here is the correct one:
#api.model
def create(self, value):
group_id = value.get('group_id')
if group_id:
group = self.env['group.customer'].browse(group_id)
if group.name=='Dealer' and value.get('code_customer', _('New')) == _('New'):
value['code_customer'] = self.env['ir.sequence'].next_by_code('code.customer.dealer') or _('New')
result = super(res_partner, self).create(value)
return result
I know my object type is not matching to compare. I tried on #api.onchange but it says:
NullObject is not iterable for selection fields.
Code:
from odoo import models,api,fields
class semester(models.Model):
_name = 'module2_semester'
_description = 'Semester_Info'
_rec_name = 'sem_id'
sub = fields.Many2many('module2_subject')
cou_id = fields.Many2one('module2_course',"Course Name",required=True)
sem_id = fields.Char("Semester ID")
sem_name = fields.Selection(selection='_getSem_value',string="Semester")
reg_no = fields.Integer("Registration Number",size=20)
#api.model
def _getSem_value(self):
print("hello")
print(self.cou_id)
if self.cou_id=='BTECH':
return [('1','1'),
('2','2'),
('3','3'),
('4','4'),
('5','5'),
('6','6'),
('7','7'),
('8','8')]
if self.cou_id=='MCA':
return [('1','1'),
('2','2'),
('3','3'),
('4','4'),
('5','5'),
('6','6')]
if self.cou_id=='MTECH':
return [('1','1'),
('2','2'),
('3','3'),
('4','4')]
You can change the Semester field type to many2one and set the attribute widget to selection in the view definition.
When the value of cou_id changes you have just to filter the records shown in the selection field by returning a custom domain.
class Semester(models.Model):
_name = 'semester'
_description = 'Semester'
name = fields.Integer()
class semester(models.Model):
_name = 'module2_semester'
_description = 'Semester_Info'
_rec_name = 'sem_id'
sub = fields.Many2many('module2_subject')
cou_id = fields.Many2one('module2_course',"Course Name",required=True)
sem_id = fields.Char("Semester ID")
# sem_name = fields.Selection(selection='_getSem_value',string="Semester")
reg_no = fields.Integer("Registration Number",size=20)
sem_name = fields.Many2one('semester', string="Semester")
#api.onchange('cou_id')
def _course_changed(self):
self.sem_name = False
if self.cou_id:
# Initialize `semesters` in case `cou_id.name` is not listed below
semesters = 0
if self.cou_id.name == 'BTECH':
semesters = 8
if self.cou_id.name == 'MCA':
semesters = 6
if self.cou_id.name == 'MTECH':
semesters = 4
sem_ids = self.env['semester'].search([('name', '<=', semesters )])
return {'domain': {'sem_name': [('id', 'in', sem_ids.ids)]}}
In the view definition:
<field name="sem_name" widget="selection"/>
I'm trying to override the create and write method from Odoo.
My code (below) hits the error indicated:
class sms(models.Model):
_description = "Module d'envoi et de reception SMS"
contenu = fields.Text("Contenu", required=True)
date_sms = fields.Datetime(string="Date", default=lambda *a: datetime.now(), required=True)
type = fields.Char(string="Type", readonly=True, default="envoi")
status = fields.Char(string="Status", required=True, default="brouillon", readonly=True)
destinataire_ids = fields.Many2one(
comodel_name='hr.employee',
relation="m2m_mission_employee_relation",
column1="m2m_id",
column2="id",
string="Destinataire", required=True)
num = fields.Char(string="Numero")
#api.onchange('destinataire_ids')
def _set_number(self):
for record in self:
record.num = self.destinataire_ids.mobile_phone
self.num = self.destinataire_ids.mobile_phone
def get_user_id(self):
context = self._context
current_uid = context.get('uid')
user = self.env['res.users'].browse(current_uid)
return user
#api.multi
def write(self, vals):
res = super(sms, self).write(vals)
#api.model
def create(self,values):
campus_create = super(sms, self).create(values)
return campus_create
The error hit was:
File "C:\Python35\lib\site-packages\odoo-11.0.post20180130-py3.5.egg\odoo\models.py", line 1536, in _add_missing_default_values
defaults.update(values)
TypeError: cannot convert dictionary update sequence element #0 to a sequence
***TypeError: cannot convert dictionary update sequence element #0 to a sequence***
Where did you say what model you are overriding?
Try put _inherit = 'model' on start of your class
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')
I want to create recordset with product in my custom class from sale order after calling an event. I will create a record in sale.order and like creating invoice, I will create record in my custom module.
What I have done is:
In my custom class:
class LoadingSlip(models.Model):
_name = 'loading.slip'
_description = 'loading information'
partner_id = fields.Char("Customer Name")
order_date = fields.Date("Order Date")
expiration_date = fields.Date("Expiration Date")
# order_line = fields.One2many('sale.order.line', 'order_id', string="Order Lines")
product_line = fields.One2many('loading.product.line', 'loading_product', string="Loading Products")
class LoadingProduct(models.Model):
_name = 'loading.product.line'
_description = "Loading Product Informations"
products_id = fields.Many2one('product.product', string='Product',
ondelete='restrict', index=True)
quantity = fields.Float(string='Quantity', default=1)
loading_product = fields.Many2one('loading.slip', string="Loading Reference", ondelete='cascade', index='True')
In sale.order
class sale_func(models.Model):
_inherit = 'sale.order'
#api.multi
def _prepare_slip(self):
test.set_trace()
self.ensure_one()
slip = {
'partner_id': self.partner_id.name,
'order_date': self.date_order,
'expiration_date': self.validity_date,
}
return slip
#api.multi
def action_slip_create(self, grouped=False, final=False):
test.set_trace() # debug point
pprint(self)
inv_obj = self.env['loading.slip']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
slips={}
pprint(slips)
slipReferences={}
test.set_trace()
for order in self:
group_key = order.id
test.set_trace()
for line in order.order_line:
if group_key not in slips:
inv_data = order._prepare_slip()
loadingslip = inv_obj.create(inv_data)
slipReferences[loadingslip] = order
slips[group_key] = loadingslip
if line.product_uom_qty > 0:
line.slip_line_create(slips[group_key].id)
if not slips:
raise UserError(_('There is no loading slip line.'))
#api.multi
def create_slip(self):
test.set_trace()
pprint(self)
sale_orders = self.env['sale.order'].browse(self._context.get('active_ids', []))
self.action_slip_create(sale_orders)
In sale.order.line
class sales_order(models.Model):
_inherit="sale.order.line"
#api.multi
def _prepare_slip_line(self):
test.set_trace()
self.ensure_one()
res={}
pprint(res)
res={
'products_id': self.product_id.id or False,
'quantity': self.product_uom_qty
}
pprint(res)
#api.multi
def slip_line_create(self, loading_product):
test.set_trace()
prdct_order = self.env['loading.product.line']
for line in self:
vals = line._prepare_slip_line()
prdct_order.create(vals)
My error is:
> /home/diwap/odoo-dev/custom-addons/sales_ext_agni/models/models.py(196)slip_line_create()
195 vals = line._prepare_slip_line()
--> 196 prdct_order.create(vals)
197
ipdb> n
TypeError: "argument of type 'NoneType' is not iterable"
I have tried update and write method instead of create in line 196 but I could not get any result it's just come up with an empty field and also no error. However when I try the real thing and i.e. write() I get this error. Is there any wrong somewhere in my code or its just an horrible thing I am doing.