From 129f8a4d7d6b1da5672b4b398f05c33385cb09e6 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 10 Jul 2024 16:23:24 +0800 Subject: [PATCH 1/5] =?UTF-8?q?1=E3=80=81=E9=87=8D=E6=9E=84=E5=B7=A5?= =?UTF-8?q?=E5=8D=95cnc=E7=BC=96=E7=A8=8B=E7=94=A8=E5=88=80=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=96=B9=E6=B3=95=EF=BC=9B=E5=88=B6=E9=80=A0=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E3=80=81=E5=B7=A5=E5=8D=95=E3=80=81cnc=E7=BC=96?= =?UTF-8?q?=E7=A8=8B=E5=8D=95=E6=B7=BB=E5=8A=A0=E5=88=80=E5=85=B7=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=B9=B6=E4=B8=94=E6=A0=B9?= =?UTF-8?q?=E6=8D=AEcnc=E7=BC=96=E7=A8=8B=E5=8D=95=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97=E5=88=B6?= =?UTF-8?q?=E9=80=A0=E8=AE=A2=E5=8D=95=E3=80=81=E5=B7=A5=E5=8D=95=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5=E7=9A=84=E5=80=BC?= =?UTF-8?q?=EF=BC=9B=E5=88=B6=E9=80=A0=E8=AE=A2=E5=8D=95form=E9=A1=B5?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B1=95=E7=A4=BA=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5=EF=BC=9B2?= =?UTF-8?q?=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E6=8B=86=E8=A7=A3?= =?UTF-8?q?=E5=8D=95=E5=88=80=E5=85=B7=E7=89=A9=E6=96=99=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E8=B4=A7=E4=BD=8D=E6=B7=BB=E5=8A=A0=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E6=B7=BB=E5=8A=A0=E4=B8=BA=E5=8F=AA=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=89=80=E5=B1=9E=E8=B4=A7=E5=8C=BA=E6=98=AF=E5=88=80=E5=85=B7?= =?UTF-8?q?=E6=88=BF=E7=9A=84=E8=B4=A7=E4=BD=8D=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 15 +++++ sf_manufacturing/models/mrp_workorder.py | 15 +++++ .../views/mrp_production_addional_change.xml | 8 ++- sf_manufacturing/views/mrp_workorder_view.xml | 2 + sf_tool_management/models/base.py | 61 +++++++----------- sf_tool_management/models/mrp_workorder.py | 63 +++++++++++++++++-- 6 files changed, 120 insertions(+), 44 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 36bdb13d..f9492a37 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -24,6 +24,21 @@ class MrpProduction(models.Model): work_order_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')], string='工单状态', default='未排') + 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'): + item.tool_state = '2' + elif item.workorder_ids.filtered(lambda a: a.tool_state == '1'): + 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 4b9371c2..4fefc154 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -158,6 +158,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): """ diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index b5e348b9..bfda7c93 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -87,9 +87,11 @@ - + + + + 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/mrp_workorder.py b/sf_tool_management/models/mrp_workorder.py index e21941ca..a2886add 100644 --- a/sf_tool_management/models/mrp_workorder.py +++ b/sf_tool_management/models/mrp_workorder.py @@ -10,6 +10,8 @@ class CNCprocessing(models.Model): _inherit = 'sf.cnc.processing' _description = 'CNC加工用刀检测' + tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='刀具状态', default='0') + # ==========MES装刀指令接口========== # def register_cnc_processing(self, knife_plan): # config = self.env['res.config.settings'].get_values() @@ -29,13 +31,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 From 134e23ea2fc82c145bfa32d8662ea3308a183b54 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 10 Jul 2024 16:25:18 +0800 Subject: [PATCH 2/5] =?UTF-8?q?1=E3=80=81=E9=87=8D=E6=9E=84=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E5=B7=A5=E5=BA=8F=E7=9A=84=E7=94=9F=E6=88=90=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 130 +++++++++++++--------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index f9492a37..0b4da7cc 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -536,70 +536,90 @@ class MrpProduction(models.Model): def _reset_work_order_sequence(self): for rec in self: - sequence_list = {} + workorder_ids = rec.workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')) # 产品模型类型 model_type_id = rec.product_id.product_model_type_id # 产品加工面板 model_processing_panel = rec.product_id.model_processing_panel - if model_type_id: - if model_processing_panel: - tmpl_num = 1 - panel_list = model_processing_panel.split(',') - for panel in panel_list: - panel_sequence_list = {} - # 成品工序 - product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids - if product_routing_tmpl_ids: - for tmpl_id in product_routing_tmpl_ids: - panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) - tmpl_num += 1 - sequence_list.update({panel: panel_sequence_list}) - # 表面工艺工序 - # 模型类型的表面工艺工序模版 - surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids - # 产品选择的表面工艺 - model_process_parameters_ids = rec.product_id.model_process_parameters_ids - process_dict = {} - if model_process_parameters_ids: - for process_parameters_id in model_process_parameters_ids: - process_id = process_parameters_id.process_id - for surface_tmpl_id in surface_tmpl_ids: - if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id: - surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name - process_dict.update({int(process_id.category_id.code): '%s-%s' % ( - surface_tmpl_name, process_parameters_id.name)}) - process_list = sorted(process_dict.keys()) - for process_num in process_list: - sequence_list.update({process_dict.get(process_num): tmpl_num}) - tmpl_num += 1 - # 坯料工序 - tmpl_num = 1 - embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids - if embryo_routing_tmpl_ids: - for tmpl_id in embryo_routing_tmpl_ids: - sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) + if not workorder_ids: + sequence_list = {} + if model_type_id: + if model_processing_panel: + tmpl_num = 1 + panel_list = model_processing_panel.split(',') + for panel in panel_list: + panel_sequence_list = {} + # 成品工序 + product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids + if product_routing_tmpl_ids: + for tmpl_id in product_routing_tmpl_ids: + panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) + tmpl_num += 1 + sequence_list.update({panel: panel_sequence_list}) + # 表面工艺工序 + # 模型类型的表面工艺工序模版 + surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids + # 产品选择的表面工艺 + model_process_parameters_ids = rec.product_id.model_process_parameters_ids + process_dict = {} + if model_process_parameters_ids: + for process_parameters_id in model_process_parameters_ids: + process_id = process_parameters_id.process_id + for surface_tmpl_id in surface_tmpl_ids: + if process_id == surface_tmpl_id.route_workcenter_id.surface_technics_id: + surface_tmpl_name = surface_tmpl_id.route_workcenter_id.name + process_dict.update({int(process_id.category_id.code): '%s-%s' % ( + surface_tmpl_name, process_parameters_id.name)}) + process_list = sorted(process_dict.keys()) + for process_num in process_list: + sequence_list.update({process_dict.get(process_num): tmpl_num}) tmpl_num += 1 + # 坯料工序 + tmpl_num = 1 + embryo_routing_tmpl_ids = model_type_id.embryo_routing_tmpl_ids + if embryo_routing_tmpl_ids: + for tmpl_id in embryo_routing_tmpl_ids: + sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) + tmpl_num += 1 + else: + raise ValidationError('该产品【加工面板】为空!') else: - raise ValidationError('该产品【加工面板】为空!') + raise ValidationError('该产品没有选择【模版类型】!') - else: - raise ValidationError('该产品没有选择【模版类型】!') - - for work in rec.workorder_ids: - if sequence_list.get(work.name): - work.sequence = sequence_list[work.name] - elif sequence_list.get(work.processing_panel): - processing_panel = sequence_list.get(work.processing_panel) - if processing_panel.get(work.name): - work.sequence = processing_panel[work.name] + for work in rec.workorder_ids: + if sequence_list.get(work.name): + work.sequence = sequence_list[work.name] + elif sequence_list.get(work.processing_panel): + processing_panel = sequence_list.get(work.processing_panel) + if processing_panel.get(work.name): + work.sequence = processing_panel[work.name] + else: + raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name) else: raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name) - else: - raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name) - # if work.name == '获取CNC加工程序': - # work.button_start() - # #work.fetchCNC() - # work.button_finish() + # 当单个面触发返工时,将新生成的工单插入到返工工单下方,并且后面的所以工单工序重排 + elif rec.workorder_ids.filtered(lambda item: item.sequence == 0): + # 获取新增的返工工单 + work_ids = rec.workorder_ids.filtered(lambda item: item.sequence == 0) + # 获取当前返工面最后一个工单工序 + sequence_max = sorted( + rec.workorder_ids.filtered(lambda item: item.processing_panel == work_ids[0].processing_panel), + key=lambda item: item.sequence, reverse=True)[0].sequence + # 对当前返工工单之后的工单工序进行重排 + work_order_ids = rec.workorder_ids.filtered(lambda item: item.sequence > sequence_max) + for work_id in work_order_ids: + work_id.sequence = work_id.sequence + 3 + # 生成新增的返工工单的工序 + # 成品工序 + panel_sequence_list = {} + product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids + if product_routing_tmpl_ids: + for tmpl_id in product_routing_tmpl_ids: + sequence_max += 1 + panel_sequence_list.update({tmpl_id.route_workcenter_id.name: sequence_max}) + for work_id in work_ids: + if panel_sequence_list.get(work_id.name): + work_id.sequence = panel_sequence_list[work_id.name] # 创建工单并进行排序 def _create_workorder(self, item): From 77815c45a0519967fcaecb1ef3093c052897f0d8 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 11 Jul 2024 16:37:20 +0800 Subject: [PATCH 3/5] =?UTF-8?q?1=E3=80=81=E5=BD=93=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E5=88=B0=E7=BC=BA=E5=88=80=E5=B7=A5=E5=8D=95=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E4=BB=8E=E5=88=80?= =?UTF-8?q?=E5=85=B7=E6=88=BF=E5=87=BA=E5=BA=93=E5=88=B0=E7=BA=BF=E8=BE=B9?= =?UTF-8?q?=E5=88=80=E6=9E=B6=E6=97=B6=EF=BC=8C=E6=9B=B4=E6=94=B9cnc?= =?UTF-8?q?=E7=BC=96=E7=A8=8B=E5=8D=95=E7=9A=84=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=8A=B6=E6=80=81=E4=B8=BA=E6=AD=A3=E5=B8=B8=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 4 ++-- sf_manufacturing/models/mrp_workorder.py | 2 ++ sf_tool_management/models/functional_tool.py | 15 +++++++++++++++ sf_tool_management/models/mrp_workorder.py | 2 -- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 0b4da7cc..0c3ab335 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -32,9 +32,9 @@ class MrpProduction(models.Model): def _compute_tool_state(self): for item in self: if item: - if item.workorder_ids.filtered(lambda a: a.tool_state == '2'): + 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'): + 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' diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 4fefc154..944bf402 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1135,6 +1135,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_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 a2886add..f3476864 100644 --- a/sf_tool_management/models/mrp_workorder.py +++ b/sf_tool_management/models/mrp_workorder.py @@ -10,8 +10,6 @@ class CNCprocessing(models.Model): _inherit = 'sf.cnc.processing' _description = 'CNC加工用刀检测' - tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='刀具状态', default='0') - # ==========MES装刀指令接口========== # def register_cnc_processing(self, knife_plan): # config = self.env['res.config.settings'].get_values() From 37977be8620916916169f2ec593f37072ecbad2a Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 16 Jul 2024 10:40:18 +0800 Subject: [PATCH 4/5] =?UTF-8?q?1=E3=80=81=E5=B7=A5=E5=8D=95=E8=A7=A3?= =?UTF-8?q?=E7=BB=91=E6=97=B6=E6=B7=BB=E5=8A=A0=E4=BA=8C=E6=AC=A1=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=98=AF=E5=90=A6=E8=A7=A3=E7=BB=91=E6=88=90=E5=8A=9F?= =?UTF-8?q?=EF=BC=9B2=E3=80=81=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=8E=A5=E5=8F=A3=E6=B7=BB=E5=8A=A0=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E4=BF=A1=E6=81=AF=E2=80=98=E5=A4=87=E6=B3=A8=E2=80=99?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workorder.py | 18 ++++++++++-------- sf_sale/models/sale_order.py | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 944bf402..eb036294 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 @@ -1019,13 +1019,15 @@ class ResMrpWorkOrder(models.Model): if workorder.state != 'done': is_production_id = False if record.routing_type == '解除装夹': - for workorder in record.production_id.workorder_ids: - if workorder.processing_panel == record.processing_panel: - rfid_code = workorder.rfid_code - workorder.write({'rfid_code_old': rfid_code, - 'rfid_code': False}) - workorder.rfid_code_old = rfid_code - workorder.rfid_code = False + for workorder in record.production_id.workorder_ids.filtered( + lambda a: a.processing_panel == record.processing_panel): + 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: diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index 2791c760..b7da1898 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -113,6 +113,7 @@ class ReSaleOrder(models.Model): 'price_unit': product.list_price, 'product_uom_qty': item['number'], 'model_glb_file': base64.b64decode(item['model_file']), + 'remark': item.get('remark') } return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) From 25ac346cb748465d3e52f7272d7dcf6b45df908f Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 18 Jul 2024 16:33:41 +0800 Subject: [PATCH 5/5] =?UTF-8?q?1=E3=80=81cnc=E7=BC=96=E7=A8=8B=E5=8D=95tre?= =?UTF-8?q?e=E8=A7=86=E5=9B=BE=E5=B1=95=E7=A4=BA=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=88=B6=E9=80=A0=E8=AE=A2=E5=8D=95=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E7=8A=B6=E6=80=81=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=97=B6=E5=BD=93=E5=B7=A5=E5=8D=95=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=8A=B6=E6=80=81=E5=8F=98=E5=8C=96=E6=97=B6=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E7=BC=BA=E5=88=80=E5=A4=87=E6=B3=A8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E7=8A=B6=E6=80=81=E4=B8=BA=E6=97=A0?= =?UTF-8?q?=E6=95=88=E5=88=80=E7=9A=84=E5=A4=87=E6=B3=A8=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=9B3=E3=80=81=E4=BC=98=E5=8C=96=E5=BD=93=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=88=80=E5=85=B7=E4=BB=8E=E3=80=90=E5=88=80=E5=85=B7?= =?UTF-8?q?=E6=88=BF=E3=80=91=E5=88=B0=E3=80=90=E5=88=B6=E9=80=A0=E5=89=8D?= =?UTF-8?q?=E3=80=91=E6=97=B6=E8=BF=9B=E8=A1=8C=E6=A0=A1=E9=AA=8C=EF=BC=8C?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=98=AF=E5=90=A6=E4=B8=BA=E5=88=B6=E9=80=A0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=89=80=E7=BC=BA=E7=9A=84=E5=88=80=EF=BC=8C?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=98=AF=E5=88=99=E4=BF=AE=E6=94=B9cnc?= =?UTF-8?q?=E7=BC=96=E7=A8=8B=E5=8D=95=E5=88=80=E5=85=B7=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=B8=BA=E6=AD=A3=E5=B8=B8=EF=BC=9B4=E3=80=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96cnc=E7=94=A8=E5=88=80=E6=A0=A1=E9=AA=8C=EF=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E6=97=A0=E6=95=88=E5=88=80=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86(=E6=97=A0=E6=95=88=E5=88=80=E6=97=B6?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E8=BF=94=E5=B7=A5=E6=B5=81=E7=A8=8B=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E7=94=9F=E6=88=90=E6=A3=80=E6=B5=8B=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E6=95=B0=E6=8D=AE)=EF=BC=8C=E4=BC=98=E5=8C=96=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=9A=84=E5=BE=85=E5=A4=84=E7=90=86=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/views/default_delivery.xml | 1 + sf_manufacturing/models/mrp_production.py | 29 ++++++- .../views/mrp_production_addional_change.xml | 1 + sf_manufacturing/views/mrp_workorder_view.xml | 1 + sf_tool_management/models/functional_tool.py | 16 ++-- sf_tool_management/models/mrp_workorder.py | 79 ++++++++++++++----- sf_tool_management/models/stock.py | 37 +++++++++ 7 files changed, 130 insertions(+), 34 deletions(-) diff --git a/sf_machine_connect/views/default_delivery.xml b/sf_machine_connect/views/default_delivery.xml index 0238c736..c9f3c07c 100644 --- a/sf_machine_connect/views/default_delivery.xml +++ b/sf_machine_connect/views/default_delivery.xml @@ -11,6 +11,7 @@ + diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index b191e514..aabec83e 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -26,22 +26,43 @@ 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) + tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', readonly=True) + tool_state_remark2 = 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', '返工')): + workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ('rework', '返工')) + if workorder_ids.filtered(lambda a: a.tool_state == '2'): item.tool_state = '2' - elif item.workorder_ids.filtered(lambda a: a.tool_state == '1' and a.state not in ('rework', '返工')): + elif workorder_ids.filtered(lambda a: a.tool_state == '1'): + tool_state_remark = '' + data = {} + # 获取所有缺刀工单加工面对应缺的刀 + for work in workorder_ids.filtered(lambda a: a.tool_state == '1'): + if work.processing_panel not in list(data.keys()): + data.update({work.processing_panel: []}) + for cnc in work.cnc_ids.filtered(lambda a: a.tool_state == '1'): + if cnc.cutting_tool_name not in data[work.processing_panel]: + data[work.processing_panel].append(cnc.cutting_tool_name) + # 按格式生成缺刀提示信息 + for key in data: + if data.get(key) and not data.get(key): + if tool_state_remark != '': + tool_state_remark = f'{tool_state_remark}\n{key}缺刀:{data.get(key)}' + else: + tool_state_remark = f'{key}缺刀:{data.get(key)}' item.tool_state = '1' + item.tool_state_remark = tool_state_remark + item.tool_state_remark2 = '' else: item.tool_state = '0' + item.tool_state_remark = '' + item.tool_state_remark2 = '' # state = fields.Selection(selection_add=[ # ('pending_scheduling', '待排程'), diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index 8003eb4d..8d70027c 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -99,6 +99,7 @@ +