From 0bea93ea4652060994e66eab48d12a394f00f78f Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 27 Nov 2024 17:54:59 +0800 Subject: [PATCH 1/9] =?UTF-8?q?1=E3=80=81=E6=B7=BB=E5=8A=A0=E8=BF=94?= =?UTF-8?q?=E5=B7=A5=E5=90=91=E5=AF=BC=E4=B8=AD=E9=80=89=E6=8B=A9=E8=BF=94?= =?UTF-8?q?=E5=B7=A5=E5=B7=A5=E5=8D=95=E9=99=90=E5=88=B6=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/wizard/rework_wizard.py | 45 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/sf_manufacturing/wizard/rework_wizard.py b/sf_manufacturing/wizard/rework_wizard.py index bb787c11..eeae9ae9 100644 --- a/sf_manufacturing/wizard/rework_wizard.py +++ b/sf_manufacturing/wizard/rework_wizard.py @@ -4,6 +4,7 @@ import logging from odoo.exceptions import UserError, ValidationError from datetime import datetime from odoo import models, api, fields, _ +from odoo.tools import groupby class ReworkWizard(models.TransientModel): @@ -37,6 +38,30 @@ class ReworkWizard(models.TransientModel): tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state') + @api.onchange('hidden_workorder_ids') + def _onchange_hidden_workorder_ids(self): + for item in self: + if item.hidden_workorder_ids not in ['', None, False]: + hidden_workorder_list = item.hidden_workorder_ids.split(',') + # 获取加工面对应需要返工的工单 + rw_ids = item.workorder_ids.filtered( + lambda w: str(w.ids[0]) in hidden_workorder_list and w.processing_panel not in ['', None, False]) + grouped_rw_ids = {key: list(group) for key, group in groupby(rw_ids, key=lambda w: w.processing_panel)} + for panel, panel_rw_ids in grouped_rw_ids.items(): + work_ids = item.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel) + if len(work_ids) == 3 and len(panel_rw_ids) != 3: + for work_id in work_ids: + if work_id not in panel_rw_ids: + hidden_workorder_list.append(str(work_id.ids[0])) + elif len(work_ids) == 2 and len(panel_rw_ids) < 2 and panel_rw_ids[0].name == 'CNC加工': + if rw_ids.filtered(lambda w: (w.sequence < panel_rw_ids[0].sequence + and w.processing_panel != panel_rw_ids[0].processing_panel)): + hidden_workorder_list.append(str(work_ids.filtered( + lambda w: (w.processing_panel == panel_rw_ids[0].processing_panel + and w.name == '装夹预调')).ids[0])) + hidden_workorder_list.sort() + item.hidden_workorder_ids = ','.join(hidden_workorder_list) + def confirm(self): if self.routing_type in ['装夹预调', 'CNC加工']: self.is_clamp_measure = False @@ -58,16 +83,16 @@ class ReworkWizard(models.TransientModel): # 1、当制造订单内ZM面的工单都已完成时,返工勾选工序时只能勾选上ZM面的所有工序进行返工 # 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选 # 获取已完成的标准工单 - done_normative_workorder_ids = self.workorder_ids.filtered( - lambda w: w.state == 'done' and w.processing_panel is not False) - # 获取需要返工的标准工单 - rework_normative_workorder_ids = rework_workorder_ids.filtered( - lambda w: w.processing_panel is not False) - if rework_normative_workorder_ids: - for rw in rework_normative_workorder_ids: - if len(done_normative_workorder_ids.filtered( - lambda w: w.processing_panel == rw.processing_panel)) == 3: - pass + # done_normative_workorder_ids = self.workorder_ids.filtered( + # lambda w: w.state == 'done' and w.processing_panel is not False) + # # 获取需要返工的标准工单 + # rework_normative_workorder_ids = rework_workorder_ids.filtered( + # lambda w: w.processing_panel is not False) + # if rework_normative_workorder_ids: + # for rw in rework_normative_workorder_ids: + # if len(done_normative_workorder_ids.filtered( + # lambda w: w.processing_panel == rw.processing_panel)) == 3: + # pass else: raise ValidationError('请选择返工工单!!!') if rework_workorder_ids: From f1e70d2c668f7f8026d067274a67a3c572ee059b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 28 Nov 2024 11:36:32 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=AF=A2=E4=BB=B7?= =?UTF-8?q?=E5=8D=95=E4=B8=AD=E8=87=AA=E5=8A=A8=E5=8C=96=E4=BA=A7=E7=BA=BF?= =?UTF-8?q?=E5=8A=A0=E5=B7=A5=E7=9A=84=E8=AE=A2=E5=8D=95=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=BC=96=E7=A8=8B=E5=8D=95=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 20e740f3..25819fe1 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -317,7 +317,7 @@ class StockRule(models.Model): if production_item.product_id.id in product_id_to_production_names: # 同一个产品多个制造订单对应一个编程单和模型库 # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递 - if not production_item.programming_no and production.production_type == '自动化产线加工': + if not production_item.programming_no and production_item.production_type == '自动化产线加工': if not production_programming.programming_no: production_item.fetchCNC( ', '.join(product_id_to_production_names[production_item.product_id.id])) From 5eea260618618a35f18870f164ee4d8ca5ed6c96 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Thu, 28 Nov 2024 13:38:14 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=93=E5=82=A8?= =?UTF-8?q?=E5=B2=97=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/security/ir.model.access.csv | 1 + sf_manufacturing/views/mrp_production_addional_change.xml | 7 +++++++ sf_quality/security/ir.model.access.csv | 1 + 3 files changed, 9 insertions(+) diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 24c38570..cdf62571 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -52,6 +52,7 @@ access_mrp_routing_workcenter_manager_group_sf_mrp_user,mrp.routing.workcenter.m access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0 +access_mrp_bom_line_group_sf_stock_user,mrp_bom_line_group_sf_stock_user,mrp.model_mrp_bom_line,sf_base.group_sf_stock_user,1,1,1,0 access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0 access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0 access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0 diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index 7a626ff2..461c2321 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -744,5 +744,12 @@ groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager" sequence="1"/> + + \ No newline at end of file diff --git a/sf_quality/security/ir.model.access.csv b/sf_quality/security/ir.model.access.csv index 19818982..907c115b 100644 --- a/sf_quality/security/ir.model.access.csv +++ b/sf_quality/security/ir.model.access.csv @@ -11,6 +11,7 @@ access_quality_point_group_sf_mrp_manager,quality_point_group_sf_mrp_manager,qua access_quality_check_group_quality,quality_check_group_quality,quality.model_quality_check,sf_base.group_quality,1,1,1,0 access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0 access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0 +access_quality_check_group_sf_stock_user,quality_check_group_sf_stock_user,quality.model_quality_check,sf_base.group_sf_stock_user,1,0,0,0 access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0 access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0 access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0 From 8ff73d564779a02ed0bf28e24e6738e28e78a431 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 28 Nov 2024 15:09:11 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workorder.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index d50b1df2..6858ccab 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1095,8 +1095,7 @@ class ResMrpWorkOrder(models.Model): # ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]========================== if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework' or workorder.production_id.schedule_state != '已排' - or len( - workorder.production_id.picking_ids.filtered(lambda w: w.state not in ['done', 'cancel'])) != 0 + or workorder.production_id.reservation_state not in ['assigned'] or workorder.production_id.workorder_ids.filtered( lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']): if workorder.state != 'waiting': From 96171013d61c9b6542651291877cddbdc05b8eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 28 Nov 2024 15:10:45 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_plan/models/custom_plan.py | 73 +++++++++++++++-------------------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index e7785ad4..7fcec54e 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -232,41 +232,37 @@ class sf_production_plan(models.Model): raise ValidationError("未选择生产线") else: # 自动化产线加工 - if record.production_id.production_type == '自动化产线加工': - if record.production_id.workorder_ids: - last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now() - for item in record.production_id.workorder_ids: - if item.name == 'CNC加工': - # 将同一个面的所有工单筛选出来 - workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel) - routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( - [('name', '=', 'CNC加工')], limit=1) - # 设置一个小的开始时间 - item.date_planned_start = datetime.now() - timedelta(days=100) - item.date_planned_finished = last_cnc_start + timedelta( - minutes=routing_workcenter.time_cycle) - item.date_planned_start = last_cnc_start - record.sudo().production_id.plan_start_processing_time = item.date_planned_start - item.duration_expected = routing_workcenter.time_cycle - pre_duration , next_duration = record.calculate_plan_time(item, workorder_list) - record.date_planned_finished = item.date_planned_finished - # 计算下一个cnc工单的开始时间 - last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration) - # 没有工单也能排程 - else: - # 人工线下加工只排第一张工单 - if record.production_id.workorder_ids: - item = record.production_id.workorder_ids[0] - last_wo_start = record.date_planned_start if record.date_planned_start else datetime.now() - routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( - [('name', '=', item.routing_type)], limit=1) - item.date_planned_start = datetime.now() - timedelta(days=100) - item.date_planned_finished = last_wo_start + timedelta( + if record.production_id.workorder_ids: + # 自动化产线加工 + if record.production_id.production_type == '自动化产线加工': + # 找到第一张CNC加工工单 + first_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[0] + date_start = record.date_planned_start if record.date_planned_start else datetime.now() + routing_workcenter = first_cnc_workorder.technology_design_id.route_id + # 设置一个小的开始时间 + first_cnc_workorder.date_planned_start = datetime.now() - timedelta(days=100) + first_cnc_workorder.date_planned_finished = date_start + timedelta( minutes=routing_workcenter.time_cycle) - item.date_planned_start = last_wo_start + first_cnc_workorder.date_planned_start = date_start + record.sudo().production_id.plan_start_processing_time = first_cnc_workorder.date_planned_start + first_cnc_workorder.duration_expected = routing_workcenter.time_cycle + record.calculate_plan_time(first_cnc_workorder, record.production_id.workorder_ids) + # 找到最后一张CNC加工工单 + last_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[-1] + record.date_planned_finished = last_cnc_workorder.date_planned_finished + else: + # 人工线下加工只排第一张工单 + item = record.production_id.workorder_ids[0] + wo_start = record.date_planned_start if record.date_planned_start else datetime.now() + item.date_planned_start = datetime.now() - timedelta(days=100) + item.date_planned_finished = wo_start + timedelta( + minutes=routing_workcenter.time_cycle) + item.date_planned_start = wo_start record.sudo().production_id.plan_start_processing_time = item.date_planned_start item.duration_expected = routing_workcenter.time_cycle - record.calculate_plan_time(item, item) + record.calculate_plan_time(item, record.production_id.workorder_ids) + last_cnc_workorder = record.production_id.workorder_ids[-1] + record.date_planned_finished = last_cnc_workorder.date_planned_finished record.state = 'done' # record.production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排' @@ -328,38 +324,31 @@ class sf_production_plan(models.Model): if workorder.id == item.id: item_position = index break - routing_workcenters = self.env['mrp.routing.workcenter'].sudo().search([]) - # 记录所有前序工序时长 - previous_workorder_duration = 0 for i in range(item_position, -1, -1): if i < 1: break current_workorder = workorder_list[i] next_workorder = workorder_list[i - 1] - routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] + routing_workcenter = next_workorder.technology_design_id.route_id # 设置一个小的开始时间 next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_finished = current_workorder.date_planned_start next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta( minutes=routing_workcenter.time_cycle) next_workorder.duration_expected = routing_workcenter.time_cycle - previous_workorder_duration += routing_workcenter.time_cycle - # 记录所有后续工序时长 - next_workorder_duration = 0 + for i in range(item_position, len(workorder_list) - 1): if i > len(workorder_list) - 1: break current_workorder = workorder_list[i] next_workorder = workorder_list[i + 1] - routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] + routing_workcenter = next_workorder.technology_design_id.route_id # 设置一个小的开始时间 next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta( minutes=routing_workcenter.time_cycle) next_workorder.date_planned_start = current_workorder.date_planned_finished next_workorder.duration_expected = routing_workcenter.time_cycle - next_workorder_duration += routing_workcenter.time_cycle - return previous_workorder_duration, next_workorder_duration def calculate_plan_time_after(self, item, workorder_id_list): """ From d57cc591159a69e1269eac3471edf9339ce11d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 28 Nov 2024 15:20:56 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E7=A8=8B?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_plan/models/custom_plan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index 7fcec54e..4c4e4b30 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -254,6 +254,7 @@ class sf_production_plan(models.Model): # 人工线下加工只排第一张工单 item = record.production_id.workorder_ids[0] wo_start = record.date_planned_start if record.date_planned_start else datetime.now() + routing_workcenter = item.technology_design_id.route_id item.date_planned_start = datetime.now() - timedelta(days=100) item.date_planned_finished = wo_start + timedelta( minutes=routing_workcenter.time_cycle) From 942aa469e3e167cc7ec574274b4cbee126bdcedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 28 Nov 2024 15:21:54 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E7=A8=8B?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_plan/models/custom_plan.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index 4c4e4b30..147caa96 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -319,6 +319,9 @@ class sf_production_plan(models.Model): def calculate_plan_time(self, item, workorder_list): """ 根据CNC工单的时间去计算之前的其他工单的开始结束时间 + param: + item: 基准工单(根据该工单的开始结束时间去计算其他工单的开始结束时间) + workorder_list: 需排程的工单列表 """ item_position = 0 for index, workorder in enumerate(workorder_list): From 7362f0cd301d1b53bcfc0df461296d6b8ce4a0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 28 Nov 2024 15:41:39 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9D=AF=E6=96=99?= =?UTF-8?q?=E5=86=97=E4=BD=99=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/views/model_type_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index f0ffd81a..0f8b3085 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -31,7 +31,7 @@
- + From 2c37dbf5c40afb045c801e5d049f41e73027e5b9 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 28 Nov 2024 15:51:54 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E5=88=B6=E9=80=A0=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 232b4907..65be98c7 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -331,6 +331,9 @@ class MrpProduction(models.Model): production.state = 'pending_cam' if production.is_rework is True: production.state = 'rework' + if (production.state == 'rework' and production.tool_state == '0' + and production.schedule_state == '已排' and production.is_rework is False): + production.state = 'pending_cam' # if production.state == 'pending_cam': # if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')): # production.state = 'done' @@ -353,6 +356,7 @@ class MrpProduction(models.Model): if production.tool_state == '2': production.state = 'rework' + # 退回调整 def technology_back_adjust(self): process_parameters = []