diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index b965a63e..b191e514 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -26,7 +26,23 @@ class MrpProduction(models.Model):
work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
string='工单状态', default='未排')
+
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
+ tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
+ store=True, compute='_compute_tool_state')
+ tool_state_remark = fields.Text(string='功能刀具状态备注', readonly=True)
+
+ @api.depends('workorder_ids.tool_state')
+ def _compute_tool_state(self):
+ for item in self:
+ if item:
+ if item.workorder_ids.filtered(lambda a: a.tool_state == '2' and a.state not in ('rework', '返工')):
+ item.tool_state = '2'
+ elif item.workorder_ids.filtered(lambda a: a.tool_state == '1' and a.state not in ('rework', '返工')):
+ item.tool_state = '1'
+ else:
+ item.tool_state = '0'
+
# state = fields.Selection(selection_add=[
# ('pending_scheduling', '待排程'),
# ('pending_processing', '待加工'),
diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py
index b065284b..2be4d90f 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -13,7 +13,7 @@ from dateutil.relativedelta import relativedelta
# import subprocess
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.addons.sf_base.commons.common import Common
-from odoo.exceptions import UserError
+from odoo.exceptions import UserError,ValidationError
from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController
@@ -159,6 +159,21 @@ class ResMrpWorkOrder(models.Model):
# 加工图纸
processing_drawing = fields.Binary(string='加工图纸')
+ # 功能刀具状态
+ tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
+ store=True, compute='_compute_tool_state')
+
+ @api.depends('cnc_ids.tool_state')
+ def _compute_tool_state(self):
+ for item in self:
+ if item:
+ if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
+ item.tool_state = '2'
+ elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
+ item.tool_state = '1'
+ else:
+ item.tool_state = '0'
+
@api.depends('production_id')
def _compute_save_name(self):
"""
@@ -1064,6 +1079,7 @@ class ResMrpWorkOrder(models.Model):
for workorder in record.production_id.workorder_ids:
if workorder.state != 'done':
is_production_id = False
+
if record.routing_type in ['解除装夹'] or (
record.is_rework is True and record.routing_type in ['装夹预调']) or (
record.test_results in ['返工', '报废'] and record.routing_type in ['CNC加工']):
@@ -1072,8 +1088,11 @@ class ResMrpWorkOrder(models.Model):
rfid_code = workorder.rfid_code
workorder.write({'rfid_code_old': rfid_code,
'rfid_code': False})
+ if workorder.rfid_code:
+ raise ValidationError(f'【{workorder.name}】工单解绑失败,请重新点击完成按钮!!!')
# workorder.rfid_code_old = rfid_code
# workorder.rfid_code = False
+
if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']:
logging.info('product_qty:%s' % record.production_id.product_qty)
for move_raw_id in record.production_id.move_raw_ids:
@@ -1193,6 +1212,8 @@ class CNCprocessing(models.Model):
program_path = fields.Char('程序文件路径')
program_create_date = fields.Datetime('程序创建日期')
+ tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='刀具状态', default='0')
+
# mrs下发编程单创建CNC加工
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
cnc_processing = None
diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml
index ca4659e5..8003eb4d 100644
--- a/sf_manufacturing/views/mrp_production_addional_change.xml
+++ b/sf_manufacturing/views/mrp_production_addional_change.xml
@@ -97,6 +97,8 @@
+
+
-
+
+
+
diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml
index 5fa77224..5ca1db7c 100644
--- a/sf_manufacturing/views/mrp_workorder_view.xml
+++ b/sf_manufacturing/views/mrp_workorder_view.xml
@@ -18,6 +18,7 @@
+
@@ -120,6 +121,7 @@
+
diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py
index b77e6469..5156a295 100644
--- a/sf_tool_management/models/base.py
+++ b/sf_tool_management/models/base.py
@@ -313,42 +313,27 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None,
'sf_functional_tool_assembly_id': None})
- def create_cam_work_plan(self, cnc_processing_ids):
+ def create_cam_work_plan(self, cnc_processing):
"""
根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
"""
- for cnc_processing in cnc_processing_ids:
- status = False
- if cnc_processing.cutting_tool_name:
- functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
- [('name', '=', cnc_processing.cutting_tool_name)])
- if functional_tools:
- for functional_tool in functional_tools:
- if functional_tool.on_tool_stock_num == 0:
- if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
- status = True
- else:
- status = True
- if status:
- knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
- 'name': cnc_processing.workorder_id.production_id.name,
- 'cam_procedure_code': cnc_processing.program_name,
- 'filename': cnc_processing.cnc_id.name,
- 'functional_tool_name': cnc_processing.cutting_tool_name,
- 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
- 'process_type': cnc_processing.processing_type,
- 'margin_x_y': float(cnc_processing.margin_x_y),
- 'margin_z': float(cnc_processing.margin_z),
- 'finish_depth': float(cnc_processing.depth_of_processing_z),
- 'extension_length': float(cnc_processing.cutting_tool_extension_length),
- 'shank_model': cnc_processing.cutting_tool_handle_type,
- 'estimated_processing_time': cnc_processing.estimated_processing_time,
- })
- logging.info('CAM工单程序用刀计划创建成功!!!')
- # 创建装刀请求
- knife_plan.apply_for_tooling()
- else:
- logging.info('功能刀具【%s】满足CNC用刀需求!!!' % cnc_processing.cutting_tool_name)
+ knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
+ 'name': cnc_processing.workorder_id.production_id.name,
+ 'cam_procedure_code': cnc_processing.program_name,
+ 'filename': cnc_processing.cnc_id.name,
+ 'functional_tool_name': cnc_processing.cutting_tool_name,
+ 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
+ 'process_type': cnc_processing.processing_type,
+ 'margin_x_y': float(cnc_processing.margin_x_y),
+ 'margin_z': float(cnc_processing.margin_z),
+ 'finish_depth': float(cnc_processing.depth_of_processing_z),
+ 'extension_length': float(cnc_processing.cutting_tool_extension_length),
+ 'shank_model': cnc_processing.cutting_tool_handle_type,
+ 'estimated_processing_time': cnc_processing.estimated_processing_time,
+ })
+ logging.info('CAM工单程序用刀计划创建成功!!!')
+ # 创建装刀请求
+ knife_plan.apply_for_tooling()
def unlink_cam_plan(self, production):
for item in production:
@@ -834,7 +819,7 @@ class FunctionalToolDismantle(models.Model):
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num',
store=True)
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
- domain="[('product_id', 'in', (integral_product_id, False))]")
+ domain="[('product_id', 'in', (integral_product_id, False)),('location_id.name', '=', '刀具房')]")
# 刀片
blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num',
@@ -844,7 +829,7 @@ class FunctionalToolDismantle(models.Model):
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True)
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
- domain="[('product_id', 'in', (blade_product_id, False))]")
+ domain="[('product_id', 'in', (blade_product_id, False)),('location_id.name', '=', '刀具房')]")
# 刀杆
bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num',
@@ -854,7 +839,7 @@ class FunctionalToolDismantle(models.Model):
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True)
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
- domain="[('product_id', 'in', (bar_product_id, False))]")
+ domain="[('product_id', 'in', (bar_product_id, False)),('location_id.name', '=', '刀具房')]")
# 刀盘
pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num',
@@ -864,7 +849,7 @@ class FunctionalToolDismantle(models.Model):
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True)
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
- domain="[('product_id', 'in', (pad_product_id, False))]")
+ domain="[('product_id', 'in', (pad_product_id, False)),('location_id.name', '=', '刀具房')]")
# 夹头
chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num',
@@ -874,7 +859,7 @@ class FunctionalToolDismantle(models.Model):
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True)
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
- domain="[('product_id', 'in', (chuck_product_id, False))]")
+ domain="[('product_id', 'in', (chuck_product_id, False)),('location_id.name', '=', '刀具房')]")
@api.onchange('functional_tool_id')
def _onchange_freight(self):
diff --git a/sf_tool_management/models/functional_tool.py b/sf_tool_management/models/functional_tool.py
index 4e791fe5..4138bfe3 100644
--- a/sf_tool_management/models/functional_tool.py
+++ b/sf_tool_management/models/functional_tool.py
@@ -115,6 +115,8 @@ class FunctionalCuttingToolEntity(models.Model):
# 新刀入库到线边
item.create_stock_move(pre_manufacturing_id, location_id)
item.current_shelf_location_id = location_id.id
+ # 对该刀进行校验(校验是否为制造订单所缺的刀)
+ item.cnc_function_tool_use_verify()
# 中控反馈该位置没有刀
else:
@@ -255,6 +257,15 @@ class FunctionalCuttingToolEntity(models.Model):
result['domain'] = [('id', '=', self.safe_inventory_id.id)]
return result
+ def cnc_function_tool_use_verify(self):
+ """
+ cnc程序用刀可用校验
+ """
+ cnc_processing_ids = self.env['sf.cnc.processing'].search(
+ [('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
+ if cnc_processing_ids:
+ cnc_processing_ids.sudo().write({'tool_state': '0'})
+
def tool_inventory_displacement_out(self):
"""
机床当前刀库实时信息接口,功能刀具出库
@@ -265,6 +276,10 @@ class FunctionalCuttingToolEntity(models.Model):
self.create_stock_move(stock_location_id, False)
self.current_location_id = stock_location_id.id
self.current_shelf_location_id = False
+
+ if self.current_location_id.name == '刀具房':
+ # 对该刀进行校验(校验是否为制造订单所缺的刀)
+ self.cnc_function_tool_use_verify()
# self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
# self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
# self.functional_tool_name_id.tool_groups_id)
diff --git a/sf_tool_management/models/mrp_workorder.py b/sf_tool_management/models/mrp_workorder.py
index e21941ca..f3476864 100644
--- a/sf_tool_management/models/mrp_workorder.py
+++ b/sf_tool_management/models/mrp_workorder.py
@@ -29,13 +29,66 @@ class CNCprocessing(models.Model):
# else:
# raise ValidationError("MES装刀指令发送失败")
+ def cnc_tool_checkout(self, cnc_processing_ids):
+ """
+ 根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
+ """
+ cam_id = self.env['sf.cam.work.order.program.knife.plan']
+ production_ids = [] # 制造订单集
+ datas = {} # 缺刀/无效刀集
+ for cnc_processing in cnc_processing_ids:
+ production_name = cnc_processing.production_id.name # 制造订单
+ processing_panel = cnc_processing.workorder_id.processing_panel # 加工面
+ if not datas.get(production_name):
+ datas.update({production_name: {}})
+ production_ids.append(cnc_processing.production_id)
+ if not datas.get(production_name).get(processing_panel):
+ datas.get(production_name).update({processing_panel: {'缺刀': [], '无效刀': []}})
+ if cnc_processing.cutting_tool_name:
+ tool_name = cnc_processing.cutting_tool_name
+ # 检验CNC用刀是否是功能刀具清单中的刀具
+ tool_inventory_id = self.env['sf.tool.inventory'].sudo().search([('name', '=', tool_name)])
+ if not tool_inventory_id:
+ datas[production_name][processing_panel]['无效刀'].append(cnc_processing.cutting_tool_name)
+ cnc_processing.tool_state = '2'
+ # todo 无效刀处理逻辑
+
+ # 跳过本次循环
+ continue
+ # 校验CNC用刀在系统是否存在
+ functional_tools = self.env['sf.functional.cutting.tool.entity'].sudo().search(
+ [('tool_name_id', '=', tool_inventory_id.id), ('functional_tool_status', '=', '正常')])
+ # 判断线边、机内是否有满足条件的刀
+ if not functional_tools.filtered(lambda p: p.current_location in ('线边刀库', '机内刀库')):
+ datas[production_name][processing_panel]['缺刀'].append(cnc_processing.cutting_tool_name)
+ cnc_processing.tool_state = '1'
+ # 判断是否有满足条件的刀
+ if not functional_tools:
+ # 创建CAM申请装刀记录
+ cam_id.create_cam_work_plan(cnc_processing)
+ logging.info('成功调用CAM工单程序用刀计划创建方法!!!')
+ for production_id in production_ids:
+ if production_id:
+ data = datas.get(production_id.name)
+ tool_state_remark = ''
+ # todo 对无效刀信息进行处理
+
+ # 对缺刀信息进行处理
+ for key in data:
+ if tool_state_remark != '':
+ tool_state_remark = f'{tool_state_remark}\n{key}缺刀:{data.get(key).get("缺刀")}'
+ else:
+ tool_state_remark = f'{key}缺刀:{data.get(key).get("缺刀")}'
+ if production_id.tool_state == '1':
+ production_id.write({
+ 'tool_state_remark': tool_state_remark
+ })
+
@api.model_create_multi
def create(self, vals):
obj = super(CNCprocessing, self).create(vals)
- for item in obj:
- # 调用CAM工单程序用刀计划创建方法
- self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(item)
- logging.info('成功调用CAM工单程序用刀计划创建方法!!!')
+ # 调用CAM工单程序用刀计划创建方法
+ self.cnc_tool_checkout(obj)
return obj