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')
Related
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
I have this method, which should loop on a One2many object, but the actual loop isn't working, I mean, if I add just one line it works fine, but if I add more than one line, than it throws me the singleton error:
#api.multi
#api.depends('order_lines', 'order_lines.isbn')
def checkit(self):
for record in self:
if self.order_lines.isbn:
return self.order_lines.isbn
else:
raise Warning(('Enter at least 1 ISBN to produce'))
These are the two objects on which this method is based upon:
class bsi_production_order(models.Model):
_name = 'bsi.production.order'
name = fields.Char('Reference', required=True, index=True, copy=False, readonly='True', default='New')
date = fields.Date(string="Production Date")
production_type = fields.Selection([
('budgeted','Budgeted'),
('nonbudgeted','Non Budgeted'),
('direct','Direct Order'),
], string='Type of Order', index=True,
track_visibility='onchange', copy=False,
help=" ")
notes = fields.Text(string="Notes")
order_lines = fields.One2many('bsi.production.order.lines', 'production_order', states={'finished': [('readonly', True)], 'cancel': [('readonly', True)]}, string="Order lines", copy=True)
class bsi_production_order_lines(models.Model):
_name = 'bsi.production.order.lines'
production_order = fields.Many2one('bsi.production.order', string="Production Orders")
isbn = fields.Many2one('product.product', string="ISBN", domain="[('is_isbn', '=', True)]")
qty = fields.Integer(string="Quantity")
consumed_qty = fields.Float(string="Consumed quantity")
remaining_qty = fields.Float(string="Remaining quantity", compute="_remaining_func")
#api.onchange('qty', 'consumed_qty')
def _remaining_func(self):
if self.consumed_qty or self.qty:
self.remaining_qty = self.consumed_qty - self.qty
If I add more than one isbn on bsi.production.order.lines it throws me:
ValueError
Expected singleton: bsi.production.order.lines(10, 11)
Any ideas?
EDIT
The duplicate is a different situation, and actually I've changed my method to match the one explained in the other question, with no success. So it's not really, or at least not an api-only issue.
In your case, it's found more then one record set in order_lines and you tried to get isbn value from it.
Try with following code:
#api.multi
#api.depends('order_lines', 'order_lines.isbn')
def checkit(self):
for record in self:
if record.order_lines:
for line in record.order_lines:
if line.isbn:
return line.isbn
else:
raise Warning(('Enter at least 1 ISBN to produce'))
For details of these error. You may refer my blog.
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.
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"/>
Currently i am creating a custom module, in which i need to create a demo record while a customer invoice is created.
This is my custom model.
class csm(models.Model):
_name= 'csm'
invoice_date = fields.Datetime('Invoice date',readonly=True)
delivery_date = fields.Datetime('Delivery date',readonly=True)
In account.invoice i have added as,
class invoice_csm(models.Model):
_inherit = 'account.invoice'
delivery_date = fields.Datetime('Delivery date')
date_invoice= fields.Datetime('Invoice date')
#api.multi
def write(self,values):
record = super(invoice_csm, self).write(values)
if self.state == 'paid':
if self.delivery_date and self.installation_date:
self.env['csm'].write({
'invoice_date': record .date_invoice,
'delivery_date': record .delivery_date,
})
return record
What i want is when the status of customer invoice is become paid, i need to create a record in my csm model. But it is not creating. But if i use directly create function then record is creating in csm, but the condtion state=='paid' wont work because we can change the state even after creating invoice. That's why i used write method, but here it is not creating the record.
(Delivery and invoice dates have values)
############ CODE FOR REFERENCE #########
class customer(models.Model):
_name = "csm"
_inherit = ['mail.thread']
name = fields.Char(string='Subject', required=True)
## RETAIL ##
invoice_date = fields.Datetime('Invoice date',readonly=True)
delivery_date = fields.Datetime('Delivery date',readonly=True)
installation_date = fields.Datetime('Installation date',readonly=True)
service1_date = fields.Datetime('First service date',readonly=True)
service2_date = fields.Datetime('Second service date',readonly=True)
service3_date = fields.Datetime('Third service date',readonly=True)
#api.multi
def unlink(self):
if self.pool['res.users'].has_group(self._cr, self.env.user.id, 'customer_service_management.group_managerz'):
pass
elif self.create_uid == self.env.user:
pass
else:
if self.create_uid != self.env.user:
raise Warning('You are not authorized to delete this record. Contact administrator/manager')
return super(customer, self).unlink()
INVOICE
class invoice_csm(models.Model):
_inherit = 'account.invoice'
delivery_date = fields.Datetime('Delivery date')
installation_date = fields.Datetime('Installation date')
service1_date = fields.Datetime('First service date')
service2_date = fields.Datetime('Second service date')
service3_date = fields.Datetime('Third service date')
#api.multi
def write(self,values):
record = super(invoice_csm, self).write(values)
if 'state' in values and values['state'] == 'paid':
self.env['csm'].create({
'name': values['number'],
'delivery_date': values['delivery_date'],
'installation_date': values['installation_date'],
'service1_date': values['service1_date'],
'service2_date': values['service2_date'],
'service3_date': values['service3_date'],
})
return record
Use self.env['csm'].create , instead of self.env['csm'].write:
#api.multi
def write(self,values):
record = super(invoice_csm, self).write(values)
if 'state' in values and values['state'] == 'paid':
if values.get('date_invoice') and values.get('delivery_date'):
self.env['csm'].create({
'invoice_date': values['date_invoice'],
'delivery_date': values['delivery_date'],
})
return record