Compare commits
29 Commits
feature/66
...
master_sf_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0559e9887 | ||
|
|
39a25bb6c8 | ||
|
|
e129c08426 | ||
|
|
c6b47bd68d | ||
|
|
126d60f8d7 | ||
|
|
4225a8fe1b | ||
|
|
a13a79f41f | ||
|
|
a828c823dd | ||
|
|
9cf2bac9c6 | ||
|
|
484fab85be | ||
|
|
2449b92bc8 | ||
|
|
d26e6edd31 | ||
|
|
b1a04f8f44 | ||
|
|
59569806e6 | ||
|
|
cdf8fbb12a | ||
|
|
5d0f094da7 | ||
|
|
95cb5251dc | ||
|
|
c8fe7504c7 | ||
|
|
222efc57c2 | ||
|
|
735d5c659d | ||
|
|
50d188b737 | ||
|
|
af3ea0f702 | ||
|
|
8bf3b68cee | ||
|
|
2766bc7d34 | ||
|
|
1082384d00 | ||
|
|
25aab1576d | ||
|
|
87891b45ef | ||
|
|
b2cfdd8d78 | ||
|
|
c6cb1d367d |
@@ -41,13 +41,14 @@ class PurchaseRequest(models.Model):
|
|||||||
if lines:
|
if lines:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
for line_item in line.order_line:
|
for line_item in line.order_line:
|
||||||
product_id = line_item.product_id.id
|
if line_item.state == 'purchase':
|
||||||
qty = line_item.product_qty
|
product_id = line_item.product_id.id
|
||||||
product_rounding[product_id] = line_item.product_id.uom_id.rounding
|
qty = line_item.product_qty
|
||||||
if product_id in product_summary:
|
product_rounding[product_id] = line_item.product_id.uom_id.rounding
|
||||||
product_summary[product_id] += qty
|
if product_id in product_summary:
|
||||||
else:
|
product_summary[product_id] += qty
|
||||||
product_summary[product_id] = qty
|
else:
|
||||||
|
product_summary[product_id] = qty
|
||||||
|
|
||||||
# 校验产品数量
|
# 校验产品数量
|
||||||
discrepancies = []
|
discrepancies = []
|
||||||
@@ -60,10 +61,10 @@ class PurchaseRequest(models.Model):
|
|||||||
|
|
||||||
if discrepancies:
|
if discrepancies:
|
||||||
# 弹出提示框
|
# 弹出提示框
|
||||||
message = "产品数量不一致:\n"
|
message = "产品与采购数量不一致:\n"
|
||||||
for product_id, required_qty, order_qty in discrepancies:
|
for product_id, required_qty, order_qty in discrepancies:
|
||||||
product_name = self.env['product.product'].browse(product_id).display_name # 获取产品名称
|
product_name = self.env['product.product'].browse(product_id).display_name # 获取产品名称
|
||||||
message += f"产品 {product_name},需求数量 {required_qty},关联采购订单数量 {order_qty}(含询价状态)\n"
|
message += f"产品 {product_name},需求数量 {required_qty},关联采购订单确认的数量 {order_qty}。\n"
|
||||||
# 添加确认框
|
# 添加确认框
|
||||||
message += "确认关闭?"
|
message += "确认关闭?"
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class MrpWorkorder(models.Model):
|
|||||||
exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录')
|
exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录')
|
||||||
|
|
||||||
def write(self, values):
|
def write(self, values):
|
||||||
if 'test_results' in values and self.exception_ids:
|
if values.get('test_results') and self.exception_ids:
|
||||||
pending_exception = self.exception_ids.filtered(
|
pending_exception = self.exception_ids.filtered(
|
||||||
lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005'
|
lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,8 +45,9 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
|
|||||||
product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
|
product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
|
||||||
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
||||||
i += 1
|
i += 1
|
||||||
if kw.get('contract_file_name') and kw.get('contract_file'):
|
if kw.get('contract_file_name') and kw.get('contract_file') and kw.get('contract_code'):
|
||||||
order_id.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file'))
|
order_id.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file'))
|
||||||
|
order_id.write({'contract_code': kw.get('contract_code'), 'contract_date': kw.get('contract_date')})
|
||||||
res['factory_order_no'] = order_id.name
|
res['factory_order_no'] = order_id.name
|
||||||
order_id.confirm_to_supply_method()
|
order_id.confirm_to_supply_method()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -227,22 +227,30 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
|
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
|
||||||
else:
|
else:
|
||||||
next_workorder = sorted_workorders[position + 1]
|
next_workorder = sorted_workorders[position + 1]
|
||||||
next_state = next_workorder.state
|
# 持续获取下一个工单,直到找到一个不是返工的工单
|
||||||
if next_state not in ['pending', 'waiting', 'ready']:
|
while next_workorder and next_workorder.state == 'rework':
|
||||||
raise UserError('下工序已经开始,无法回退')
|
position += 1
|
||||||
if next_workorder.is_subcontract:
|
if position + 1 < len(sorted_workorders):
|
||||||
next_workorder.picking_ids.write({'state': 'waiting'})
|
next_workorder = sorted_workorders[position + 1]
|
||||||
next_workorder.state = 'pending'
|
|
||||||
self.time_ids.date_end = None
|
|
||||||
cur_workorder.state = 'progress'
|
|
||||||
cur_workorder.production_id.state = 'progress'
|
|
||||||
quality_check = self.env['quality.check'].search(
|
|
||||||
[('workorder_id', '=', self.id)])
|
|
||||||
for check_order in quality_check:
|
|
||||||
if check_order.point_id.is_inspect:
|
|
||||||
check_order.quality_state = 'waiting'
|
|
||||||
else:
|
else:
|
||||||
check_order.quality_state = 'none'
|
next_workorder = None
|
||||||
|
if next_workorder:
|
||||||
|
next_state = next_workorder.state
|
||||||
|
if next_state not in ['pending', 'waiting', 'ready']:
|
||||||
|
raise UserError('下工序已经开始,无法回退')
|
||||||
|
if next_workorder.is_subcontract:
|
||||||
|
next_workorder.picking_ids.write({'state': 'waiting'})
|
||||||
|
next_workorder.state = 'pending'
|
||||||
|
self.time_ids.date_end = None
|
||||||
|
cur_workorder.state = 'progress'
|
||||||
|
cur_workorder.production_id.state = 'progress'
|
||||||
|
quality_check = self.env['quality.check'].search(
|
||||||
|
[('workorder_id', '=', self.id)])
|
||||||
|
for check_order in quality_check:
|
||||||
|
if check_order.point_id.is_inspect:
|
||||||
|
check_order.quality_state = 'waiting'
|
||||||
|
else:
|
||||||
|
check_order.quality_state = 'none'
|
||||||
|
|
||||||
def _compute_working_users(self):
|
def _compute_working_users(self):
|
||||||
super()._compute_working_users()
|
super()._compute_working_users()
|
||||||
@@ -1592,25 +1600,17 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
len(done_workorder) == len(
|
len(done_workorder) == len(
|
||||||
record.production_id.workorder_ids.filtered(lambda wo: wo.state != 'cancel'))):
|
record.production_id.workorder_ids.filtered(lambda wo: wo.state != 'cancel'))):
|
||||||
is_production_id = True
|
is_production_id = True
|
||||||
if record.routing_type in ['解除装夹'] or (
|
|
||||||
record.is_rework is True and record.routing_type in ['装夹预调']):
|
|
||||||
for workorder in record.production_id.workorder_ids:
|
|
||||||
if workorder.processing_panel == record.processing_panel:
|
|
||||||
rfid_code = workorder.rfid_code
|
|
||||||
if record.is_rework is not True:
|
|
||||||
workorder.write({'rfid_code_old': rfid_code, 'rfid_code': False})
|
|
||||||
elif workorder.routing_type != '装夹预调' and workorder.state != 'rework':
|
|
||||||
workorder.write({'rfid_code_old': False, 'rfid_code': False})
|
|
||||||
elif workorder.routing_type == '装夹预调' and workorder.state != 'rework':
|
|
||||||
workorder.write({'rfid_code_old': rfid_code, 'rfid_code': False})
|
|
||||||
self.env['stock.lot'].sudo().search([('rfid', '=', rfid_code)]).write(
|
|
||||||
{'tool_material_status': '可用'})
|
|
||||||
if workorder.rfid_code:
|
|
||||||
raise ValidationError(f'【{workorder.name}】工单解绑失败,请重新点击完成按钮!!!')
|
|
||||||
# workorder.rfid_code_old = rfid_code
|
|
||||||
# workorder.rfid_code = False
|
|
||||||
logging.info('workorder.rfid_code:%s' % workorder.rfid_code)
|
|
||||||
|
|
||||||
|
if record.routing_type in ['解除装夹']:
|
||||||
|
rfid_code = record.rfid_code
|
||||||
|
work_ids = record.production_id.workorder_ids.filtered(
|
||||||
|
lambda wo: wo.processing_panel == record.processing_panel and wo.state != 'rework')
|
||||||
|
work_ids.write({'rfid_code_old': rfid_code, 'rfid_code': False})
|
||||||
|
self.env['stock.lot'].sudo().search([('rfid', '=', rfid_code)]).write(
|
||||||
|
{'tool_material_status': '可用'})
|
||||||
|
if any(wo.rfid_code for wo in work_ids):
|
||||||
|
raise ValidationError(f'【{record.name}】工单解绑失败,请重新点击完成按钮!!!')
|
||||||
|
logging.info('work_ids.rfid_code:%s' % [wo.rfid_code for wo in work_ids])
|
||||||
if is_production_id is True:
|
if is_production_id is True:
|
||||||
logging.info('product_qty:%s' % record.production_id.product_qty)
|
logging.info('product_qty:%s' % record.production_id.product_qty)
|
||||||
for move_raw_id in record.production_id.move_raw_ids:
|
for move_raw_id in record.production_id.move_raw_ids:
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ class ProductionWizard(models.TransientModel):
|
|||||||
mrp_workorder_list = self.mrp_production_id.workorder_ids.filtered(lambda kw: kw.rfid_code)
|
mrp_workorder_list = self.mrp_production_id.workorder_ids.filtered(lambda kw: kw.rfid_code)
|
||||||
for workorder in mrp_workorder_list:
|
for workorder in mrp_workorder_list:
|
||||||
rfid_code = workorder.rfid_code
|
rfid_code = workorder.rfid_code
|
||||||
workorder.filtered(lambda wo: wo.routing_type == '装夹预调' and wo.rfid_code is not False).write(
|
workorder.filtered(lambda wo: wo.routing_type == '装夹预调' and wo.rfid_code and wo.state != 'rework').write(
|
||||||
{'rfid_code_old': rfid_code, 'rfid_code': False})
|
{'rfid_code_old': rfid_code, 'rfid_code': False})
|
||||||
workorder.filtered(lambda wo: (wo.routing_type != '装夹预调' and
|
workorder.filtered(lambda wo: (wo.routing_type != '装夹预调' and
|
||||||
(wo.rfid_code_old is not False or wo.rfid_code is not False))).write(
|
(wo.rfid_code_old or wo.rfid_code) and wo.state != 'rework')).write(
|
||||||
{'rfid_code_old': False, 'rfid_code': False})
|
{'rfid_code_old': False, 'rfid_code': False})
|
||||||
|
|
||||||
if self.is_remanufacture is True:
|
if self.is_remanufacture is True:
|
||||||
|
|||||||
@@ -126,18 +126,27 @@ class ReworkWizard(models.TransientModel):
|
|||||||
# 2、返工CNC工单和装夹预调工单则自动解绑RFID
|
# 2、返工CNC工单和装夹预调工单则自动解绑RFID
|
||||||
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
|
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
|
||||||
|
|
||||||
vals_list = [{
|
# for order in rework_workorder_ids:
|
||||||
'id': order.id,
|
# order.write({
|
||||||
'rfid_code_old': order.rfid_code,
|
# 'rfid_code_old': order.rfid_code,
|
||||||
'rfid_code': False
|
# 'rfid_code': False
|
||||||
} for order in rework_workorder_ids]
|
# })
|
||||||
rework_workorder_ids.write(vals_list)
|
|
||||||
if clamp_workorder_ids:
|
|
||||||
for clamp_workorder_id in clamp_workorder_ids:
|
|
||||||
self.production_id.workorder_ids.filtered(lambda wk: (
|
|
||||||
wk.processing_panel == clamp_workorder_id.processing_panel)).write({'rfid_code': None})
|
|
||||||
# 返工工单状态设置为【返工】
|
# 返工工单状态设置为【返工】
|
||||||
rework_workorder_ids.write({'state': 'rework'})
|
rework_workorder_ids.write({'state': 'rework'})
|
||||||
|
if clamp_workorder_ids:
|
||||||
|
for clamp_workorder_id in clamp_workorder_ids:
|
||||||
|
# 清除返工的装夹预调工单以及其他同面返工工单的RFID并保存rfid记录
|
||||||
|
self.production_id.workorder_ids.filtered(lambda wk: (
|
||||||
|
wk.processing_panel == clamp_workorder_id.processing_panel
|
||||||
|
and wk.state == 'rework' and wk.rfid_code)).write(
|
||||||
|
{'rfid_code_old': clamp_workorder_id.rfid_code, 'rfid_code': None})
|
||||||
|
# 清除返工的装夹预调工单同面的非返工工单的RFID
|
||||||
|
self.production_id.workorder_ids.filtered(lambda wk: (
|
||||||
|
wk.processing_panel == clamp_workorder_id.processing_panel and wk.state != 'rework')).write(
|
||||||
|
{'rfid_code_old': None, 'rfid_code': None})
|
||||||
|
# 清除其他返工工单的RFID
|
||||||
|
for work in rework_workorder_ids.filtered(lambda wk: wk.rfid_code):
|
||||||
|
work.write({'rfid_code_old': work.rfid_code, 'rfid_code': None})
|
||||||
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
|
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
|
||||||
workorders_values = []
|
workorders_values = []
|
||||||
for work in rework_workorder_ids:
|
for work in rework_workorder_ids:
|
||||||
@@ -164,8 +173,12 @@ class ReworkWizard(models.TransientModel):
|
|||||||
# ====新工单绑定rfid===
|
# ====新工单绑定rfid===
|
||||||
for new_work_id in new_work_ids:
|
for new_work_id in new_work_ids:
|
||||||
if new_work_id.routing_type in ['CNC加工', '解除装夹']:
|
if new_work_id.routing_type in ['CNC加工', '解除装夹']:
|
||||||
new_work_id.write({'rfid_code': self.production_id.workorder_ids.filtered(
|
# 获取new_work_id同一个加工面已经绑定rfid的非返工的装夹预调工单
|
||||||
lambda wk: wk.sequence == new_work_id.sequence - 1).rfid_code})
|
work_id = self.production_id.workorder_ids.filtered(
|
||||||
|
lambda wk: (wk.processing_panel == new_work_id.processing_panel and wk.rfid_code
|
||||||
|
and wk.routing_type == '装夹预调' and wk.state != 'rework'))
|
||||||
|
if work_id:
|
||||||
|
new_work_id.write({'rfid_code': work_id.rfid_code})
|
||||||
self.production_id.detection_result_ids.filtered(
|
self.production_id.detection_result_ids.filtered(
|
||||||
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
|
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
|
||||||
panels = [] # 返工的加工面
|
panels = [] # 返工的加工面
|
||||||
@@ -219,11 +232,13 @@ class ReworkWizard(models.TransientModel):
|
|||||||
self.production_id.get_new_program(panel_name)
|
self.production_id.get_new_program(panel_name)
|
||||||
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
|
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
|
||||||
# ============= 处理CNC加工加工工单的 CNC程序和cmm程序 信息=============
|
# ============= 处理CNC加工加工工单的 CNC程序和cmm程序 信息=============
|
||||||
for cnc_work in new_work_ids.filtered(lambda wk: wk.name == 'CNC加工' or wk.name == '人工线下加工'):
|
for cnc_work in new_work_ids.filtered(
|
||||||
|
lambda wk: wk.name == 'CNC加工' or wk.name == '人工线下加工'):
|
||||||
ret = {'programming_list': []}
|
ret = {'programming_list': []}
|
||||||
old_cnc_rework = max(self.production_id.workorder_ids.filtered(
|
old_cnc_rework = max(self.production_id.workorder_ids.filtered(
|
||||||
lambda crw: crw.processing_panel == cnc_work.processing_panel
|
lambda crw: crw.processing_panel == cnc_work.processing_panel
|
||||||
and crw.state == 'rework' and (crw.routing_type == 'CNC加工' or crw.routing_type == '人工线下加工')),
|
and crw.state == 'rework' and (
|
||||||
|
crw.routing_type == 'CNC加工' or crw.routing_type == '人工线下加工')),
|
||||||
key=lambda w: w.create_date
|
key=lambda w: w.create_date
|
||||||
)
|
)
|
||||||
# 获取当前工单的CNC程序和cmm程序
|
# 获取当前工单的CNC程序和cmm程序
|
||||||
@@ -265,7 +280,8 @@ class ReworkWizard(models.TransientModel):
|
|||||||
new_cnc_workorder = self.production_id.workorder_ids.filtered(
|
new_cnc_workorder = self.production_id.workorder_ids.filtered(
|
||||||
lambda ap1: ap1.processing_panel == cnc_work.processing_panel
|
lambda ap1: ap1.processing_panel == cnc_work.processing_panel
|
||||||
and ap1.state not in (
|
and ap1.state not in (
|
||||||
'rework', 'done') and (ap1.routing_type == 'CNC加工' or ap1.routing_type == '人工线下加工')
|
'rework', 'done') and (
|
||||||
|
ap1.routing_type == 'CNC加工' or ap1.routing_type == '人工线下加工')
|
||||||
)
|
)
|
||||||
if not new_cnc_workorder.cnc_ids:
|
if not new_cnc_workorder.cnc_ids:
|
||||||
new_cnc_workorder.write({
|
new_cnc_workorder.write({
|
||||||
@@ -302,7 +318,8 @@ class ReworkWizard(models.TransientModel):
|
|||||||
'is_rework': False})
|
'is_rework': False})
|
||||||
# ==================申请重新编程=======================
|
# ==================申请重新编程=======================
|
||||||
if self.is_reprogramming is True:
|
if self.is_reprogramming is True:
|
||||||
self.production_id.update_programming_state(trigger_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
|
self.production_id.update_programming_state(
|
||||||
|
trigger_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
|
||||||
self.production_id.write(
|
self.production_id.write(
|
||||||
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
||||||
# ================= 返工完成,制造订单状态置为加工中 ==============
|
# ================= 返工完成,制造订单状态置为加工中 ==============
|
||||||
@@ -323,7 +340,7 @@ class ReworkWizard(models.TransientModel):
|
|||||||
for p in production_id.detection_result_ids.filtered(
|
for p in production_id.detection_result_ids.filtered(
|
||||||
lambda ap1: ap1.handle_result == '待处理'):
|
lambda ap1: ap1.handle_result == '待处理'):
|
||||||
if p.processing_panel is not False and p.processing_panel not in panel_arr:
|
if p.processing_panel is not False and p.processing_panel not in panel_arr:
|
||||||
if len(panel_arr)>0:
|
if len(panel_arr) > 0:
|
||||||
panel_arr += ','.join(p.processing_panel)
|
panel_arr += ','.join(p.processing_panel)
|
||||||
else:
|
else:
|
||||||
panel_arr = p.processing_panel
|
panel_arr = p.processing_panel
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ class SFMessagePurchaseRequest(models.Model):
|
|||||||
_inherit = ['purchase.request', 'jikimo.message.dispatch']
|
_inherit = ['purchase.request', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
original_state = self.state
|
original_state = {}
|
||||||
|
for item in self:
|
||||||
|
original_state.update({f'{item.id}': item.state})
|
||||||
res = super(SFMessagePurchaseRequest, self).write(vals)
|
res = super(SFMessagePurchaseRequest, self).write(vals)
|
||||||
if vals.get('state') == 'approved' and original_state != 'approved':
|
for item in self:
|
||||||
self.add_queue('采购申请待处理通知')
|
if vals.get('state') == 'approved' and original_state.get(f'{item.id}') != 'approved':
|
||||||
|
item.add_queue('采购申请待处理通知')
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_message(self, message_queue_ids):
|
def _get_message(self, message_queue_ids):
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class ReSaleOrder(models.Model):
|
|||||||
|
|
||||||
model_display_version = fields.Char('模型展示版本', default="v1")
|
model_display_version = fields.Char('模型展示版本', default="v1")
|
||||||
|
|
||||||
|
contract_code = fields.Char('合同编号')
|
||||||
|
contract_date = fields.Date('合同日期')
|
||||||
contract_document_id = fields.Many2one('documents.document', string='合同文件')
|
contract_document_id = fields.Many2one('documents.document', string='合同文件')
|
||||||
contract_file = fields.Binary(related='contract_document_id.datas', string='合同文件内容')
|
contract_file = fields.Binary(related='contract_document_id.datas', string='合同文件内容')
|
||||||
contract_file_name = fields.Char(related='contract_document_id.attachment_id.name', string='文件名')
|
contract_file_name = fields.Char(related='contract_document_id.attachment_id.name', string='文件名')
|
||||||
@@ -374,12 +376,13 @@ class RePurchaseOrder(models.Model):
|
|||||||
|
|
||||||
@api.depends('partner_id')
|
@api.depends('partner_id')
|
||||||
def _compute_user_id(self):
|
def _compute_user_id(self):
|
||||||
if not self.user_id:
|
for item in self:
|
||||||
if self.partner_id:
|
if not item.user_id:
|
||||||
self.user_id = self.partner_id.purchase_user_id.id
|
if item.partner_id:
|
||||||
# self.state = 'purchase'
|
item.user_id = item.partner_id.purchase_user_id.id
|
||||||
else:
|
# self.state = 'purchase'
|
||||||
self.user_id = self.env.user.id
|
else:
|
||||||
|
item.user_id = item.env.user.id
|
||||||
|
|
||||||
@api.constrains('order_line')
|
@api.constrains('order_line')
|
||||||
def check_order_line(self):
|
def check_order_line(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user