From 10e995ec7f76dc935da66f40e9240a915ad35302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 16 Jun 2025 16:25:01 +0800 Subject: [PATCH 01/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=BA=A7=E9=87=8F=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 71 ++++++++++++------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index cefa4ba8..b94d70bf 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -377,7 +377,11 @@ class Sf_Dashboard_Connect(http.Controller): line_list_obj = request.env['sf.production.line'].sudo().search([('name', 'ilike', 'CNC')]) line_list = list(map(lambda x: x.name, line_list_obj)) # print('line_list: %s' % line_list) - res['LineList'] = line_list + res['LineList'] = ['业绩总览'] + res['LineList'] += line_list + res['LineList'].append('人工线下加工中心') + # 增加“业绩总览”与“人工线下加工中心” + except Exception as e: res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} @@ -401,37 +405,57 @@ class Sf_Dashboard_Connect(http.Controller): try: plan_obj = request.env['sf.production.plan'].sudo() - production_obj = request.env['mrp.production'].sudo() + # production_obj = request.env['mrp.production'].sudo() work_order_obj = request.env['mrp.workorder'].sudo() line_list = ast.literal_eval(kw['line_list']) + + line_list_obj = request.env['sf.production.line'].sudo().search([('name', 'ilike', 'CNC')]) + cnc_line_list = list(map(lambda x: x.name, line_list_obj)) # print('line_list: %s' % line_list) for line in line_list: + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + plan_domain = [] + quality_check_domain = [('production_line_id.name', 'in', cnc_line_list + ['人工线下加工中心'])] + # production_domain = [] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + plan_domain = [('production_type', '=', '人工线下加工')] + quality_check_domain = [('production_line_id.name', '=', line)] + # production_domain = [] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] + plan_domain = [('production_line_id.name', '=', line)] + quality_check_domain = [('operation_id.name', '=', 'CNC加工')] + # production_domain = [] # # 工单计划量 # plan_data_total_counts = production_obj.search_count( # [('production_line_id.name', '=', line), ('state', 'not in', ['cancel']), # ('active', '=', True)]) # 工单计划量切换为CNC工单 - plan_data_total_counts = work_order_obj.search_count( - [('production_line_id.name', '=', line), ('id', '!=', 8061), - ('state', 'in', ['ready', 'progress', 'done']), ('routing_type', '=', 'CNC加工')]) + plan_data_total_counts = work_order_obj.search_count(work_order_domain + [ + ('id', '!=', 8061), + ('state', 'in', ['ready', 'progress', 'done']) + ]) # # 工单完成量 # plan_data_finish_counts = plan_obj.search_count( # [('production_line_id.name', '=', line), ('state', 'in', ['finished'])]) # 工单完成量切换为CNC工单 - plan_data_finish_counts = work_order_obj.search_count( - [('production_line_id.name', '=', line), - ('state', 'in', ['done']), ('routing_type', '=', 'CNC加工')]) + plan_data_finish_counts = work_order_obj.search_count(work_order_domain + [ + ('state', 'in', ['done']) + ]) # 超期完成量 # 搜索所有已经完成的工单 - plan_data_overtime = work_order_obj.search([ - ('production_line_id.name', '=', line), - ('state', 'in', ['done']), - ('routing_type', '=', 'CNC加工') + plan_data_overtime = work_order_obj.search(work_order_domain + [ + ('state', 'in', ['done']) ]) # 使用 filtered 进行字段比较 @@ -443,24 +467,21 @@ class Sf_Dashboard_Connect(http.Controller): plan_data_overtime_counts = len(plan_data_overtime_counts) # 查找符合条件的生产计划记录 - plan_data = plan_obj.search([ - ('production_line_id.name', '=', line), - ]) + plan_data = plan_obj.search(plan_domain) # 过滤出那些检测结果状态为 '返工' 或 '报废' 的记录 # faulty_plans = plan_data.filtered(lambda p: any( # result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids # )) - faulty_plans = request.env['quality.check'].sudo().search([ - ('operation_id.name', '=', 'CNC加工'), + faulty_plans = request.env['quality.check'].sudo().search(quality_check_domain + [ ('quality_state', 'in', ['fail']) ]) # 查找制造订单取消与归档的数量 - cancel_order_count = production_obj.search_count( - [('production_line_id.name', '=', line), ('state', 'in', ['cancel']), - ('active', '=', False)]) + # cancel_order_count = production_obj.search_count( + # [('production_line_id.name', '=', line), ('state', 'in', ['cancel']), + # ('active', '=', False)]) # 计算符合条件的记录数量 # plan_data_fault_counts = len(faulty_plans) + cancel_order_count @@ -468,8 +489,9 @@ class Sf_Dashboard_Connect(http.Controller): # 工单返工数量 - plan_data_rework_counts = plan_obj.search_count( - [('production_line_id.name', '=', line), ('production_id.state', 'in', ['rework'])]) + plan_data_rework_counts = plan_obj.search_count(plan_domain + [ + ('production_id.state', 'in', ['rework']) + ]) # 工单完成率 finishe_rate = round( @@ -479,8 +501,9 @@ class Sf_Dashboard_Connect(http.Controller): plan_data_progress_deviation = plan_data_total_counts - plan_data_finish_counts - plan_data_fault_counts # 完成记录 - plan_data_finish_orders = plan_obj.search( - [('production_line_id.name', '=', line), ('state', 'in', ['finished'])]) + plan_data_finish_orders = plan_obj.search(plan_domain + [ + ('state', 'in', ['finished']) + ]) # # 检测量 # detection_nums = 0 From 61034c34244f8fed1cb9425e813b8e6dba0f7550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 16 Jun 2025 17:33:55 +0800 Subject: [PATCH 02/33] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index b94d70bf..4f8fdce3 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -438,20 +438,24 @@ class Sf_Dashboard_Connect(http.Controller): # ('active', '=', True)]) # 工单计划量切换为CNC工单 - plan_data_total_counts = work_order_obj.search_count(work_order_domain + [ + plan_data_total = work_order_obj.search(work_order_domain + [ ('id', '!=', 8061), ('state', 'in', ['ready', 'progress', 'done']) ]) + plan_data_total_counts = sum(plan_data_total.mapped('qty_produced')) + # # 工单完成量 # plan_data_finish_counts = plan_obj.search_count( # [('production_line_id.name', '=', line), ('state', 'in', ['finished'])]) # 工单完成量切换为CNC工单 - plan_data_finish_counts = work_order_obj.search_count(work_order_domain + [ + plan_data_finish = work_order_obj.search(work_order_domain + [ ('state', 'in', ['done']) ]) + plan_data_finish_counts = sum(plan_data_finish.mapped('qty_produced')) + # 超期完成量 # 搜索所有已经完成的工单 plan_data_overtime = work_order_obj.search(work_order_domain + [ @@ -464,7 +468,8 @@ class Sf_Dashboard_Connect(http.Controller): ) # 获取数量 - plan_data_overtime_counts = len(plan_data_overtime_counts) + # plan_data_overtime_counts = len(plan_data_overtime_counts) + plan_data_overtime_counts = sum(plan_data_overtime_counts.mapped('qty_produced')) # 查找符合条件的生产计划记录 plan_data = plan_obj.search(plan_domain) @@ -485,7 +490,8 @@ class Sf_Dashboard_Connect(http.Controller): # 计算符合条件的记录数量 # plan_data_fault_counts = len(faulty_plans) + cancel_order_count - plan_data_fault_counts = len(faulty_plans) + # plan_data_fault_counts = len(faulty_plans) + plan_data_fault_counts = sum(faulty_plans.workorder_id.mapped('qty_produced')) # 工单返工数量 @@ -631,11 +637,22 @@ class Sf_Dashboard_Connect(http.Controller): date_list.append(current_date) current_date += timedelta(days=1) return date_list + for line in line_list: date_field_name = 'date_finished' # 替换为你模型中的实际字段名 order_counts = [] + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] + if time_unit == 'hour': time_intervals = get_time_intervals(begin_time, end_time, time_unit) print('============================= %s' % time_intervals) @@ -652,9 +669,7 @@ class Sf_Dashboard_Connect(http.Controller): # (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 # ]) - orders = request.env['mrp.workorder'].sudo().search([ - ('routing_type', '=', 'CNC加工'), # 将第一个条件合并进来 - ('production_line_id.name', '=', line), + orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ ('state', 'in', ['done']), (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) @@ -674,25 +689,22 @@ class Sf_Dashboard_Connect(http.Controller): for date in date_list: next_day = date + timedelta(days=1) - orders = request.env['mrp.workorder'].sudo().search( - [('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']), - ('routing_type', '=', 'CNC加工'), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) + orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['done']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) - rework_orders = request.env['mrp.workorder'].sudo().search( - [('production_id.production_line_id.name', '=', line), ('state', 'in', ['rework']), - ('routing_type', '=', 'CNC加工'), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) - not_passed_orders = request.env['mrp.workorder'].sudo().search( - [('production_id.production_line_id.name', '=', line), ('state', 'in', ['scrap', 'cancel']), - ('routing_type', '=', 'CNC加工'), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) + rework_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['rework']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) + not_passed_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['scrap', 'cancel']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) order_counts.append({ 'date': date.strftime('%Y-%m-%d'), 'order_count': len(orders), From 84846fb3daddd6ca46aada284df2eed14eba2aea Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 18 Jun 2025 16:54:15 +0800 Subject: [PATCH 03/33] =?UTF-8?q?bfm=E5=86=85=E9=83=A8=E4=B8=8B=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9D=AF=E6=96=99=E9=95=BF=E5=AE=BD=E9=AB=98?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=88=B0sf=E4=BA=A7=E5=93=81-=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E5=8F=82=E6=95=B0-=E5=9D=AF=E6=96=99=E5=B0=BA?= =?UTF-8?q?=E5=AF=B8=E7=9A=84=E9=95=BF=E5=AE=BD=E9=AB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/product_template.py | 6 +++--- sf_manufacturing/models/product_template.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index a2d848c2..e4b15922 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -76,9 +76,9 @@ class ResProductTemplate(models.Model): vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), 'blank_type': item.get('blank_type'), - 'model_long': item['model_long'] + model_type.embryo_tolerance, - 'model_width': item['model_width'] + model_type.embryo_tolerance, - 'model_height': item['model_height'] + model_type.embryo_tolerance, + 'model_long': item.get('blank_length') if item.get('blank_length') else item['model_long'] + model_type.embryo_tolerance, + 'model_width': item.get('blank_width') if item.get('blank_width') else item['model_width'] + model_type.embryo_tolerance, + 'model_height': item.get('blank_height') if item.get('blank_height') else item['model_height'] + model_type.embryo_tolerance, 'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( item['model_width'] + model_type.embryo_tolerance) * ( item['model_height'] + model_type.embryo_tolerance), diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index eec6b118..5f371aed 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -897,9 +897,9 @@ class ResProductMo(models.Model): vals = { 'name': product_name, 'blank_type': item.get('blank_type'), - 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long), - 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width), - 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height), + 'model_long': item.get('blank_length') if item.get('blank_length') else self.format_float(item['model_long'] + embryo_redundancy_id.long), + 'model_width': item.get('blank_width') if item.get('blank_width') else self.format_float(item['model_width'] + embryo_redundancy_id.width), + 'model_height': item.get('blank_height') if item.get('blank_height') else self.format_float(item['model_height'] + embryo_redundancy_id.height), 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * ( item['model_width'] + embryo_redundancy_id.width) * ( item['model_height'] + embryo_redundancy_id.height)), From 790dd3dd05b777ad188750cba3cbff7f8242cf5d Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 18 Jun 2025 17:00:16 +0800 Subject: [PATCH 04/33] =?UTF-8?q?=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E8=A1=8C=E7=9A=84=E4=BA=A4=E8=B4=A7=E6=88=AA=E6=AD=A2=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=94=B9=E4=B8=BA=E5=AE=A2=E6=88=B7=E4=BA=A4=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_sale/models/sale_order.py | 2 +- sf_sale/views/sale_order_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index cab8368c..c879093e 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -292,7 +292,7 @@ class ResaleOrderLine(models.Model): manual_quotation = fields.Boolean('人工编程', default=False) model_url = fields.Char('模型文件地址') model_id = fields.Char('模型ID') - delivery_end_date = fields.Date('交货截止日期') + delivery_end_date = fields.Date('客户交期') @api.depends('embryo_redundancy_id') def _compute_is_incoming_material(self): diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml index d45a5200..3b115620 100644 --- a/sf_sale/views/sale_order_view.xml +++ b/sf_sale/views/sale_order_view.xml @@ -141,7 +141,7 @@ hide - + From e86bd59a43f5ca731041bdf3f979f82e9fcb3b23 Mon Sep 17 00:00:00 2001 From: hyyy <123@qq.com> Date: Wed, 18 Jun 2025 17:56:27 +0800 Subject: [PATCH 05/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=87=BA=E5=8E=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E6=8A=A5=E5=91=8A=E5=90=88=E6=A0=BCLOGO?= =?UTF-8?q?=E7=A7=BB=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/static/src/js/print_demand.js | 48 ++++++++++++------- .../data/insepection_report_template.xml | 2 +- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/sf_demand_plan/static/src/js/print_demand.js b/sf_demand_plan/static/src/js/print_demand.js index 5df0d02f..a05638a7 100644 --- a/sf_demand_plan/static/src/js/print_demand.js +++ b/sf_demand_plan/static/src/js/print_demand.js @@ -25,7 +25,11 @@ odoo.define('sf_demand.print_demand', function (require) { ); } + if(!$('.denmand_set').length) { + + const checked = self.getParent().radioCheck || 'all' + self.$el.prepend(`
更多设置: @@ -33,21 +37,25 @@ odoo.define('sf_demand.print_demand', function (require) { - +
`) - self.$el.prepend(` - - `); - } + setTimeout(() => { + $(`input[name=set][value=${checked}]`).prop('checked', true) + $('.denmand_set').trigger('click') + }, 100); + self.$el.prepend(` + + `); + } }); }, start: function() { @@ -106,7 +114,7 @@ odoo.define('sf_demand.print_demand', function (require) { } }, getSelectedIds: function() { - return this.state.data.map(_ => { + return this.state.data.filter(_ => !_.hide).map(_ => { return _.data.id }) }, @@ -129,16 +137,24 @@ odoo.define('sf_demand.print_demand', function (require) { // self.do_warn("打印失败", error.data.message || "未知错误"); }).finally(e => { this.getParent().reload() - }) }, _onDenmandChange(e) { const isChecked = $(e.currentTarget).find('input:checked').val() + this.getParent().radioCheck = isChecked this.$el.find('tbody').find('.o_data_row').show() - if(!isChecked) return - this.$el.find('tbody').children().each(function() { + + this.state.data.forEach(_ => { + _.hide = false + }) + const self = this + if(!isChecked || isChecked == 'all') return + this.$el.find('tbody').children('.o_data_row').each(function() { if($(this).find('td[name=type]').text() != isChecked) { + const i = $(this).index() + + self.state.data[i].hide = true $(this).hide() } }) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 14a42065..06ce9214 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -275,7 +275,7 @@ - +
From d21e0c7fd922eeaebf7a58697979fd5c51939349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 19 Jun 2025 10:54:33 +0800 Subject: [PATCH 06/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=BA=BF=E4=B8=8B=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 132 +++++++++++------- 1 file changed, 79 insertions(+), 53 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 4f8fdce3..1ba59c6b 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -417,21 +417,15 @@ class Sf_Dashboard_Connect(http.Controller): if line == '业绩总览': work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] plan_domain = [] - quality_check_domain = [('production_line_id.name', 'in', cnc_line_list + ['人工线下加工中心'])] - # production_domain = [] elif line == '人工线下加工中心': work_order_domain = [('routing_type', '=', '人工线下加工')] plan_domain = [('production_type', '=', '人工线下加工')] - quality_check_domain = [('production_line_id.name', '=', line)] - # production_domain = [] else: work_order_domain = [ ('production_line_id.name', '=', line), ('routing_type', '=', 'CNC加工') ] plan_domain = [('production_line_id.name', '=', line)] - quality_check_domain = [('operation_id.name', '=', 'CNC加工')] - # production_domain = [] # # 工单计划量 # plan_data_total_counts = production_obj.search_count( # [('production_line_id.name', '=', line), ('state', 'not in', ['cancel']), @@ -472,15 +466,15 @@ class Sf_Dashboard_Connect(http.Controller): plan_data_overtime_counts = sum(plan_data_overtime_counts.mapped('qty_produced')) # 查找符合条件的生产计划记录 - plan_data = plan_obj.search(plan_domain) + # plan_data = plan_obj.search(plan_domain) # 过滤出那些检测结果状态为 '返工' 或 '报废' 的记录 # faulty_plans = plan_data.filtered(lambda p: any( # result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids # )) - faulty_plans = request.env['quality.check'].sudo().search(quality_check_domain + [ - ('quality_state', 'in', ['fail']) + faulty_plans = work_order_obj.search(work_order_domain + [ + ('state', 'in', ['scrap', 'rework']) ]) # 查找制造订单取消与归档的数量 @@ -491,14 +485,16 @@ class Sf_Dashboard_Connect(http.Controller): # 计算符合条件的记录数量 # plan_data_fault_counts = len(faulty_plans) + cancel_order_count # plan_data_fault_counts = len(faulty_plans) - plan_data_fault_counts = sum(faulty_plans.workorder_id.mapped('qty_produced')) + plan_data_fault_counts = sum(faulty_plans.mapped('qty_produced')) # 工单返工数量 - plan_data_rework_counts = plan_obj.search_count(plan_domain + [ - ('production_id.state', 'in', ['rework']) + plan_data_rework = work_order_obj.search(plan_domain + [ + ('state', 'in', ['rework']) ]) + plan_data_rework_counts = sum(plan_data_rework.mapped('qty_produced')) + # 工单完成率 finishe_rate = round( (plan_data_finish_counts / plan_data_total_counts if plan_data_total_counts > 0 else 0), 3) @@ -563,25 +559,25 @@ class Sf_Dashboard_Connect(http.Controller): delay_rate = round((delay_num / plan_data_finish_counts if plan_data_finish_counts > 0 else 0), 3) on_time_rate = 1 - delay_rate - if plan_data: - data = { - 'plan_data_total_counts': plan_data_total_counts, - 'plan_data_finish_counts': plan_data_finish_counts, - 'plan_data_plan_counts': plan_data_total_counts, - 'plan_data_fault_counts': plan_data_fault_counts, - 'nopass_orders_counts': detection_data - len(pass_nums), - 'finishe_rate': finishe_rate, - 'plan_data_progress_deviation': plan_data_progress_deviation, - 'plan_data_rework_counts': plan_data_rework_counts, - 'on_time_rate': on_time_rate, - # 'detection_data': detection_data, - 'detection_data': plan_data_finish_counts, - 'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts, - 'plan_data_overtime_counts': plan_data_overtime_counts, - 'overtime_rate': plan_data_overtime_counts / plan_data_finish_counts - if plan_data_finish_counts > 0 else 0, - } - res['data'][line] = data + # if plan_data: + data = { + 'plan_data_total_counts': plan_data_total_counts, + 'plan_data_finish_counts': plan_data_finish_counts, + 'plan_data_plan_counts': plan_data_total_counts, + 'plan_data_fault_counts': plan_data_fault_counts, + 'nopass_orders_counts': detection_data - len(pass_nums), + 'finishe_rate': finishe_rate, + 'plan_data_progress_deviation': plan_data_progress_deviation, + 'plan_data_rework_counts': plan_data_rework_counts, + 'on_time_rate': on_time_rate, + # 'detection_data': detection_data, + 'detection_data': plan_data_finish_counts, + 'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts, + 'plan_data_overtime_counts': plan_data_overtime_counts, + 'overtime_rate': plan_data_overtime_counts / plan_data_finish_counts + if plan_data_finish_counts > 0 else 0, + } + res['data'][line] = data return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode() @@ -677,7 +673,8 @@ class Sf_Dashboard_Connect(http.Controller): # 使用小时和分钟作为键,确保每个小时的数据有独立的键 key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 - time_count_dict[key] = len(orders) + # time_count_dict[key] = len(orders) + time_count_dict[key] = sum(orders.mapped('qty_produced')) # order_counts.append() res['data'][line] = { 'finish_order_nums': time_count_dict, @@ -707,9 +704,9 @@ class Sf_Dashboard_Connect(http.Controller): ]) order_counts.append({ 'date': date.strftime('%Y-%m-%d'), - 'order_count': len(orders), - 'rework_orders': len(rework_orders), - 'not_passed_orders': len(not_passed_orders) + 'order_count': sum(orders.mapped('qty_produced')), + 'rework_orders': sum(rework_orders.mapped('qty_produced')), + 'not_passed_orders': sum(not_passed_orders.mapped('qty_produced')) }) # 外面包一层,没什么是包一层不能解决的,包一层就能区分了,类似于包一层div # 外面包一层的好处是,可以把多个数据结构打包在一起,方便前端处理 @@ -723,7 +720,7 @@ class Sf_Dashboard_Connect(http.Controller): @http.route('/api/RealTimeProduct', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") def RealTimeProduct(self, **kw): """ - 获取实时产量 + 获取实时产量(作废) :param kw: :return: """ @@ -746,6 +743,21 @@ class Sf_Dashboard_Connect(http.Controller): # 当班计划量 for line in line_list: + + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + plan_domain = [] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + plan_domain = [('production_type', '=', '人工线下加工')] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] + plan_domain = [('production_line_id.name', '=', line)] + + plan_order_nums = plan_obj.search_count( [('production_line_id.name', '=', line), ('state', 'not in', ['draft']), ('date_planned_start', '>=', begin_time), @@ -791,6 +803,7 @@ class Sf_Dashboard_Connect(http.Controller): # res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} res = {'status': 1, 'message': '成功', 'data': {}} plan_obj = request.env['sf.production.plan'].sudo() + work_order_obj = request.env['mrp.workorder'].sudo() line_list = ast.literal_eval(kw['line_list']) begin_time_str = kw['begin_time'].strip('"') end_time_str = kw['end_time'].strip('"') @@ -800,28 +813,39 @@ class Sf_Dashboard_Connect(http.Controller): not_done_data = [] done_data = [] final_data = {} + not_done_index = 1 + done_index = 1 for line in line_list: + + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] # 未完成订单 # not_done_orders = plan_obj.search( # [('production_line_id.name', '=', line), ('state', 'not in', ['finished']), # ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True) # ]) - not_done_orders = request.env['mrp.workorder'].sudo().search( - [('production_line_id.name', '=', line), ('state', 'in', ['ready', 'progress']), - ('routing_type', '=', 'CNC加工') - ]) + not_done_orders = work_order_obj.search(work_order_domain + + [('state', 'in', ['ready', 'progress'])], order='id asc' + ) # 完成订单 # 获取当前时间,并计算24小时前的时间 current_time = datetime.now() time_24_hours_ago = current_time - timedelta(hours=24) - finish_orders = plan_obj.search([ - ('production_line_id.name', '=', line), ('state', 'in', ['finished']), - ('production_id.state', 'not in', ['cancel']), ('active', '=', True), - ('actual_end_time', '>=', time_24_hours_ago) - ]) + finish_orders = work_order_obj.search(work_order_domain + [ + ('state', 'in', ['finished']), + ('production_id.state', 'not in', ['cancel']), + ('date_finished', '>=', time_24_hours_ago) + ], order='id asc') # print(finish_orders) # 获取所有未完成订单的ID列表 @@ -830,14 +854,14 @@ class Sf_Dashboard_Connect(http.Controller): finish_order_ids = [order.id for order in finish_orders] # 对ID进行排序 - sorted_order_ids = sorted(order_ids) + # sorted_order_ids = sorted(order_ids) - finish_sorted_order_ids = sorted(finish_order_ids) + # finish_sorted_order_ids = sorted(finish_order_ids) # 创建ID与序号的对应关系 - id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(sorted_order_ids)} + # id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(sorted_order_ids)} - finish_id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(finish_sorted_order_ids)} + # finish_id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(finish_sorted_order_ids)} # # 输出结果或进一步处理 # for order_id, sequence in id_to_sequence.items(): @@ -868,16 +892,17 @@ class Sf_Dashboard_Connect(http.Controller): } line_dict = { - 'sequence': id_to_sequence[order.id], + 'sequence': not_done_index, 'workorder_name': order.production_id.name, 'blank_name': blank_name, 'material': material, 'dimensions': dimensions, - 'order_qty': 1, + 'order_qty': order.qty_production, 'state': state_dict[order.state], } not_done_data.append(line_dict) + not_done_index += 1 for finish_order in finish_orders: if not finish_order.actual_end_time: @@ -896,17 +921,18 @@ class Sf_Dashboard_Connect(http.Controller): material = material_match.group(1) if material_match else 'No match found' line_dict = { - 'sequence': finish_id_to_sequence[finish_order.id], + 'sequence': done_index, 'workorder_name': finish_order.name, 'blank_name': blank_name, 'material': material, 'dimensions': dimensions, - 'order_qty': finish_order.product_qty, + 'order_qty': order.qty_produced, 'finish_time': finish_order.actual_end_time.strftime( '%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' } done_data.append(line_dict) + done_index += 1 # 开始包一层 res['data'][line] = {'not_done_data': not_done_data, 'done_data': done_data} From 8c9db7e8c8c6abfccd5f1d8e0d25116e5e2dd8ed Mon Sep 17 00:00:00 2001 From: hyyy <123@qq.com> Date: Thu, 19 Jun 2025 14:32:59 +0800 Subject: [PATCH 07/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=88=E6=A0=BClogo?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/data/insepection_report_template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 06ce9214..61a6c794 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -275,7 +275,7 @@ - +
From 55cc4906ef8b3059d37cc2597d9cf4f7ad768600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 19 Jun 2025 15:02:55 +0800 Subject: [PATCH 08/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=97=A5=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E9=87=8F=E7=BB=9F=E8=AE=A1,=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=BA=A7=E7=BA=BF=E4=BA=A7=E9=87=8F=E7=9B=B8=E5=85=B3,?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=B7=A5=E5=8D=95=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 160 ++++++++++++------ 1 file changed, 109 insertions(+), 51 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 1ba59c6b..4aaf8ff6 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -635,25 +635,32 @@ class Sf_Dashboard_Connect(http.Controller): return date_list - for line in line_list: - date_field_name = 'date_finished' # 替换为你模型中的实际字段名 - order_counts = [] + if time_unit == 'hour': + + for line in line_list: + date_field_name = 'date_finished' # 替换为你模型中的实际字段名 + order_counts = [] - if line == '业绩总览': - work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] - elif line == '人工线下加工中心': - work_order_domain = [('routing_type', '=', '人工线下加工')] - else: - work_order_domain = [ - ('production_line_id.name', '=', line), - ('routing_type', '=', 'CNC加工') - ] - - if time_unit == 'hour': + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] time_intervals = get_time_intervals(begin_time, end_time, time_unit) print('============================= %s' % time_intervals) time_count_dict = {} + plan_count_dict = {} + + orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['done']), + (date_field_name, '>=', begin_time.strftime('%Y-%m-%d %H:%M:%S')), + (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) + ]) for time_interval in time_intervals: start_time, end_time = time_interval @@ -665,55 +672,106 @@ class Sf_Dashboard_Connect(http.Controller): # (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 # ]) - orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ - ('state', 'in', ['done']), - (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), - (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) - ]) + interval_orders = orders.filtered( + lambda o: o[date_field_name] >= start_time + and o[date_field_name] <= end_time + ) # 使用小时和分钟作为键,确保每个小时的数据有独立的键 key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 # time_count_dict[key] = len(orders) - time_count_dict[key] = sum(orders.mapped('qty_produced')) + time_count_dict[key] = sum(interval_orders.mapped('qty_produced')) + + # 计划量,目前只能从mail.message中筛选出 + plan_order_messages = request.env['mail.message'].sudo().search([ + ('model', '=', 'mrp.workorder'), + ('create_date', '>=', begin_time.strftime('%Y-%m-%d %H:%M:%S')), + ('create_date', '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')), + ('tracking_value_ids.field_desc', '=', '状态'), + ('tracking_value_ids.new_value_char', '=', '就绪') + ]) + + for time_interval in time_intervals: + start_time, end_time = time_interval + + # orders = plan_obj.search([ + # ('production_line_id.name', '=', line), + # ('state', 'in', ['done']), + # (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), + # (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 + # ]) + + interval_plan_orders = plan_order_messages.filtered( + lambda o: o.create_date >= start_time + and o.create_date <= end_time + ) + + interval_orders = request.env['mrp.workorder'].sudo().browse(interval_plan_orders.mapped('res_id')) + if line == '业绩总览': + interval_orders = interval_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工']) + elif line == '人工线下加工中心': + interval_orders = interval_orders.filtered(lambda o: o.routing_type == '人工线下加工') + else: + interval_orders = interval_orders.filtered(lambda o: o.routing_type == 'CNC加工' and o.production_line_id.name == line) + + # 使用小时和分钟作为键,确保每个小时的数据有独立的键 + key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 + # time_count_dict[key] = len(orders) + plan_count_dict[key] = sum(interval_orders.mapped('qty_produced')) + # order_counts.append() res['data'][line] = { 'finish_order_nums': time_count_dict, - 'plan_order_nums': 28 + 'plan_order_nums': plan_count_dict } - return json.dumps(res) + else: - date_list = get_date_list(begin_time, end_time) + for line in line_list: + date_field_name = 'date_finished' # 替换为你模型中的实际字段名 + order_counts = [] - for date in date_list: - next_day = date + timedelta(days=1) - orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ - ('state', 'in', ['done']), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) + if line == '业绩总览': + work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] + elif line == '人工线下加工中心': + work_order_domain = [('routing_type', '=', '人工线下加工')] + else: + work_order_domain = [ + ('production_line_id.name', '=', line), + ('routing_type', '=', 'CNC加工') + ] - rework_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ - ('state', 'in', ['rework']), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) - not_passed_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ - ('state', 'in', ['scrap', 'cancel']), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) - order_counts.append({ - 'date': date.strftime('%Y-%m-%d'), - 'order_count': sum(orders.mapped('qty_produced')), - 'rework_orders': sum(rework_orders.mapped('qty_produced')), - 'not_passed_orders': sum(not_passed_orders.mapped('qty_produced')) - }) - # 外面包一层,没什么是包一层不能解决的,包一层就能区分了,类似于包一层div - # 外面包一层的好处是,可以把多个数据结构打包在一起,方便前端处理 + date_list = get_date_list(begin_time, end_time) - # date_list_dict = {line: order_counts} + for date in date_list: + next_day = date + timedelta(days=1) + orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['done']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) - res['data'][line] = order_counts + rework_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['rework']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) + not_passed_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [ + ('state', 'in', ['scrap', 'cancel']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) + order_counts.append({ + 'date': date.strftime('%Y-%m-%d'), + 'order_count': sum(orders.mapped('qty_produced')), + 'rework_orders': sum(rework_orders.mapped('qty_produced')), + 'not_passed_orders': sum(not_passed_orders.mapped('qty_produced')) + }) + # 外面包一层,没什么是包一层不能解决的,包一层就能区分了,类似于包一层div + # 外面包一层的好处是,可以把多个数据结构打包在一起,方便前端处理 + + # date_list_dict = {line: order_counts} + + res['data'][line] = order_counts return json.dumps(res) # 实时产量 @@ -799,7 +857,7 @@ class Sf_Dashboard_Connect(http.Controller): :param kw: :return: """ - + request.env['stock.warehouse'].browse(request.env.company.id).pbm_loc_id # res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} res = {'status': 1, 'message': '成功', 'data': {}} plan_obj = request.env['sf.production.plan'].sudo() From 78edf1f7eb544f231719e2d053b2df9ef823dd3d Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 19 Jun 2025 15:17:26 +0800 Subject: [PATCH 09/33] =?UTF-8?q?=E8=B4=A8=E6=A3=80=E5=8D=95=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E9=9A=90=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/views/quality_check_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_quality/views/quality_check_view.xml b/sf_quality/views/quality_check_view.xml index aed8ce4d..3798ad95 100644 --- a/sf_quality/views/quality_check_view.xml +++ b/sf_quality/views/quality_check_view.xml @@ -66,7 +66,7 @@ 不合格 - {'invisible': ['|','|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework')),'&',('quality_state', '=', 'pass'), ('test_type', '=', '出厂检验报告')]} + {'invisible': ['|','|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework')),'&',('quality_state', '=', 'pass'), ('test_type', '=', 'factory_inspection')]} 不合格 From aec2d1c516c01f04cc3fd5e4361fcaf318caa629 Mon Sep 17 00:00:00 2001 From: guyaodong Date: Thu, 19 Jun 2025 16:18:04 +0800 Subject: [PATCH 10/33] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=88=80=E5=85=B7?= =?UTF-8?q?=E6=88=BF=E6=A0=B7=E5=BC=8F=E5=92=8C=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/migrations/1.2/post-migrate.py | 6 +++ sf_warehouse/models/model.py | 20 +++++++++- .../static/src/js/custom_kanban_controller.js | 38 ++++++++++++++----- sf_warehouse/views/shelf_location.xml | 4 +- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/sf_warehouse/migrations/1.2/post-migrate.py b/sf_warehouse/migrations/1.2/post-migrate.py index f4a0d9a4..8efec3c8 100644 --- a/sf_warehouse/migrations/1.2/post-migrate.py +++ b/sf_warehouse/migrations/1.2/post-migrate.py @@ -4,8 +4,14 @@ def migrate(cr, version): env = api.Environment(cr, SUPERUSER_ID, {}) sf_shelf_model = env["sf.shelf"] sf_shelf_location_model = env["sf.shelf.location"] + + preproduction_shelf_ids = sf_shelf_location_model.get_preproduction_shelf_ids() + shelves = sf_shelf_model.search([]) for shelf in shelves: + if shelf.id not in preproduction_shelf_ids: + continue + shelf_barcode = shelf.barcode or "" if not shelf_barcode: continue diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 8b9a86e4..8b19bd81 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -470,7 +470,6 @@ class ShelfLocation(models.Model): record.display_rfid = record.product_sn_id.rfid if record.product_sn_id else '' except Exception as e: record.display_rfid = '' - _logger.error(f"计算 display_rfid 时出错: {e}") @api.depends('product_id') def _compute_tool(self): @@ -600,6 +599,24 @@ class ShelfLocation(models.Model): _layer_capacity = f"{_layer_capacity:02d}" record.kanban_show_layer_info=f"{_layer}-{_layer_capacity}" record.kanban_show_center_control_code=f"{_cc_code}" + @api.model + def get_preproduction_shelf_ids(self): + """ + 获取预生产区域的货架ID列表 + Returns: + list: 货架ID列表 + """ + query = """ + SELECT DISTINCT b.shelf_id + FROM stock_location a + LEFT JOIN sf_shelf_location b ON a.id = b.location_id + WHERE a.barcode LIKE 'WH-PREPRODUCTION' + """ + self.env.cr.execute(query) + result = self.env.cr.fetchall() + # 将结果转换为ID列表 + shelf_ids = [record[0] for record in result if record[0]] + return shelf_ids class SfShelfLocationLot(models.Model): _name = 'sf.shelf.location.lot' @@ -616,6 +633,7 @@ class SfShelfLocationLot(models.Model): for item in self: if item.qty_num > item.qty: raise ValidationError('变更数量不能比库存数量大!!!') + class SfStockMoveLine(models.Model): diff --git a/sf_warehouse/static/src/js/custom_kanban_controller.js b/sf_warehouse/static/src/js/custom_kanban_controller.js index ab3a57d6..2d591505 100644 --- a/sf_warehouse/static/src/js/custom_kanban_controller.js +++ b/sf_warehouse/static/src/js/custom_kanban_controller.js @@ -28,8 +28,18 @@ class CustomKanbanController extends KanbanController { isBaseStyle: true }); let self = this; - // 获取货架分层数据 + onWillStart(async () => { + try { + this.preproductionShelfIds = await this.orm.call( + 'sf.shelf.location', + 'get_preproduction_shelf_ids', + [] + ); + } catch (error) { + this.preproductionShelfIds = []; + } + this.searchModel.on('update', self, self._onUpdate); await this.loadShelfLayersData(); }); @@ -50,7 +60,11 @@ class CustomKanbanController extends KanbanController { let domain = this.searchModel.domain; if (domain.length > 0) { let shelfDomain = domain.find(item => item[0] === 'shelf_id'); - this.onShelfChange(shelfDomain[2]); + if (shelfDomain && shelfDomain[2] && this.preproductionShelfIds && this.preproductionShelfIds.includes(shelfDomain[2])) { + this.onShelfChange(shelfDomain[2]); + } else { + this.setKanbanStyle('sf_kanban_location_style'); + } } else { this.setKanbanStyle('sf_kanban_location_style'); } @@ -63,8 +77,7 @@ class CustomKanbanController extends KanbanController { let shelfDomain = domain.find(item => item[0] === 'shelf_id'); if (shelfDomain) { let shelfId = shelfDomain[2]; - // 如果货架ID存在,则设置相应的样式 - if (shelfId) { + if (shelfId && this.preproductionShelfIds.includes(shelfId)) { this.onShelfChange(shelfId); return; } @@ -75,7 +88,6 @@ class CustomKanbanController extends KanbanController { this.setKanbanStyle('sf_kanban_location_style'); } catch (error) { } - } // 加载所有货架的层数数据 @@ -107,10 +119,18 @@ class CustomKanbanController extends KanbanController { // 添加新类 if (isHave) kanbanViewEl.classList.add(style); } - const ghostCards = document.querySelectorAll('.o_kanban_ghost'); - ghostCards.forEach(card => { - card.remove(); - }); + + // 获取当前的搜索域 + let domain = this.searchModel.domain; + let shelfDomain = domain.find(item => item[0] === 'shelf_id'); + + // 只有当shelf_id在preproductionShelfIds中时才删除幽灵看板 + if (shelfDomain && this.preproductionShelfIds && this.preproductionShelfIds.includes(shelfDomain[2])) { + const ghostCards = document.querySelectorAll('.o_kanban_ghost'); + ghostCards.forEach(card => { + card.remove(); + }); + } } updatePagerLimit(limit) { diff --git a/sf_warehouse/views/shelf_location.xml b/sf_warehouse/views/shelf_location.xml index 8b7bf9b6..82548935 100644 --- a/sf_warehouse/views/shelf_location.xml +++ b/sf_warehouse/views/shelf_location.xml @@ -229,7 +229,7 @@
- +
From 8bd1c8a0953bd34d7bef17be6744b357555e8387 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 19 Jun 2025 16:29:31 +0800 Subject: [PATCH 11/33] =?UTF-8?q?=E5=A4=84=E7=90=86=20bfm=E5=86=85?= =?UTF-8?q?=E9=83=A8=E4=B8=8B=E5=8D=95=E5=8C=85=E5=90=AB=E5=9D=AF=E6=96=99?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E6=97=B6=EF=BC=8C=E7=94=9F=E6=88=90=E7=9A=84?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=9A=84=E5=8A=A0=E5=B7=A5=E5=8F=82=E6=95=B0?= =?UTF-8?q?-=E4=BD=93=E7=A7=AF=E6=95=B0=E6=8D=AE=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/product_template.py | 17 +++++++++++------ sf_manufacturing/models/product_template.py | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index e4b15922..b7d54518 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -73,15 +73,20 @@ class ResProductTemplate(models.Model): copy_product_id.product_tmpl_id.active = True model_type = self.env['sf.model.type'].search([], limit=1) attachment = self.attachment_create(item['model_name'], item['model_data']) + # 判断参数中是否包含 坯料尺寸(长、宽、高) + blank_bool = any(value is not None and value != 0 for value in ( + item.get('blank_length'), item.get('blank_width'), item.get('blank_height'))) if all( + key in item for key in ('blank_length', 'blank_width', 'blank_height')) else False vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), 'blank_type': item.get('blank_type'), - 'model_long': item.get('blank_length') if item.get('blank_length') else item['model_long'] + model_type.embryo_tolerance, - 'model_width': item.get('blank_width') if item.get('blank_width') else item['model_width'] + model_type.embryo_tolerance, - 'model_height': item.get('blank_height') if item.get('blank_height') else item['model_height'] + model_type.embryo_tolerance, - 'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( - item['model_width'] + model_type.embryo_tolerance) * ( - item['model_height'] + model_type.embryo_tolerance), + 'model_long': item.get('blank_length') if blank_bool else item['model_long'] + model_type.embryo_tolerance, + 'model_width': item.get('blank_width') if blank_bool else item['model_width'] + model_type.embryo_tolerance, + 'model_height': item.get('blank_height') if blank_bool else item['model_height'] + model_type.embryo_tolerance, + 'model_volume': ((item['model_long'] + model_type.embryo_tolerance) * + (item['model_width'] + model_type.embryo_tolerance) * + (item['model_height'] + model_type.embryo_tolerance)) if not blank_bool else ( + item.get('blank_length') * item.get('blank_width') * item.get('blank_height')), 'product_model_type_id': model_type.id, 'model_processing_panel': 'R', 'model_machining_precision': item['model_machining_precision'], diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 5f371aed..30d807d1 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -894,15 +894,20 @@ class ResProductMo(models.Model): if not embryo_redundancy_id: raise UserError('请先配置模型类型内的坯料冗余') product_name = self.generate_product_name(order_id, item, i) + # 判断参数中是否包含 坯料尺寸(长、宽、高) + blank_bool = any(value is not None and value != 0 for value in ( + item.get('blank_length'), item.get('blank_width'), item.get('blank_height'))) if all( + key in item for key in ('blank_length', 'blank_width', 'blank_height')) else False vals = { 'name': product_name, 'blank_type': item.get('blank_type'), - 'model_long': item.get('blank_length') if item.get('blank_length') else self.format_float(item['model_long'] + embryo_redundancy_id.long), - 'model_width': item.get('blank_width') if item.get('blank_width') else self.format_float(item['model_width'] + embryo_redundancy_id.width), - 'model_height': item.get('blank_height') if item.get('blank_height') else self.format_float(item['model_height'] + embryo_redundancy_id.height), - 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * ( - item['model_width'] + embryo_redundancy_id.width) * ( - item['model_height'] + embryo_redundancy_id.height)), + 'model_long': item.get('blank_length') if blank_bool else self.format_float(item['model_long'] + embryo_redundancy_id.long), + 'model_width': item.get('blank_width') if blank_bool else self.format_float(item['model_width'] + embryo_redundancy_id.width), + 'model_height': item.get('blank_height') if blank_bool else self.format_float(item['model_height'] + embryo_redundancy_id.height), + 'model_volume': self.format_float(((item['model_long'] + model_type.embryo_tolerance) * + (item['model_width'] + model_type.embryo_tolerance) * + (item['model_height'] + model_type.embryo_tolerance))) if not blank_bool else ( + item.get('blank_length') * item.get('blank_width') * item.get('blank_height')), 'product_model_type_id': model_type.id, 'model_processing_panel': item['processing_panel_detail'], 'model_machining_precision': item['model_machining_precision'], From 45730e2dd431fa01808e21a752c4eef0ef7c8534 Mon Sep 17 00:00:00 2001 From: hyyy <123@qq.com> Date: Fri, 20 Jun 2025 09:09:45 +0800 Subject: [PATCH 12/33] =?UTF-8?q?=E8=B4=A8=E6=A3=80PDF=E9=A2=84=E8=A7=88lo?= =?UTF-8?q?go=E7=A7=BB=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/data/insepection_report_template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 61a6c794..a2fb9932 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -148,7 +148,7 @@ - +
From d73ffab9b5a74f18684e475003f09bd4475fbd85 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 10:28:07 +0800 Subject: [PATCH 13/33] =?UTF-8?q?=E5=A4=84=E7=90=86bfm=E4=B8=8B=E5=8D=95?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/product_template.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 30d807d1..4062814e 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -904,9 +904,9 @@ class ResProductMo(models.Model): 'model_long': item.get('blank_length') if blank_bool else self.format_float(item['model_long'] + embryo_redundancy_id.long), 'model_width': item.get('blank_width') if blank_bool else self.format_float(item['model_width'] + embryo_redundancy_id.width), 'model_height': item.get('blank_height') if blank_bool else self.format_float(item['model_height'] + embryo_redundancy_id.height), - 'model_volume': self.format_float(((item['model_long'] + model_type.embryo_tolerance) * - (item['model_width'] + model_type.embryo_tolerance) * - (item['model_height'] + model_type.embryo_tolerance))) if not blank_bool else ( + 'model_volume': self.format_float(((item['model_long'] + embryo_redundancy_id.long) * + (item['model_width'] + embryo_redundancy_id.width) * + (item['model_height'] + embryo_redundancy_id.height))) if not blank_bool else ( item.get('blank_length') * item.get('blank_width') * item.get('blank_height')), 'product_model_type_id': model_type.id, 'model_processing_panel': item['processing_panel_detail'], From e7b312fb22e1f8f1db40c6195cca162f88f3e121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 10:53:31 +0800 Subject: [PATCH 14/33] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 4aaf8ff6..a028f63b 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -857,7 +857,6 @@ class Sf_Dashboard_Connect(http.Controller): :param kw: :return: """ - request.env['stock.warehouse'].browse(request.env.company.id).pbm_loc_id # res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} res = {'status': 1, 'message': '成功', 'data': {}} plan_obj = request.env['sf.production.plan'].sudo() From f38f60a6a83dcc1d6adc6c390fee803656cb4f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 11:24:39 +0800 Subject: [PATCH 15/33] =?UTF-8?q?=E8=AE=A1=E5=88=92=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sf_production_demand_plan.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index 79fcb99b..e4a9ae0e 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -323,8 +323,15 @@ class SfProductionDemandPlan(models.Model): date_planned_start = datetime.combine(date_part, time_part) pro_plan_list.production_line_id = sf_production_line.id pro_plan_list.date_planned_start = date_planned_start - for pro_plan in pro_plan_list: - pro_plan.do_production_schedule() + batch_size = 100 + for i in range(0, len(pro_plan_list), batch_size): + current_time = fields.Datetime.now().strftime('%Y%m%d%H%M%S') + batch = self.env['queue.job.batch'].get_new_batch('plan-%s-%s' % (current_time, i)) + pro_plans = pro_plan_list[i:i+batch_size] + pro_plans.with_context( + job_batch=batch + ).with_delay().do_production_schedule() + batch.enqueue() def button_action_print(self): return { From 2c2fa87719c05554730e4e11bce0d49bb2549d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 11:26:48 +0800 Subject: [PATCH 16/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=A7=E9=87=8F?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index a028f63b..78202ea6 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -489,7 +489,7 @@ class Sf_Dashboard_Connect(http.Controller): # 工单返工数量 - plan_data_rework = work_order_obj.search(plan_domain + [ + plan_data_rework = work_order_obj.search(work_order_domain + [ ('state', 'in', ['rework']) ]) From aadccce47ef507b2df2c585a3a9f2954dad94ec4 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 11:35:23 +0800 Subject: [PATCH 17/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=87=BA=E5=8E=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E6=8A=A5=E5=91=8A=E7=94=9F=E6=88=90=E6=A8=A1?= =?UTF-8?q?=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index a2fb9932..6687e43e 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -92,7 +92,7 @@
- + @@ -113,7 +113,7 @@
产品名称:
- +

检验结果

@@ -182,7 +182,7 @@ - +

操作员:

@@ -200,12 +200,38 @@

--> - + - + + + + From 79f89f068b3fad273cd01718f4ba08cd4bc8ee6f Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 11:47:59 +0800 Subject: [PATCH 18/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=87=BA=E5=8E=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E6=8A=A5=E5=91=8A=E6=A8=A1=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/data/insepection_report_template.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 6687e43e..494e63f7 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -207,7 +207,7 @@ + From 109ea8729deee12baf9f85c6c9adc4de2b22ba09 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 12:03:17 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=87=BA=E5=8E=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E6=8A=A5=E5=91=8A=E6=A8=A1=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 494e63f7..f8ef2ac9 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -203,33 +203,9 @@ - + - - - @@ -354,8 +330,13 @@ - + + +
+ +
+
From 364127beb3e50144734af20d0304c239611a40df Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 13:37:42 +0800 Subject: [PATCH 20/33] 1 --- sf_quality/data/insepection_report_template.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index f8ef2ac9..dbc28574 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -203,8 +203,13 @@ - + + +
+ +
+
From 788183e2393b2e5244abe9148fdef98250c39874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 13:52:37 +0800 Subject: [PATCH 21/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sf_production_demand_plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index e4a9ae0e..cbd83c02 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -323,7 +323,7 @@ class SfProductionDemandPlan(models.Model): date_planned_start = datetime.combine(date_part, time_part) pro_plan_list.production_line_id = sf_production_line.id pro_plan_list.date_planned_start = date_planned_start - batch_size = 100 + batch_size = 28 for i in range(0, len(pro_plan_list), batch_size): current_time = fields.Datetime.now().strftime('%Y%m%d%H%M%S') batch = self.env['queue.job.batch'].get_new_batch('plan-%s-%s' % (current_time, i)) From e7afc76753d2da50e9b5f77c79d111a0b1efafec Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 14:01:56 +0800 Subject: [PATCH 22/33] =?UTF-8?q?=E5=87=BA=E5=8E=82=E6=A3=80=E9=AA=8C?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E6=A8=A1=E7=89=88=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index dbc28574..7cef66e9 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -202,13 +202,10 @@ --> - - - - -
- -
+ + + + @@ -334,13 +331,10 @@ --> - - - - -
- -
+ + + + From 5947b3dfe9bc2b6978cd47da69b16e142df2e5f8 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 14:26:29 +0800 Subject: [PATCH 23/33] =?UTF-8?q?=E5=9B=9E=E9=80=80=E5=87=BA=E5=8E=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E6=8A=A5=E5=91=8A=E6=A8=A1=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/data/insepection_report_template.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 7cef66e9..c68893fb 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -202,11 +202,11 @@ --> - + - +
@@ -331,11 +331,11 @@ --> - + - +
From b33c992b25c91bc85f436748739a2ebaf058f211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 14:51:58 +0800 Subject: [PATCH 24/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E8=AE=A1=E5=88=92=EF=BC=8C=E4=B8=8B=E8=BE=BE=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jikimo_demand_plan_queue/__init__.py | 2 ++ jikimo_demand_plan_queue/__manifest__.py | 18 +++++++++++++++++ jikimo_demand_plan_queue/models/__init__.py | 2 ++ .../models/production_demand_plan.py | 20 +++++++++++++++++++ sf_demand_plan/__manifest__.py | 2 +- .../models/sf_production_demand_plan.py | 15 ++++++-------- 6 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 jikimo_demand_plan_queue/__init__.py create mode 100644 jikimo_demand_plan_queue/__manifest__.py create mode 100644 jikimo_demand_plan_queue/models/__init__.py create mode 100644 jikimo_demand_plan_queue/models/production_demand_plan.py diff --git a/jikimo_demand_plan_queue/__init__.py b/jikimo_demand_plan_queue/__init__.py new file mode 100644 index 00000000..a0fdc10f --- /dev/null +++ b/jikimo_demand_plan_queue/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/jikimo_demand_plan_queue/__manifest__.py b/jikimo_demand_plan_queue/__manifest__.py new file mode 100644 index 00000000..aa970328 --- /dev/null +++ b/jikimo_demand_plan_queue/__manifest__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +{ + 'name': '机企猫 需求计划排程队列', + 'version': '1.0', + 'summary': """ 使用队列进行排程 """, + 'author': 'fox', + 'website': '', + 'category': '', + 'depends': ['queue_job', 'sf_demand_plan'], + 'data': [ + + ], + + 'application': True, + 'installable': True, + 'auto_install': False, + 'license': 'LGPL-3', +} diff --git a/jikimo_demand_plan_queue/models/__init__.py b/jikimo_demand_plan_queue/models/__init__.py new file mode 100644 index 00000000..54314ee3 --- /dev/null +++ b/jikimo_demand_plan_queue/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import production_demand_plan diff --git a/jikimo_demand_plan_queue/models/production_demand_plan.py b/jikimo_demand_plan_queue/models/production_demand_plan.py new file mode 100644 index 00000000..fd51e055 --- /dev/null +++ b/jikimo_demand_plan_queue/models/production_demand_plan.py @@ -0,0 +1,20 @@ +from odoo import models, fields + + +class ProductionDemandPlan(models.Model): + _inherit = 'sf.production.demand.plan' + + + def _do_production_schedule(self, pro_plan_list): + """使用队列进行排程""" + batch_size = 10 + current_time = fields.Datetime.now().strftime('%Y%m%d%H%M%S') + index = 1 + for i in range(0, len(pro_plan_list), batch_size): + batch = self.env['queue.job.batch'].get_new_batch('plan-%s-%s' % (current_time, index)) + pro_plans = pro_plan_list[i:i+batch_size] + pro_plans.with_context( + job_batch=batch + ).with_delay().do_production_schedule() + index += 1 + batch.enqueue() \ No newline at end of file diff --git a/sf_demand_plan/__manifest__.py b/sf_demand_plan/__manifest__.py index 2a543f1a..aab4ed99 100644 --- a/sf_demand_plan/__manifest__.py +++ b/sf_demand_plan/__manifest__.py @@ -10,7 +10,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['sf_plan', 'jikimo_printing'], + 'depends': ['sf_plan'], 'data': [ 'security/ir.model.access.csv', 'views/demand_plan.xml', diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index cbd83c02..12214bff 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -323,15 +323,12 @@ class SfProductionDemandPlan(models.Model): date_planned_start = datetime.combine(date_part, time_part) pro_plan_list.production_line_id = sf_production_line.id pro_plan_list.date_planned_start = date_planned_start - batch_size = 28 - for i in range(0, len(pro_plan_list), batch_size): - current_time = fields.Datetime.now().strftime('%Y%m%d%H%M%S') - batch = self.env['queue.job.batch'].get_new_batch('plan-%s-%s' % (current_time, i)) - pro_plans = pro_plan_list[i:i+batch_size] - pro_plans.with_context( - job_batch=batch - ).with_delay().do_production_schedule() - batch.enqueue() + self._do_production_schedule(pro_plan_list) + + def _do_production_schedule(self, pro_plan_list): + for pro_plan in pro_plan_list: + pro_plan.do_production_schedule() + def button_action_print(self): return { From 5bb6fcd4f7b70fb38986971a47121640c1c47c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 15:03:42 +0800 Subject: [PATCH 25/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jikimo_demand_plan_queue/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jikimo_demand_plan_queue/__manifest__.py b/jikimo_demand_plan_queue/__manifest__.py index aa970328..83f5e07d 100644 --- a/jikimo_demand_plan_queue/__manifest__.py +++ b/jikimo_demand_plan_queue/__manifest__.py @@ -6,7 +6,7 @@ 'author': 'fox', 'website': '', 'category': '', - 'depends': ['queue_job', 'sf_demand_plan'], + 'depends': ['queue_job_batch', 'sf_demand_plan'], 'data': [ ], From 2e168a4ba71c33d410f4e3e2b59dab2410aae53c Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 15:35:07 +0800 Subject: [PATCH 26/33] =?UTF-8?q?=E5=87=BA=E5=8E=82=E6=A3=80=E9=AA=8C?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E6=A8=A1=E7=89=88-=E9=A1=B5=E8=84=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index c68893fb..4b91ec13 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -201,12 +201,31 @@ --> + - + - + - From 13d33488dc21aafedb6771c568c84002e498a1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Jun 2025 15:39:11 +0800 Subject: [PATCH 27/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E9=87=8F=E5=AD=97=E6=AE=B5=E4=B8=BA=C2=96qty=5Fproduction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 78202ea6..4974127e 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -437,7 +437,7 @@ class Sf_Dashboard_Connect(http.Controller): ('state', 'in', ['ready', 'progress', 'done']) ]) - plan_data_total_counts = sum(plan_data_total.mapped('qty_produced')) + plan_data_total_counts = sum(plan_data_total.mapped('qty_production')) # # 工单完成量 # plan_data_finish_counts = plan_obj.search_count( @@ -717,7 +717,7 @@ class Sf_Dashboard_Connect(http.Controller): # 使用小时和分钟作为键,确保每个小时的数据有独立的键 key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 # time_count_dict[key] = len(orders) - plan_count_dict[key] = sum(interval_orders.mapped('qty_produced')) + plan_count_dict[key] = sum(interval_orders.mapped('qty_production')) # order_counts.append() res['data'][line] = { From e3fb2668906fcee98714c14456cf0ac3aa6a5e89 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 15:55:58 +0800 Subject: [PATCH 28/33] =?UTF-8?q?=E5=87=BA=E5=8E=82=E6=A3=80=E9=AA=8C?= =?UTF-8?q?=E6=8A=A5=E5=91=8A-=E9=A1=B5=E8=84=9A=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 4b91ec13..5b18d641 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -202,20 +202,6 @@ -->