I want to add my created record to one2many field. However it results ValueError: Expected singleton: product.job_line(762, 763).
I don't know why it doesn't separate into two object but it merge into one object when JobContainer call the write method. After that it results the error as I told you before.
How to solve this one ?
Here is my code of SaleOrder :
# -*- coding: utf-8 -*-
import logging
from odoo import models, fields, api
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = 'sale.order'
job_container = fields.One2many('job.container', 'order')
discount = fields.Float()
state = fields.Selection(
[
('draft', 'Quotation'),
('sent', 'Quotation Sent'),
('pending', 'Pending Approval'),
('sale', 'Sales Order'),
('done', 'Locked'),
('cancel', 'Cancelled'),
],
string='Status', readonly=True, copy=False, index=True,
track_visibility='onchange', default='draft'
)
@api.onchange('discount')
def _amount_all(self):
super(SaleOrder, self)._amount_all()
for order in self:
total = order.amount_total
if order.discount > 1:
total -= order.discount
else:
total -= total * order.discount
order.update({
'amount_total': total
})
@api.multi
def action_confirm(self):
if self.state != 'pending' and self.get_full_price() != self.amount_total:
self.state = 'pending'
elif self.job_container:
self.state = 'sale'
self.confirmation_date = fields.Datetime.now()
self.job_container.confirmation_date = self.confirmation_date
else:
self.create_job_container()
self.delegate_job_values()
super(SaleOrder, self).action_confirm()
def delegate_job_values(self):
total_price = self.amount_total
price_list = []
for line in self.order_line:
qty = line.product_uom_qty
product = line.product_id.product_tmpl_id
price = line.price_total*self.get_discount_percent()/qty
if price == 0:
price = line.price_total/qty
for _ in range(0, int(qty)):
price_list += product.create_price_list(price)
for index in range(0, len(self.job_container.job_lines)):
total_price -= price_list[index]
if index == len(self.job_container.job_lines)-1:
self.job_container.job_lines[index].update({
'cost': price_list[index] + total_price,
'order':self.id,
})
else:
self.job_container.job_lines[index].update({
'cost': price_list[index],
'order': self.id,
})
def get_full_price(self):
total_price = 0
for line in self.order_line:
total_price += line.product_id.product_tmpl_id.list_price*line.product_uom_qty
return total_price
def create_job_container(self):
container = self.env['job.container'].create({
'order': self.id,
'partner': self.partner_id.id,
'confirmation_date': fields.Datetime.now()
})
for line in self.order_line:
qty = line.product_uom_qty
product = line.product_id.product_tmpl_id
job_lines = []
for _ in range(0, int(qty)):
for job_line in product.create_job_lines():
_logger.info("JL : "+str(job_line))
job_lines.append(job_line.id)
# container.add_job_line(job_line)
# container.update({
# 'job_lines': [(1,job_line.id,job_line)]
# })
container.job_lines += job_line
_logger.info('Job Line '+str(job_lines))
# container.job_lines = job_lines
container.update_job_lines_left()
@api.one
def action_approve(self):
self.action_confirm()
def write(self, val):
old_state = self.state
_logger.info('Value : '+str(val))
_logger.info('Old State '+old_state)
super(SaleOrder, self).write(val)
if old_state == 'sale' and 'confirmation_date' not in val:
self.state = 'pending'
return True
def get_discount_percent(self):
if self.discount < 1:
return self.discount
else:
return self.discount/(self.amount_total+self.discount)
def update_invoice_order(self):
for invoice in self.invoice_ids:
invoice.update({'order':self.id})
@api.multi
def action_invoice_create(self, grouped=False, final=False):
super(SaleOrder, self).action_invoice_create(grouped, final)
self.update_invoice_order()
@api.one
def pending(self):
self.state = 'pending'
self.job_container.unpending()
Here is my code of Job Container :
# -*- coding: utf-8 -*-
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class JobContainer(models.Model):
_name = 'job.container'
_order = 'jobs_left'
_inherit = ['mail.thread']
order = fields.Many2one('sale.order', readonly=True)
partner = fields.Many2one('res.partner', readonly=True)
confirmation_date = fields.Datetime(readonly=True, track_visibility='onchange')
job_lines = fields.One2many('product.job_line', 'container')
jobs_left = fields.Integer(compute='update_job_lines_left')
to_pending = fields.Boolean()
def pending(self):
self.order.pending()
def unpending(self):
self.to_pending = False
for line in self.job_lines:
line.to_pending = False
@api.one
def update_job_lines_left(self):
left = 0
for job_line in self.job_lines:
if not job_line.is_finish and not job_line.state=='cancel':
left += 1
self.jobs_left = left
def adjust_cost(self,cost):
sum = 0
for line in self.job_lines:
if line.state=='active' and not line.is_finish:
line.cost+=round(cost/len(self.job_lines),2)
sum += line.cost
left = self.order.amount_total-sum
for line in self.job_lines:
if line.state=='active' and not line.is_finish:
line.cost+=left
break
@api.onchange('job_lines')
def notify_pending(self):
_logger.info("IN")
self.to_pending = True
@api.multi
def write(self,val):
_logger.info(val)
super(JobContainer,self).write(val)
_logger.info(str(val))
if self.to_pending:
_logger.info("INNNN")
self.pending()
return True