From 4274b9fe99e5dd433661f942c605cd00d46f9f23 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Jun 2025 17:53:04 +0800 Subject: [PATCH 01/20] =?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?= =?UTF-8?q?=E5=9B=9E=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_quality/data/insepection_report_template.xml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index dbc28574..263afc9d 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -203,13 +203,8 @@ - + - -
- -
-
@@ -335,13 +330,8 @@ - + - -
- -
-
From b177bd95ff5c0bce29f7dcf1c7de868249255652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 23 Jun 2025 11:04:44 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E5=B0=86fetchCNC=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=88=B0sf=5Fmrs=5Fconnect=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 80 -------------------- sf_mrs_connect/models/mrp_production.py | 91 ++++++++++++++++++++++- 2 files changed, 88 insertions(+), 83 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 2d0545af..eac183d7 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -740,86 +740,6 @@ class MrpProduction(models.Model): logging.info('change_programming_state error:%s' % e) raise UserError("修改编程单状态失败,请联系管理员") - # cnc程序获取 - def fetchCNC(self, production_names): - cnc = self.env['mrp.production'].search([('id', '=', self.id)]) - quick_order = False - if cnc.product_id.default_code: - quick_order = self.env['quick.easy.order'].search( - [('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])]) - programme_way = False - if cnc.manual_quotation is True: - programme_way = 'manual operation' - else: - programme_way = 'auto' - if cnc.production_type == '人工线下加工': - programme_way = 'manual operation' - if quick_order: - programme_way = 'manual operation' - try: - res = { - 'production_no': production_names, - 'machine_tool_code': '', - 'product_name': cnc.product_id.name, - 'remanufacture_type': '', - 'model_code': cnc.product_id.model_code, - 'material_code': self.env['sf.production.materials'].search( - [('id', '=', cnc.product_id.materials_id.id)]).materials_no, - 'material_type_code': self.env['sf.materials.model'].search( - [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no, - 'machining_processing_panel': cnc.product_id.model_processing_panel, - 'machining_precision': '', - 'embryo_long': cnc.product_id.bom_ids[0].bom_line_ids.product_id.length, - 'embryo_height': cnc.product_id.bom_ids[0].bom_line_ids.product_id.height, - 'embryo_width': cnc.product_id.bom_ids[0].bom_line_ids.product_id.width, - 'order_no': cnc.origin, - 'model_order_no': cnc.product_id.default_code, - 'user': cnc.env.user.name, - 'programme_way': programme_way, - # 'model_file': '' if not cnc.product_id.model_file else base64.b64encode( - # cnc.product_id.model_file).decode('utf-8'), - # 'glb_url': cnc.product_id.glb_url, - 'part_name': cnc.product_id.part_name, - 'part_number': cnc.product_id.part_number, - 'machining_drawings': base64.b64encode(cnc.product_id.machining_drawings).decode( - 'utf-8') if cnc.product_id.machining_drawings else '', - 'machining_drawings_name': cnc.product_id.machining_drawings_name, - 'machining_drawings_mimetype': cnc.product_id.machining_drawings_mimetype, - # 'model_id': cnc.product_id.model_id, - } - # 打印出除了 model_file 之外的所有键值对 - for key, value in res.items(): - if key != 'model_file': - logging.info('%s: %s' % (key, value)) - configsettings = self.env['res.config.settings'].get_values() - config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) - url = '/api/intelligent_programming/create' - config_url = configsettings['sf_url'] + url - res['token'] = configsettings['token'] - # res_str = json.dumps(res) - ret = requests.post(config_url, json={}, data=res, headers=config_header) - ret = ret.json() - logging.info('fetchCNC-ret:%s' % ret) - if ret['status'] == 1: - self.write( - {'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'}) - # 生成编程记录 - self.programming_record_ids.create({ - 'number': len(self.programming_record_ids) + 1, - 'production_id': self.id, - 'reason': '首次下发', - 'programming_method': False, - 'current_programming_count': False, - 'target_production_id': False, - 'apply_time': fields.Datetime.now(), - 'send_time': False, - }) - else: - raise UserError(ret['message']) - except Exception as e: - logging.info('fetchCNC error:%s' % e) - raise UserError("cnc程序获取编程单失败,请联系管理员") - # 维修模块按钮 def button_maintenance_req(self): self.ensure_one() diff --git a/sf_mrs_connect/models/mrp_production.py b/sf_mrs_connect/models/mrp_production.py index ac3f6640..ec740abd 100644 --- a/sf_mrs_connect/models/mrp_production.py +++ b/sf_mrs_connect/models/mrp_production.py @@ -1,6 +1,11 @@ +import base64 +import requests +import logging + from itertools import groupby -from odoo import models, api -from odoo.tools.misc import OrderedSet +from odoo import models, api, fields +from odoo.exceptions import UserError +from odoo.addons.sf_base.commons.common import Common class MrpProduction(models.Model): @@ -41,4 +46,84 @@ class MrpProduction(models.Model): 'programming_no': grouped_product_programming_no[production.product_id.id], 'programming_state': '编程中' }) - return productions \ No newline at end of file + return productions + + # cnc程序获取 + def fetchCNC(self, production_names): + cnc = self.env['mrp.production'].search([('id', '=', self.id)]) + quick_order = False + if cnc.product_id.default_code: + quick_order = self.env['quick.easy.order'].search( + [('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])]) + programme_way = False + if cnc.manual_quotation is True: + programme_way = 'manual operation' + else: + programme_way = 'auto' + if cnc.production_type == '人工线下加工': + programme_way = 'manual operation' + if quick_order: + programme_way = 'manual operation' + try: + res = { + 'production_no': production_names, + 'machine_tool_code': '', + 'product_name': cnc.product_id.name, + 'remanufacture_type': '', + 'model_code': cnc.product_id.model_code, + 'material_code': self.env['sf.production.materials'].search( + [('id', '=', cnc.product_id.materials_id.id)]).materials_no, + 'material_type_code': self.env['sf.materials.model'].search( + [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no, + 'machining_processing_panel': cnc.product_id.model_processing_panel, + 'machining_precision': '', + 'embryo_long': cnc.product_id.bom_ids[0].bom_line_ids.product_id.length, + 'embryo_height': cnc.product_id.bom_ids[0].bom_line_ids.product_id.height, + 'embryo_width': cnc.product_id.bom_ids[0].bom_line_ids.product_id.width, + 'order_no': cnc.origin, + 'model_order_no': cnc.product_id.default_code, + 'user': cnc.env.user.name, + 'programme_way': programme_way, + # 'model_file': '' if not cnc.product_id.model_file else base64.b64encode( + # cnc.product_id.model_file).decode('utf-8'), + # 'glb_url': cnc.product_id.glb_url, + 'part_name': cnc.product_id.part_name, + 'part_number': cnc.product_id.part_number, + 'machining_drawings': base64.b64encode(cnc.product_id.machining_drawings).decode( + 'utf-8') if cnc.product_id.machining_drawings else '', + 'machining_drawings_name': cnc.product_id.machining_drawings_name, + 'machining_drawings_mimetype': cnc.product_id.machining_drawings_mimetype, + # 'model_id': cnc.product_id.model_id, + } + # 打印出除了 model_file 之外的所有键值对 + for key, value in res.items(): + if key != 'model_file': + logging.info('%s: %s' % (key, value)) + configsettings = self.env['res.config.settings'].get_values() + config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) + url = '/api/intelligent_programming/create' + config_url = configsettings['sf_url'] + url + res['token'] = configsettings['token'] + # res_str = json.dumps(res) + ret = requests.post(config_url, json={}, data=res, headers=config_header) + ret = ret.json() + logging.info('fetchCNC-ret:%s' % ret) + if ret['status'] == 1: + self.write( + {'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'}) + # 生成编程记录 + self.programming_record_ids.create({ + 'number': len(self.programming_record_ids) + 1, + 'production_id': self.id, + 'reason': '首次下发', + 'programming_method': False, + 'current_programming_count': False, + 'target_production_id': False, + 'apply_time': fields.Datetime.now(), + 'send_time': False, + }) + else: + raise UserError(ret['message']) + except Exception as e: + logging.info('fetchCNC error:%s' % e) + raise UserError("cnc程序获取编程单失败,请联系管理员") \ No newline at end of file From fe3492ceb5eb8b33fd8f261e743510427ca25094 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 24 Jun 2025 11:32:41 +0800 Subject: [PATCH 03/20] =?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 --- .../models/sf_production_demand_plan.py | 52 ++++++++++--------- sf_demand_plan/views/demand_plan.xml | 2 +- 2 files changed, 29 insertions(+), 25 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..1e1459d3 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 @@ -399,29 +402,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 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 35b1d648c326977ddb0d54d9ba27c7c041208899 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 24 Jun 2025 15:36:23 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8D=95=E4=BB=B6=E7=94=A8=E9=87=8F=20unit=5Fnumber=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=80=BC=E7=94=B1bfm=E4=B8=8B?= =?UTF-8?q?=E5=8D=95=E5=90=8C=E6=AD=A5=E8=8E=B7=E5=BE=97=EF=BC=9B=E4=BA=A7?= =?UTF-8?q?=E5=93=81=E7=94=9F=E6=88=90=E7=9A=84BOM=E4=B8=AD=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=95=B0=E9=87=8F=E7=9A=84=E5=80=BC=E7=94=B1unit=5Fnu?= =?UTF-8?q?mber=20=E5=AD=97=E6=AE=B5=E6=8F=90=E4=BE=9B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/product_supplierinfo.py | 7 +++++-- .../views/product_template_management_view.xml | 3 ++- sf_manufacturing/models/product_template.py | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sf_dlm/models/product_supplierinfo.py b/sf_dlm/models/product_supplierinfo.py index f4278e03..313b51ed 100644 --- a/sf_dlm/models/product_supplierinfo.py +++ b/sf_dlm/models/product_supplierinfo.py @@ -47,11 +47,14 @@ class ResMrpBomMo(models.Model): item.subcontractor_name = '' def bom_create_line_has(self, embryo): + product = self.product_tmpl_id + if product.unit_number in (0, None, False): + raise ValueError(f'单件用量的值不能为{product.unit_number}') vals = { 'bom_id': self.id, 'product_id': embryo.id, 'product_tmpl_id': embryo.product_tmpl_id.id, - 'product_qty': 1, + 'product_qty': product.unit_number, 'product_uom_id': 1 } return self.env['mrp.bom.line'].sudo().create(vals) @@ -122,7 +125,7 @@ class ResMrpBomMo(models.Model): # 查bom的原材料 def get_raw_bom(self, product): raw_bom = self.env['product.product'].search( - [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)],limit=1) + [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)], limit=1) return raw_bom diff --git a/sf_dlm_management/views/product_template_management_view.xml b/sf_dlm_management/views/product_template_management_view.xml index bb9904a7..b0a7b87e 100644 --- a/sf_dlm_management/views/product_template_management_view.xml +++ b/sf_dlm_management/views/product_template_management_view.xml @@ -95,6 +95,7 @@ +