From 71a0f39ec99c704aad82de18a248612b0f703fcf Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 18 Jun 2025 10:50:13 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E9=87=87=E8=B4=AD=E8=AE=A2=E5=8D=95=E7=B1=BB=E5=9E=8B=E4=B8=BA?= =?UTF-8?q?=E5=A7=94=E5=A4=96=E5=8A=A0=E5=B7=A5=EF=BC=8C=E5=88=99=E4=B8=8D?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BE=9B=E5=BA=94=E5=95=86=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E7=94=9F=E6=88=90=E8=A1=A5=E7=BB=99=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/__init__.py | 1 + sf_manufacturing/models/bom.py | 16 ++++++++++++++++ sf_manufacturing/models/stock.py | 14 ++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 sf_manufacturing/models/bom.py diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index 8af783e7..c8af2d82 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -18,4 +18,5 @@ from . import quick_easy_order from . import purchase_order from . import quality_check from . import purchase_request_line +from . import bom # from . import stock_warehouse_orderpoint \ No newline at end of file diff --git a/sf_manufacturing/models/bom.py b/sf_manufacturing/models/bom.py new file mode 100644 index 00000000..d0a35300 --- /dev/null +++ b/sf_manufacturing/models/bom.py @@ -0,0 +1,16 @@ +from odoo import models +from odoo.osv.expression import AND + + +class MrpBom(models.Model): + _inherit = 'mrp.bom' + + def _bom_subcontract_find(self, product, picking_type=None, company_id=False, bom_type='subcontract', subcontractor=False): + domain = self._bom_find_domain(product, picking_type=picking_type, company_id=company_id, bom_type=bom_type) + if self.env.context.get('stock_picking') == 'outsourcing': + return self.search(domain, order='sequence, product_id, id', limit=1) + if subcontractor: + domain = AND([domain, [('subcontractor_ids', 'parent_of', subcontractor.ids)]]) + return self.search(domain, order='sequence, product_id, id', limit=1) + else: + return self.env['mrp.bom'] diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 4134de94..05943e83 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -1216,6 +1216,20 @@ class ReStockMove(models.Model): res['lot_id'] = self.subcontract_workorder_id.production_id.move_raw_ids.move_line_ids[0].lot_id.id return res + def _get_subcontract_bom(self): + self.ensure_one() + purchase_type = getattr(self.picking_id.purchase_id, 'purchase_type', False) + if purchase_type: + self = self.with_context(stock_picking=purchase_type) + bom = self.env['mrp.bom'].sudo()._bom_subcontract_find( + self.product_id, + picking_type=self.picking_type_id, + company_id=self.company_id.id, + bom_type='subcontract', + subcontractor=self.picking_id.partner_id + ) + return bom + class ReStockQuant(models.Model): _inherit = 'stock.quant' From 35e80266d7b6edb642eab5a3e1fe4db0c372a6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 23 Jun 2025 08:59:02 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=A5=E4=BA=A7?= =?UTF-8?q?=E9=87=8F=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 4974127e..94161271 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -601,8 +601,11 @@ class Sf_Dashboard_Connect(http.Controller): line_list = ast.literal_eval(kw['line_list']) begin_time_str = kw['begin_time'].strip('"') end_time_str = kw['end_time'].strip('"') - begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') - end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') + # 将时间减去8小时(UTC+8转UTC) + begin_time = (datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') - timedelta(hours=8)) + end_time = (datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') - timedelta(hours=8)) + # begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') + # end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') # print('line_list: %s' % line_list) print('kw', kw) time_unit = kw.get('time_unit', 'day').strip('"') # 默认单位为天 From 05c5c0ef811a6d9e67f88dc97f0feaa287ab5835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 23 Jun 2025 09:22:37 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= 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 94161271..ba8ac697 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -681,7 +681,7 @@ class Sf_Dashboard_Connect(http.Controller): ) # 使用小时和分钟作为键,确保每个小时的数据有独立的键 - key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 + key = (start_time + timedelta(hours=8)).strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 # time_count_dict[key] = len(orders) time_count_dict[key] = sum(interval_orders.mapped('qty_produced')) @@ -718,7 +718,7 @@ class Sf_Dashboard_Connect(http.Controller): 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') # 只取小时:分钟:秒作为键 + key = (start_time + timedelta(hours=8)).strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 # time_count_dict[key] = len(orders) plan_count_dict[key] = sum(interval_orders.mapped('qty_production')) From 0d76d1a7d3b724015b19b2c2e76837c01a3b5d61 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Mon, 23 Jun 2025 13:59:37 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E9=9C=80=E6=B1=82=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/sf_production_demand_plan.py | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index 12214bff..d07e4936 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -403,29 +403,30 @@ class SfProductionDemandPlan(models.Model): outsourcing_purchase_request.extend(pr_ids.ids) if record.supply_method == 'outsourcing' and not record.sale_order_line_id.is_incoming_material: bom_line_ids = record.product_id.bom_ids.bom_line_ids - # BOM_数量 - total_product_qty = sum(line.product_qty for line in bom_line_ids) - bom_product_ids = bom_line_ids.mapped('product_id') - product_purchase_orders = self.env['purchase.order'].sudo().search([ - ('state', 'in', ('purchase', 'done')), - ('order_line.product_id', 'in', bom_product_ids.ids) - ]) - # 购订单_数量 - total_outsourcing_purchase_quantity = sum( - sum( - order.order_line.filtered( - lambda line: line.product_id in bom_product_ids - ).mapped('product_qty') + if bom_line_ids: + # BOM_数量 + total_product_qty = sum(line.product_qty for line in bom_line_ids) + bom_product_ids = bom_line_ids.mapped('product_id') + product_purchase_orders = self.env['purchase.order'].sudo().search([ + ('state', 'in', ('purchase', 'done')), + ('order_line.product_id', 'in', bom_product_ids.ids) + ]) + # 购订单_数量 + total_outsourcing_purchase_quantity = sum( + sum( + order.order_line.filtered( + lambda line: line.product_id in bom_product_ids + ).mapped('product_qty') + ) + for order in product_purchase_orders ) - for order in product_purchase_orders - ) - quantity = total_outsourcing_purchase_quantity / total_product_qty - if float_compare(quantity, record.product_uom_qty, - precision_rounding=record.product_id.uom_id.rounding) == -1: - purchase_request = self.env['purchase.request'].sudo().search( - [('line_ids.product_id', 'in', bom_product_ids.ids), - ('line_ids.purchase_state', 'not in', ('purchase', 'done')), ('state', '!=', 'done')]) - outsourcing_purchase_request.extend(purchase_request.ids) + quantity = total_outsourcing_purchase_quantity / total_product_qty + if float_compare(quantity, record.product_uom_qty, + precision_rounding=record.product_id.uom_id.rounding) == -1: + purchase_request = self.env['purchase.request'].sudo().search( + [('line_ids.product_id', 'in', bom_product_ids.ids), + ('line_ids.purchase_state', 'not in', ('purchase', 'done')), ('state', '!=', 'done')]) + outsourcing_purchase_request.extend(purchase_request.ids) record.outsourcing_purchase_request = json.dumps(outsourcing_purchase_request) if outsourcing_purchase_request: record.hide_action_purchase_orders = True From a2a652eea4fbe764b268787e928cd62858db649a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 23 Jun 2025 17:54:38 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=A4=A7=E5=B1=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index ba8ac697..565ba613 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -639,6 +639,15 @@ class Sf_Dashboard_Connect(http.Controller): if time_unit == 'hour': + + # 计划量,目前只能从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 line in line_list: date_field_name = 'date_finished' # 替换为你模型中的实际字段名 @@ -685,15 +694,6 @@ class Sf_Dashboard_Connect(http.Controller): # time_count_dict[key] = len(orders) 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 @@ -876,6 +876,18 @@ class Sf_Dashboard_Connect(http.Controller): not_done_index = 1 done_index = 1 + # 获取当前时间,并计算24小时前的时间 + current_time = datetime.now() + time_48_hours_ago = current_time - timedelta(hours=48) + + # 计划量,目前只能从mail.message中筛选出 + plan_order_messages = request.env['mail.message'].sudo().search([ + ('model', '=', 'mrp.workorder'), + ('create_date', '>=', time_48_hours_ago.strftime('%Y-%m-%d %H:%M:%S')), + ('tracking_value_ids.field_desc', '=', '状态'), + ('tracking_value_ids.new_value_char', 'in', ['就绪', '生产中']) + ]) + for line in line_list: if line == '业绩总览': @@ -892,19 +904,27 @@ class Sf_Dashboard_Connect(http.Controller): # [('production_line_id.name', '=', line), ('state', 'not in', ['finished']), # ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True) # ]) - not_done_orders = work_order_obj.search(work_order_domain + - [('state', 'in', ['ready', 'progress'])], order='id asc' - ) + # not_done_orders = work_order_obj.search(work_order_domain + + # [('state', 'in', ['ready', 'progress'])], order='id asc' + # ) + not_done_orders = request.env['mrp.workorder'].sudo().browse(plan_order_messages.mapped('res_id')) + if line == '业绩总览': + not_done_orders = not_done_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工']) + elif line == '人工线下加工中心': + not_done_orders = not_done_orders.filtered(lambda o: o.routing_type == '人工线下加工') + else: + not_done_orders = not_done_orders.filtered(lambda o: o.routing_type == 'CNC加工' and o.production_line_id.name == line) + # 完成订单 # 获取当前时间,并计算24小时前的时间 - current_time = datetime.now() - time_24_hours_ago = current_time - timedelta(hours=24) + # current_time = datetime.now() + # time_24_hours_ago = current_time - timedelta(hours=24) finish_orders = work_order_obj.search(work_order_domain + [ ('state', 'in', ['finished']), ('production_id.state', 'not in', ['cancel']), - ('date_finished', '>=', time_24_hours_ago) + ('date_finished', '>=', time_48_hours_ago) ], order='id asc') # print(finish_orders) From 7d1f7b11ebdd2156709f8d387cd4dd43f55031d6 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 24 Jun 2025 11:39:47 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=9D=AF=E6=96=99=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_demand_plan/models/sf_production_demand_plan.py | 7 +++++-- sf_demand_plan/views/demand_plan.xml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py index d07e4936..49cbe926 100644 --- a/sf_demand_plan/models/sf_production_demand_plan.py +++ b/sf_demand_plan/models/sf_production_demand_plan.py @@ -196,11 +196,14 @@ class SfProductionDemandPlan(models.Model): else: line.model_long = None - @api.depends('product_id.model_long', 'product_id.model_width', 'product_id.model_height') + @api.depends('product_id.model_long', 'product_id.model_width', 'product_id.model_height', 'product_id.blank_type') def _compute_embryo_long(self): for line in self: if line.product_id: - line.embryo_long = f"{round(line.product_id.model_long, 3)}*{round(line.product_id.model_width, 3)}*{round(line.product_id.model_height, 3)}" + if line.product_id.blank_type == '圆料': + line.embryo_long = f"Ø{round(line.product_id.model_width, 3)}*{round(line.product_id.model_long, 3)}" + else: + line.embryo_long = f"{round(line.product_id.model_long, 3)}*{round(line.product_id.model_width, 3)}*{round(line.product_id.model_height, 3)}" else: line.embryo_long = None diff --git a/sf_demand_plan/views/demand_plan.xml b/sf_demand_plan/views/demand_plan.xml index 24a2707e..5b9c425a 100644 --- a/sf_demand_plan/views/demand_plan.xml +++ b/sf_demand_plan/views/demand_plan.xml @@ -28,7 +28,7 @@ - + From 33647fa3e09b255121e8fabb2a849654eee4e70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 24 Jun 2025 14:18:27 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=98=8E=E7=BB=86?= =?UTF-8?q?=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 | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 565ba613..18b4346c 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -870,11 +870,7 @@ class Sf_Dashboard_Connect(http.Controller): begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') # print('line_list: %s' % line_list) - not_done_data = [] - done_data = [] final_data = {} - not_done_index = 1 - done_index = 1 # 获取当前时间,并计算24小时前的时间 current_time = datetime.now() @@ -889,6 +885,10 @@ class Sf_Dashboard_Connect(http.Controller): ]) for line in line_list: + not_done_data = [] + done_data = [] + not_done_index = 1 + done_index = 1 if line == '业绩总览': work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] @@ -922,11 +922,11 @@ class Sf_Dashboard_Connect(http.Controller): # time_24_hours_ago = current_time - timedelta(hours=24) finish_orders = work_order_obj.search(work_order_domain + [ - ('state', 'in', ['finished']), + ('state', 'in', ['done']), ('production_id.state', 'not in', ['cancel']), ('date_finished', '>=', time_48_hours_ago) ], order='id asc') - # print(finish_orders) + # logging.info('完成订单: %s' % finish_orders) # 获取所有未完成订单的ID列表 order_ids = [order.id for order in not_done_orders] @@ -985,8 +985,6 @@ class Sf_Dashboard_Connect(http.Controller): not_done_index += 1 for finish_order in finish_orders: - if not finish_order.actual_end_time: - continue blank_name = '' try: blank_name = finish_order.production_id.move_raw_ids[0].product_id.name @@ -1007,8 +1005,8 @@ class Sf_Dashboard_Connect(http.Controller): 'material': material, 'dimensions': dimensions, '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 ' ' + 'finish_time': finish_order.date_finished.strftime( + '%Y-%m-%d %H:%M:%S') if finish_order.date_finished else ' ' } done_data.append(line_dict) From 2a330a4bd862da1bec3ef87b13ae88d8aa7f7ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 24 Jun 2025 14:52:03 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=AE=A2=E5=8D=95=E8=AF=A6=E6=83=85=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= 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, 2 insertions(+) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 18b4346c..de4a8a33 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -862,6 +862,8 @@ class Sf_Dashboard_Connect(http.Controller): """ # res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} res = {'status': 1, 'message': '成功', 'data': {}} + # 解决产品名称取到英文的问题 + request.update_context(lang='zh_CN') plan_obj = request.env['sf.production.plan'].sudo() work_order_obj = request.env['mrp.workorder'].sudo() line_list = ast.literal_eval(kw['line_list'])