From 740df7c99a383741a352c18241e7d80ecc3bc7cb Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Mon, 20 Mar 2023 17:37:23 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A1=A8=E9=9D=A2?= =?UTF-8?q?=E5=B7=A5=E8=89=BA=E5=A4=96=E5=8D=8F=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 1 + sf_base/views/common_view.xml | 4 ++- sf_manufacturing/models/model_type.py | 31 +++++++++++++++++-- .../models/mrp_routing_workcenter.py | 9 ++++-- sf_manufacturing/models/mrp_workorder.py | 19 ++++-------- sf_manufacturing/security/ir.model.access.csv | 2 ++ sf_manufacturing/views/model_type_view.xml | 11 +++++++ 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index a1c33521..01b66a4d 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -50,6 +50,7 @@ class MrsProductionProcess(models.Model): partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂') active = fields.Boolean('有效', default=True) parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数') + gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") class MrsProcessingTechnology(models.Model): diff --git a/sf_base/views/common_view.xml b/sf_base/views/common_view.xml index be899852..1f5e2907 100644 --- a/sf_base/views/common_view.xml +++ b/sf_base/views/common_view.xml @@ -58,8 +58,8 @@ + - @@ -101,6 +101,8 @@ + + diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index 5428534d..2787d28e 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -11,6 +11,9 @@ class ModelType(models.Model): '成品工序模板') embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id', '胚料工序模板') + surface_technics_routing_tmpl_ids = fields.One2many('sf.surface_technics.model.type.routing.sort', + 'surface_technics_model_type_id', + '表面工艺工序模板') class ProductModelTypeRoutingSort(models.Model): @@ -26,7 +29,7 @@ class ProductModelTypeRoutingSort(models.Model): ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), - ('解除装夹', '解除装夹'), ('切割', '切割') + ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') ], string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') product_model_type_id = fields.Many2one('sf.model.type') @@ -49,7 +52,7 @@ class EmbryoModelTypeRoutingSort(models.Model): ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), - ('解除装夹', '解除装夹'), ('切割', '切割') + ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') ], string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') embryo_model_type_id = fields.Many2one('sf.model.type') @@ -57,3 +60,27 @@ class EmbryoModelTypeRoutingSort(models.Model): _sql_constraints = [ ('route_model_type_uniq', 'unique (route_workcenter_id,embryo_model_type_id)', '胚料工序不能重复!') ] + + +class SurfaceTechnicsModelTypeRoutingSort(models.Model): + _name = 'sf.surface_technics.model.type.routing.sort' + _description = '表面工艺工序排序' + + sequence = fields.Integer('Sequence') + route_workcenter_id = fields.Many2one('mrp.routing.workcenter') + is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') + routing_type = fields.Selection([ + ('获取CNC加工程序', '获取CNC加工程序'), + ('装夹', '装夹'), + ('前置三元定位检测', '前置三元定位检测'), + ('CNC加工', 'CNC加工'), + ('后置三元质量检测', '后置三元质量检测'), + ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') + ], string="工序类型", related='route_workcenter_id.routing_type') + workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') + surface_technics_model_type_id = fields.Many2one('sf.model.type') + + _sql_constraints = [ + ( + 'route_model_type_uniq', 'unique (route_workcenter_id,surface_technics_model_type_id)', '表面工艺工序不能重复!') + ] diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index 5bb08aa2..8eb22ca5 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -11,7 +11,8 @@ class ResMrpRoutingWorkcenter(models.Model): ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), - ('切割', '切割') + ('切割', '切割'), + ('绑定表面工艺', '绑定表面工艺') ], string="工序类型") is_repeat = fields.Boolean('重复', default=False) workcenter_id = fields.Many2one('mrp.workcenter', required=False) @@ -42,8 +43,10 @@ class ResMrpRoutingWorkcenter(models.Model): print(item.name) if item.machine_tool_id: machine_tool = self.env['sf.machine_tool'].search( - [('x_axis', '>', product.bom_ids.bom_line_ids.product_id.length), ('y_axis', '>', product.bom_ids.bom_line_ids.product_id.width), - ('z_axis', '>', product.bom_ids.bom_line_ids.product_id.height), ('id', '=', item.machine_tool_id.id)]) + [('x_axis', '>', product.bom_ids.bom_line_ids.product_id.length), + ('y_axis', '>', product.bom_ids.bom_line_ids.product_id.width), + ('z_axis', '>', product.bom_ids.bom_line_ids.product_id.height), + ('id', '=', item.machine_tool_id.id)]) if machine_tool: workcenter_ids.append(item.id) if len(workcenter_ids) == 1: diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 82e228a4..f858c88d 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -29,7 +29,7 @@ class ResMrpWorkOrder(models.Model): ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), - ('切割', '切割') + ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') ], string="工序类型") results = fields.Char('检测结果') @@ -137,7 +137,7 @@ class ResMrpWorkOrder(models.Model): except: raise UserError("参数计算有误") - #拼接工单对象属性值 + # 拼接工单对象属性值 def json_workorder_str(self, k, production, route): workorders_values_str = [0, '', { 'product_uom_id': production.product_uom_id.id, @@ -203,9 +203,9 @@ class ResMrpWorkOrder(models.Model): else: raise UserError('托盘码不能为空') - #验证坯料序列号是否正确 - def pro_code_is_ok(self,barcode): - if barcode!=False: + # 验证坯料序列号是否正确 + def pro_code_is_ok(self, barcode): + if barcode != False: if barcode != self.pro_code: raise UserError('坯料序列号错误') return False @@ -216,7 +216,7 @@ class ResMrpWorkOrder(models.Model): pro_code_ok = fields.Boolean(default=False) - #托盘扫码绑定 + # 托盘扫码绑定 def gettray_auto(self, barcode): if barcode != False: values = self.env['sf.tray'].search([("code", "=", barcode)]) @@ -255,7 +255,6 @@ class ResMrpWorkOrder(models.Model): else: raise UserError('托盘码不能为空') - # 解除托盘绑定 def unbindtray(self): tray = self.env['sf.tray'].search([("production_id", "=", self.production_id.id)]) @@ -393,7 +392,6 @@ class ResMrpWorkOrder(models.Model): }] return workorders_values_str - # 重写工单开始按钮方法 def button_start(self): if self.routing_type == '装夹': @@ -467,7 +465,6 @@ class CNCprocessing(models.Model): workorder_id = fields.Many2one('mrp.workorder', string="工单") button_state = fields.Boolean(string='是否已经下发') - # mrs下发编程单创建CNC加工 def cnc_processing_create(self, cnc_workorder, ret): logging.info('ret:%s' % ret) @@ -567,8 +564,6 @@ class SfWorkOrderBarcodes(models.Model): else: self.pro_code_ok = workorder.pro_code_is_ok(barcode) - - # return { # 'type': 'ir.actions.act_window', # 'name': '工单', @@ -577,5 +572,3 @@ class SfWorkOrderBarcodes(models.Model): # 'context': {'active_id': self.id}, # # 'target': 'current', # } - - diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index f2bf5270..bc24436c 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -3,6 +3,8 @@ access_sf_cnc_processing,sf_cnc_processing,model_sf_cnc_processing,base.group_us access_sf_model_type,sf_model_type,model_sf_model_type,base.group_user,1,1,1,1 access_sf_product_model_type_routing_sort,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,base.group_user,1,1,1,1 access_sf_embryo_model_type_routing_sort,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,base.group_user,1,1,1,1 +access_sf_surface_technics_model_type_routing_sort,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,base.group_user,1,1,1,1 + diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index e44f7311..e827e1df 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -55,6 +55,17 @@ + + + + + + + + + + + From 446bd04a9d4bd62f9812e0339d1af4ab2c283571 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Thu, 23 Mar 2023 18:18:57 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=90=8C=E6=AD=A5mrs?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E7=B1=BB=E5=88=AB?= =?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_base/models/common.py | 12 +++ sf_base/views/common_view.xml | 88 +++++++++++++++------ sf_base/views/menu_view.xml | 7 ++ sf_dlm/__manifest__.py | 2 +- sf_dlm/views/product_template_view.xml | 2 +- sf_manufacturing/models/tray.py | 2 +- sf_mrs_connect/data/ir_cron_data.xml | 22 +++--- sf_mrs_connect/models/res_config_setting.py | 2 + sf_mrs_connect/models/sync_common.py | 77 ++++++++++++++++-- 9 files changed, 170 insertions(+), 44 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 01b66a4d..32c4b245 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -38,6 +38,17 @@ class MrsMaterialModel(models.Model): active = fields.Boolean('有效', default=True) +class MrsProductionProcessCategory(models.Model): + _name = 'sf.production.process.category' + _description = '表面工艺类别' + order = 'id desc' + + name = fields.Char('名称') + code = fields.Char("编码") + production_process_ids = fields.One2many('sf.production.process', 'category_id', string="表面工艺") + active = fields.Boolean('有效', default=True) + + # 工艺 编码,名称,备注 class MrsProductionProcess(models.Model): _name = 'sf.production.process' @@ -51,6 +62,7 @@ class MrsProductionProcess(models.Model): active = fields.Boolean('有效', default=True) parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数') gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") + category_id = fields.Many2one('sf.production.process.category') class MrsProcessingTechnology(models.Model): diff --git a/sf_base/views/common_view.xml b/sf_base/views/common_view.xml index 1f5e2907..d89acc71 100644 --- a/sf_base/views/common_view.xml +++ b/sf_base/views/common_view.xml @@ -39,6 +39,59 @@ + + + + sf.production.process.category + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + sf.production.process.category + + + + + + + + + + search.sf.production.process.category + sf.production.process.category + + + + + + + + sf.production.process @@ -95,8 +148,6 @@ - - @@ -231,26 +282,6 @@ - - - - - - - - - - - - - - - - - - - - 材料 ir.actions.act_window @@ -290,13 +321,24 @@ sf.processing.technology tree,form -

加工工艺!

+ + 表面工艺类别 + ir.actions.act_window + sf.production.process.category + tree,form + +

+ 表面工艺类别! +

+
+
+ #------------------托盘------------------ 托盘 diff --git a/sf_base/views/menu_view.xml b/sf_base/views/menu_view.xml index 3b329ccb..620712ac 100644 --- a/sf_base/views/menu_view.xml +++ b/sf_base/views/menu_view.xml @@ -63,6 +63,13 @@ action="sf_production_process" /> + mrp.bom.form.inherit.sf mrp.bom - + - - - - - - - - - - + + 同步表面工艺类别 + + code + model.sync_production_process_category() + 1 + days + -1 + + 同步资源库机床型号 @@ -132,7 +132,7 @@ - + 同步表面工艺可选参数 code diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index 9a61ce8d..856b3c83 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -26,6 +26,8 @@ class ResConfigSettings(models.TransientModel): _logger.info("同步资源库材料型号") self.env['sf.production.process'].sync_all_production_process() _logger.info("同步资源库表面工艺") + self.env['sf.production.process.category'].sync_all_production_process_category() + _logger.info("同步资源库表面工艺类别") self.env['sf.processing.technology'].sync_all_processing_technology() _logger.info("同步资源库加工工艺") self.env['sf.machine.brand.tags'].sync_all_machine_brand_tags() diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index 6cdd98ba..c4da9926 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -6,6 +6,7 @@ from odoo import models from odoo.exceptions import ValidationError import logging from odoo.addons.sf_base.commons.common import Common + _logger = logging.getLogger(__name__) @@ -162,6 +163,66 @@ class sfMaterialModel(models.Model): raise ValidationError("认证未通过") +class sfProductionProcessCategory(models.Model): + _inherit = 'sf.production.process.category' + _description = '表面工艺类别' + url = '/api/production_process_category/list' + + # 定时同步每日表面工艺类别 + def sync_production_process_category(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + + strUrl = sf_sync_config['sf_url'] + self.url + r = requests.post(strUrl, json={}, data=None, headers=headers) + r = r.json() + result = json.loads(r['result']) + if result['status'] == 1: + for item in result['production_process_category_yesterday_list']: + if item: + production_process_category = self.env['sf.production.process.category'].search( + [("code", '=', item['code'])]) + if production_process_category: + production_process_category.name = item['name'], + production_process_category.code = item['code'], + production_process_category.active = item['active'] + else: + self.env['sf.production.process.category'].create({ + "name": item['name'], + "code": item['code'], + "active": item['active'], + }) + else: + raise ValidationError("认证未通过") # 定时同步表面工艺 + + # 同步所有表面工艺类别 + def sync_all_production_process_category(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + + strUrl = sf_sync_config['sf_url'] + self.url + r = requests.post(strUrl, json={}, data=None, headers=headers) + r = r.json() + result = json.loads(r['result']) + if result['status'] == 1: + for item in result['production_process_category_all_list']: + if item: + category = self.env['sf.production.process.category'].search( + [("process_encode", '=', item['process_encode'])]) + if not category: + self.env['sf.production.process.category'].create({ + "name": item['name'], + "code": item['code'], + "active": item['active'], + }) + else: + raise ValidationError("认证未通过") + + class sfProductionProcess(models.Model): _inherit = 'sf.production.process' _description = '表面工艺' @@ -184,21 +245,21 @@ class sfProductionProcess(models.Model): brand = self.env['sf.production.process'].search( [("process_encode", '=', item['process_encode'])]) if brand: - brand.id = item['id'], brand.name = item['name'], + brand.category_id = self.env['sf.production.process.category'].search( + [("code", '=', item['category_code'])]).id, brand.process_encode = item['process_encode'], brand.remark = item['remark'], brand.active = item['active'], brand.remark = item['remark'] else: self.env['sf.production.process'].create({ - "id": item['id'], "name": item['name'], + "category_id": self.env['sf.production.process.category'].search( + [("code", '=', item['category_code'])]).id, "process_encode": item['process_encode'], "remark": item['remark'], "active": item['active'], - # "tag_ids": item['tag_ids'] - }) else: raise ValidationError("认证未通过") # 定时同步表面工艺 @@ -221,8 +282,9 @@ class sfProductionProcess(models.Model): [("process_encode", '=', item['process_encode'])]) if not brand: self.env['sf.production.process'].create({ - "id": item['id'], "name": item['name'], + "category_id": self.env['sf.production.process.category'].search( + [("code", '=', item['category_code'])]).id, "process_encode": item['process_encode'], "remark": item['remark'], "active": item['active'], @@ -949,6 +1011,7 @@ class sfProcessingOrder(models.Model): else: raise ValidationError("认证未通过") + class sfProductionProcessParameter(models.Model): _inherit = 'sf.production.process.parameter' _description = '表面工艺可选参数' @@ -980,7 +1043,7 @@ class sfProductionProcessParameter(models.Model): "name": item['name'], "code": item['code'], "active": item['active'], - "price" : item['price'], + "price": item['price'], "process_id": self.env['sf.production.process'].search( [('process_encode', '=', item['process_id_code'])]).id, 'materials_model_ids': self.env['sf.materials.model'].search( @@ -1019,4 +1082,4 @@ class sfProductionProcessParameter(models.Model): }) else: - raise ValidationError("认证未通过") \ No newline at end of file + raise ValidationError("认证未通过") From bf010e2ccaccd1716bb39feb9cd025be325672d7 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Mon, 27 Mar 2023 21:04:33 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E8=AD=A6=E5=91=8A?= =?UTF-8?q?=E5=8F=8A=E5=BC=80=E5=8F=91=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/__manifest__.py | 1 + sf_base/models/common.py | 2 + sf_base/security/ir.model.access.csv | 1 + sf_base/views/common_view.xml | 86 ++++++++++----------- sf_bf_connect/__manifest__.py | 3 +- sf_bf_connect/controllers/controllers.py | 1 - sf_bf_connect/models/jd_eclp.py | 4 +- sf_dlm/__manifest__.py | 5 +- sf_dlm/data/product_data.xml | 10 ++- sf_dlm/models/product_template.py | 30 +++---- sf_dlm/views/product_template_view.xml | 5 +- sf_machine_connect/__manifest__.py | 2 +- sf_manufacturing/__manifest__.py | 1 + sf_manufacturing/models/mrp_production.py | 2 +- sf_mrs_connect/__manifest__.py | 1 + sf_mrs_connect/models/res_config_setting.py | 4 +- sf_mrs_connect/models/sync_common.py | 2 +- sf_sale/__manifest__.py | 1 + 18 files changed, 89 insertions(+), 72 deletions(-) diff --git a/sf_base/__manifest__.py b/sf_base/__manifest__.py index 11931f4c..2daf3ec0 100644 --- a/sf_base/__manifest__.py +++ b/sf_base/__manifest__.py @@ -23,6 +23,7 @@ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 32c4b245..2a4fce98 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -63,6 +63,8 @@ class MrsProductionProcess(models.Model): parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数') gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") category_id = fields.Many2one('sf.production.process.category') + workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) + class MrsProcessingTechnology(models.Model): diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index c9e93e5b..816341ee 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -15,6 +15,7 @@ access_sf_tray,sf_tray,model_sf_tray,base.group_user,1,1,1,1 access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,1 access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,1 +access_sf_production_process_category,sf_production_process_category,model_sf_production_process_category,base.group_user,1,1,1,1 diff --git a/sf_base/views/common_view.xml b/sf_base/views/common_view.xml index d89acc71..89d6df00 100644 --- a/sf_base/views/common_view.xml +++ b/sf_base/views/common_view.xml @@ -108,55 +108,49 @@ sf.production.process
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - + + + + + + + + + + + + + + + - - - - - - - - -
-
-
- - - - - + + + + + + + + + + + +
+ + +
+
+
+ + + + + + + +
diff --git a/sf_bf_connect/__manifest__.py b/sf_bf_connect/__manifest__.py index bcec62fa..013390f1 100644 --- a/sf_bf_connect/__manifest__.py +++ b/sf_bf_connect/__manifest__.py @@ -13,13 +13,14 @@ 'depends': ['sf_base', 'sf_sale', 'sf_dlm'], 'data': [ 'views/res_partner_view.xml', - 'views/view.xml', + # 'views/view.xml', 'report/bill_report.xml', ], 'demo': [ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, diff --git a/sf_bf_connect/controllers/controllers.py b/sf_bf_connect/controllers/controllers.py index 12270d8e..471fc152 100644 --- a/sf_bf_connect/controllers/controllers.py +++ b/sf_bf_connect/controllers/controllers.py @@ -111,7 +111,6 @@ class Sf_Bf_Connect(http.Controller): product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has( purchase_embryo) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) - order_id.step_file = product.model_file i += 1 res['factory_order_no'] = order_id.name return json.JSONEncoder().encode(res) diff --git a/sf_bf_connect/models/jd_eclp.py b/sf_bf_connect/models/jd_eclp.py index 7eb1af20..5a7579af 100644 --- a/sf_bf_connect/models/jd_eclp.py +++ b/sf_bf_connect/models/jd_eclp.py @@ -1,4 +1,4 @@ -import cpca +#import cpca import logging import base64 import requests @@ -37,7 +37,7 @@ class JdEclp(models.Model): deliveryType = fields.Selection([('6', '特快零担'), ('25', '特快重货')], string='运输类型', default='25') # bill = fields.Char(string='物流面单') - bill = fields.Many2one('ir.attachment', string='物流面单', compute='query_bill_pdf') + # bill = fields.Many2one('ir.attachment', string='物流面单', compute='query_bill_pdf') # bill_show = fields.Binary(string='物流面单展示', readonly=True, related='self.bill.datas') bill_show = fields.Binary(string='物流面单展示', readonly=True) diff --git a/sf_dlm/__manifest__.py b/sf_dlm/__manifest__.py index e20486c8..ba5e706b 100644 --- a/sf_dlm/__manifest__.py +++ b/sf_dlm/__manifest__.py @@ -10,9 +10,11 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['mrp', 'base', 'sf_manufacturing', 'web_widget_model_viewer', 'mrp_subcontracting'], + 'depends': ['mrp', 'base', 'sf_manufacturing', 'web_widget_model_viewer', 'mrp_subcontracting', 'purchase_stock', + 'uom'], 'data': [ 'data/product_data.xml', + 'data/uom_data.xml', 'views/product_template_view.xml', 'views/product_workorder.xml' ], @@ -20,6 +22,7 @@ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, diff --git a/sf_dlm/data/product_data.xml b/sf_dlm/data/product_data.xml index f4b9b717..8e01b270 100644 --- a/sf_dlm/data/product_data.xml +++ b/sf_dlm/data/product_data.xml @@ -15,6 +15,11 @@ 原材料
+ + + + + CNC加工产品模板 @@ -29,7 +34,7 @@ true serial - + false 胚料自加工模板 @@ -45,6 +50,7 @@ true serial + false @@ -60,6 +66,7 @@ serial + false 胚料采购模板 @@ -74,6 +81,7 @@ serial + false \ No newline at end of file diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index 9dbfed49..1364c76e 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -1,8 +1,8 @@ from odoo import models, fields, api from odoo.exceptions import ValidationError from odoo.modules import get_resource_path -from OCC.Extend.DataExchange import read_step_file -from OCC.Extend.DataExchange import write_stl_file +# from OCC.Extend.DataExchange import read_step_file +# from OCC.Extend.DataExchange import write_stl_file import logging import base64 import hashlib @@ -30,8 +30,9 @@ class ResProductTemplate(models.Model): product_model_type_id = fields.Many2one('sf.model.type', string='产品模型类型') embryo_model_type_id = fields.Many2one('sf.model.type', string='胚料模型类型') model_processing_panel = fields.Char('模型加工面板') - model_surface_process_id = fields.Many2one('sf.production.process', string='表面工艺') - model_process_parameters_id = fields.Many2one('sf.processing.technology', string='工艺参数') + # model_surface_process_category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别') + model_surface_process_id = fields.Many2many('sf.production.process', 'rel_product_process', string='表面工艺') + model_process_parameters_id = fields.Many2many('sf.processing.technology', 'rel_product_technology', string='工艺参数') # model_price = fields.Float('模型单价', digits=(16, 3)) model_remark = fields.Char('模型备注说明') length = fields.Float('长[mm]', digits=(16, 3)) @@ -108,8 +109,8 @@ class ResProductTemplate(models.Model): [('materials_no', '=', item['texture_type_code'])]).id, 'model_surface_process_id': self.env['sf.production.process'].search( [('process_encode', '=', item['surface_process_code'])]).id, - # 'model_process_parameters_id': self.env['sf.processing.technology'].search( - # [('process_encode', '=', item['process_parameters_code'])]).id, + 'model_process_parameters_id': self.env['sf.processing.technology'].search( + [('process_encode', '=', item['process_parameters_code'])]).id, 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), # 'barcode': item['barcode'], @@ -182,14 +183,15 @@ class ResProductTemplate(models.Model): @api.model_create_multi def create(self, vals_list): for vals in vals_list: - if vals['upload_model_file']: - for item in vals['upload_model_file']: - attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))]) - base64_data = base64.b64encode(attachment.datas) - base64_datas = base64_data.decode('utf-8') - model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest() - report_path = attachment._full_path(attachment.store_fname) - vals['model_file'] = self.transition_glb_file(report_path, model_code) + if vals.get('upload_model_file'): + if vals.get('is_bfm') is False and vals.get('categ_type') == '成品': + for item in vals['upload_model_file']: + attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))]) + base64_data = base64.b64encode(attachment.datas) + base64_datas = base64_data.decode('utf-8') + model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest() + report_path = attachment._full_path(attachment.store_fname) + vals['model_file'] = self.transition_glb_file(report_path, model_code) self._sanitize_vals(vals) templates = super(ResProductTemplate, self).create(vals_list) if "create_product_product" not in self._context: diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index 7eb5f625..176a4669 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -14,7 +14,8 @@ + widget="many2many_binary" + attrs="{'invisible': ['|', ('categ_type', '!=', '成品'),('categ_type', '=', False)]}"/> @@ -24,6 +25,8 @@ + + diff --git a/sf_machine_connect/__manifest__.py b/sf_machine_connect/__manifest__.py index af66a542..26c849d9 100644 --- a/sf_machine_connect/__manifest__.py +++ b/sf_machine_connect/__manifest__.py @@ -34,7 +34,7 @@ 'assets': { }, - + 'license': 'LGPL-3', 'installable': True, 'application': True, # 'auto_install': False, diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 70277dca..2db63e1b 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -27,6 +27,7 @@ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index ebcee7bf..a8b8b0eb 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -248,7 +248,7 @@ class MrpProduction(models.Model): if work.name == '获取CNC加工程序': work.button_start() #work.button_finish() - work.fetchCNC() + #work.fetchCNC() #创建工单并进行排序 def _create_workorder(self): diff --git a/sf_mrs_connect/__manifest__.py b/sf_mrs_connect/__manifest__.py index 3954aa3f..b1955012 100644 --- a/sf_mrs_connect/__manifest__.py +++ b/sf_mrs_connect/__manifest__.py @@ -19,6 +19,7 @@ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index 856b3c83..8aae305a 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -24,10 +24,10 @@ class ResConfigSettings(models.TransientModel): _logger.info("同步资源库材料") self.env['sf.materials.model'].sync_all_materials_model() _logger.info("同步资源库材料型号") - self.env['sf.production.process'].sync_all_production_process() - _logger.info("同步资源库表面工艺") self.env['sf.production.process.category'].sync_all_production_process_category() _logger.info("同步资源库表面工艺类别") + self.env['sf.production.process'].sync_all_production_process() + _logger.info("同步资源库表面工艺") self.env['sf.processing.technology'].sync_all_processing_technology() _logger.info("同步资源库加工工艺") self.env['sf.machine.brand.tags'].sync_all_machine_brand_tags() diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index c4da9926..d751a090 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -212,7 +212,7 @@ class sfProductionProcessCategory(models.Model): for item in result['production_process_category_all_list']: if item: category = self.env['sf.production.process.category'].search( - [("process_encode", '=', item['process_encode'])]) + [("code", '=', item['code'])]) if not category: self.env['sf.production.process.category'].create({ "name": item['name'], diff --git a/sf_sale/__manifest__.py b/sf_sale/__manifest__.py index 51769040..1414f297 100644 --- a/sf_sale/__manifest__.py +++ b/sf_sale/__manifest__.py @@ -18,6 +18,7 @@ ], 'qweb': [ ], + 'license': 'LGPL-3', 'installable': True, 'application': False, 'auto_install': False, From 93c9287717b88938ba2c40697eea998f0412e7a2 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Tue, 28 Mar 2023 21:26:02 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=A1=A8=E9=9D=A2?= =?UTF-8?q?=E5=B7=A5=E8=89=BA=E5=A4=96=E5=8D=8F=E5=AD=97=E6=AE=B5=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/product_template.py | 28 ++++++--- sf_dlm/views/product_template_view.xml | 11 ++-- sf_manufacturing/models/stock.py | 87 +++++++++++++++++++++++++- 3 files changed, 113 insertions(+), 13 deletions(-) diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index 1364c76e..d37e2887 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -31,8 +31,9 @@ class ResProductTemplate(models.Model): embryo_model_type_id = fields.Many2one('sf.model.type', string='胚料模型类型') model_processing_panel = fields.Char('模型加工面板') # model_surface_process_category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别') - model_surface_process_id = fields.Many2many('sf.production.process', 'rel_product_process', string='表面工艺') - model_process_parameters_id = fields.Many2many('sf.processing.technology', 'rel_product_technology', string='工艺参数') + model_surface_process_ids = fields.Many2many('sf.production.process', 'rel_product_process', string='表面工艺') + model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'rel_product_parameter', + string='工艺参数') # model_price = fields.Float('模型单价', digits=(16, 3)) model_remark = fields.Char('模型备注说明') length = fields.Float('长[mm]', digits=(16, 3)) @@ -99,6 +100,7 @@ class ResProductTemplate(models.Model): 'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']), 'model_name': attachment.name, 'upload_model_file': [(6, 0, [attachment.id])], + # 'tag_ids': [(6, 0, [t.id for t in account_template.tag_ids])], # 'single_manufacturing': True, # 'tracking': 'serial', 'list_price': item['price'], @@ -107,10 +109,8 @@ class ResProductTemplate(models.Model): [('materials_no', '=', item['texture_code'])]).id, 'materials_type_id': self.env['sf.materials.model'].search( [('materials_no', '=', item['texture_type_code'])]).id, - 'model_surface_process_id': self.env['sf.production.process'].search( - [('process_encode', '=', item['surface_process_code'])]).id, - 'model_process_parameters_id': self.env['sf.processing.technology'].search( - [('process_encode', '=', item['process_parameters_code'])]).id, + 'model_surface_process_ids': self.get_production_process_id(item['surface_process_code']), + 'model_process_parameters_ids': self.get_process_parameters_id(item['process_parameters_code']), 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), # 'barcode': item['barcode'], @@ -121,6 +121,20 @@ class ResProductTemplate(models.Model): # product_id.product_tmpl_id.active = False return copy_product_id + def get_production_process_id(self, surface_process_code): + production_process_ids = [] + for item in surface_process_code: + production_process = self.env['sf.production.process'].search([('process_encode', '=', item)]) + production_process_ids.append(production_process.id) + return [(6, 0, production_process_ids)] + + def get_process_parameters_id(self, process_parameters_code): + process_parameters_ids = [] + for item in process_parameters_code: + process_parameters = self.env['sf.production.process.parameter'].search([('code', '=', item)]) + process_parameters_ids.append(process_parameters.id) + return [(6, 0, process_parameters_ids)] + def attachment_create(self, name, data): attachment = self.env['ir.attachment'].create({ 'datas': base64.b64decode(data), @@ -226,7 +240,7 @@ class ResProductTemplate(models.Model): item.model_file = self.transition_glb_file(report_path, model_code) # 将attach的datas内容转为glb文件 - def transition_glb_file(self,report_path, code): + def transition_glb_file(self, report_path, code): shapes = read_step_file(report_path) output_file = os.path.join('/tmp', str(code) + '.stl') write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index 176a4669..aeb4ee63 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -25,8 +25,10 @@ - - + + @@ -67,9 +69,8 @@ - - + + diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 03095ad4..abd7fad8 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -3,8 +3,9 @@ from collections import defaultdict, namedtuple from odoo.addons.stock.models.stock_rule import ProcurementException from re import findall as regex_findall from re import split as regex_split -from odoo import SUPERUSER_ID, _, api, models +from odoo import SUPERUSER_ID, _, api, models from odoo.tools import float_compare +from odoo.exceptions import UserError class StockRule(models.Model): @@ -226,3 +227,87 @@ class ProductionLot(models.Model): return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[ 1] return "%s-%03d" % (product.name, 1) + + +# class ResPurchaseOrder(models.Model): +# _inherit = 'purchase.order' +# +# # def button_approve(self, force=False): +# # result = super().button_approve(force=force) +# # self._create_picking_RES() +# # return result +# +# # @api.depends('order_line.move_ids') +# # def _compute_subcontracting_resupply_picking_count(self): +# # for purchase in self: +# # purchase.subcontracting_resupply_picking_count = len(purchase._get_subcontracting_resupplies_new()) +# # +# # def _get_subcontracting_resupplies_new(self): +# # moves_subcontracted = self.order_line.move_ids.filtered(lambda m: m.is_subcontract) +# # # subcontracted_productions = moves_subcontracted.move_orig_ids.production_id +# # return moves_subcontracted.picking_id +# +# def _prepare_picking_RES(self): +# if not self.group_id: +# self.group_id = self.group_id.create({ +# 'name': self.name, +# 'partner_id': self.partner_id.id +# }) +# if not self.partner_id.property_stock_supplier.id: +# raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) +# picking_type_id_res = self.env['stock.picking.type'].search( +# [('sequence_code', '=', 'RES'), ('barcode', '=', 'WH-RESUPPLY')]) +# return { +# 'picking_type_id': picking_type_id_res.id if picking_type_id_res else self.picking_type_id.id, +# 'partner_id': self.partner_id.id, +# 'user_id': False, +# 'date': self.date_order, +# 'origin': self.name, +# 'location_dest_id': self._get_destination_location(), +# 'location_id': self.partner_id.property_stock_supplier.id, +# 'company_id': self.company_id.id, +# } +# +# def _create_picking(self): +# StockPicking = self.env['stock.picking'] +# for order in self.filtered(lambda po: po.state in ('purchase', 'done')): +# if any(product.type in ['product', 'consu'] for product in order.order_line.product_id): +# order = order.with_company(order.company_id) +# pickings = order.picking_ids.filtered(lambda x: x.state not in ('done', 'cancel')) +# if not pickings: +# if order.order_line.product_id.categ_type == '胚料': +# res = order._prepare_picking_RES() +# else: +# res = order._prepare_picking() +# picking = StockPicking.with_user(SUPERUSER_ID).create(res) +# pickings = picking +# else: +# picking = pickings[0] +# moves = order.order_line._create_stock_moves(picking) +# moves = moves.filtered(lambda x: x.state not in ('done', 'cancel'))._action_confirm() +# seq = 0 +# for move in sorted(moves, key=lambda move: move.date): +# seq += 5 +# move.sequence = seq +# moves._action_assign() +# # Get following pickings (created by push rules) to confirm them as well. +# forward_pickings = self.env['stock.picking']._get_impacted_pickings(moves) +# (pickings | forward_pickings).action_confirm() +# picking.message_post_with_view('mail.message_origin_link', +# values={'self': picking, 'origin': order}, +# subtype_id=self.env.ref('mail.mt_note').id) +# return True +# +# +# class ResPurchaseOrderLine(models.Model): +# _inherit = 'purchase.order.line' +# +# def _create_stock_moves(self, picking): +# values = [] +# for line in self.filtered(lambda l: not l.display_type): +# for val in line._prepare_stock_moves(picking): +# val['production_id'] = 10 +# values.append(val) +# line.move_dest_ids.created_purchase_line_id = False +# +# return self.env['stock.move'].create(values) From 20d9e469f5699267c760c325078b79c8fb8dd3fc Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 29 Mar 2023 17:48:03 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E7=B1=BB=E5=88=AB=E6=8B=96=E5=8A=A8=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 15 +- sf_base/views/common_view.xml | 32 ++++- sf_dlm/views/product_template_view.xml | 6 +- sf_manufacturing/models/mrp_production.py | 4 + sf_manufacturing/models/mrp_workorder.py | 18 +++ sf_manufacturing/models/stock.py | 165 +++++++++++----------- sf_mrs_connect/models/sync_common.py | 6 +- 7 files changed, 147 insertions(+), 99 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 2a4fce98..02d1237b 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -45,6 +45,7 @@ class MrsProductionProcessCategory(models.Model): name = fields.Char('名称') code = fields.Char("编码") + sequence = fields.Integer('排序') production_process_ids = fields.One2many('sf.production.process', 'category_id', string="表面工艺") active = fields.Boolean('有效', default=True) @@ -61,9 +62,8 @@ class MrsProductionProcess(models.Model): partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂') active = fields.Boolean('有效', default=True) parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数') - gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") category_id = fields.Many2one('sf.production.process.category') - workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) + # workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) @@ -112,12 +112,15 @@ class SupplierSort(models.Model): ('supplier_sort_uniq', 'unique (partner_id,materials_model_id)', '排序不能重复!') ] + class MrsProductionProcessParameter(models.Model): _name = 'sf.production.process.parameter' _description = '可选参数' - name = fields.Char('参数名') - active = fields.Boolean('有效', default=True) - price = fields.Float('单价') + + code = fields.Char("编码") + name = fields.Char('名称') + gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") + # price = fields.Float('单价') process_id = fields.Many2one('sf.production.process', string='表面工艺') materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料') - code = fields.Char("编码") \ No newline at end of file + active = fields.Boolean('有效', default=True) \ No newline at end of file diff --git a/sf_base/views/common_view.xml b/sf_base/views/common_view.xml index 89d6df00..82e1e918 100644 --- a/sf_base/views/common_view.xml +++ b/sf_base/views/common_view.xml @@ -49,6 +49,7 @@ + @@ -74,8 +75,9 @@ sf.production.process.category - - + + + @@ -112,22 +114,38 @@ - - - - - + + +
+ + + + + + + + + + + + + + + + + +
diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index aeb4ee63..75345845 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -26,7 +26,11 @@ + > + + + + diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index a8b8b0eb..b371fd29 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -127,6 +127,10 @@ class MrpProduction(models.Model): if i == processing_panel_len and route.routing_type == '解除装夹': workorders_values.append( self.env['mrp.workorder'].json_workorder_str(k, production, route)) + # 表面工艺 + # for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: + # workorders_values.append( + # self.env['mrp.workorder']._json_workorder_surface_process_str(production, item)) elif production.product_id.categ_id.type == '胚料': embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( [('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)], diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index f858c88d..6b0d5b2a 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -157,6 +157,24 @@ class ResMrpWorkOrder(models.Model): }] return workorders_values_str + # 拼接工单对象属性值(表面工艺) + def _json_workorder_surface_process_str(self, production, route): + workorders_values_str = [0, '', { + 'product_uom_id': production.product_uom_id.id, + 'qty_producing': 0, + 'operation_id': False, + 'name': route.name, + 'processing_panel': '', + 'routing_type': '绑定表面工艺', + 'work_state': '', + 'workcenter_id': '', + 'date_planned_start': False, + 'date_planned_finished': False, + 'duration_expected': 60, + 'duration': 0 + }] + return workorders_values_str + # 维修模块按钮 def button_maintenance_req(self): self.ensure_one() diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index abd7fad8..ef1805eb 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -229,85 +229,86 @@ class ProductionLot(models.Model): return "%s-%03d" % (product.name, 1) -# class ResPurchaseOrder(models.Model): -# _inherit = 'purchase.order' -# -# # def button_approve(self, force=False): -# # result = super().button_approve(force=force) -# # self._create_picking_RES() -# # return result -# -# # @api.depends('order_line.move_ids') -# # def _compute_subcontracting_resupply_picking_count(self): -# # for purchase in self: -# # purchase.subcontracting_resupply_picking_count = len(purchase._get_subcontracting_resupplies_new()) -# # -# # def _get_subcontracting_resupplies_new(self): -# # moves_subcontracted = self.order_line.move_ids.filtered(lambda m: m.is_subcontract) -# # # subcontracted_productions = moves_subcontracted.move_orig_ids.production_id -# # return moves_subcontracted.picking_id -# -# def _prepare_picking_RES(self): -# if not self.group_id: -# self.group_id = self.group_id.create({ -# 'name': self.name, -# 'partner_id': self.partner_id.id -# }) -# if not self.partner_id.property_stock_supplier.id: -# raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) -# picking_type_id_res = self.env['stock.picking.type'].search( -# [('sequence_code', '=', 'RES'), ('barcode', '=', 'WH-RESUPPLY')]) -# return { -# 'picking_type_id': picking_type_id_res.id if picking_type_id_res else self.picking_type_id.id, -# 'partner_id': self.partner_id.id, -# 'user_id': False, -# 'date': self.date_order, -# 'origin': self.name, -# 'location_dest_id': self._get_destination_location(), -# 'location_id': self.partner_id.property_stock_supplier.id, -# 'company_id': self.company_id.id, -# } -# -# def _create_picking(self): -# StockPicking = self.env['stock.picking'] -# for order in self.filtered(lambda po: po.state in ('purchase', 'done')): -# if any(product.type in ['product', 'consu'] for product in order.order_line.product_id): -# order = order.with_company(order.company_id) -# pickings = order.picking_ids.filtered(lambda x: x.state not in ('done', 'cancel')) -# if not pickings: -# if order.order_line.product_id.categ_type == '胚料': -# res = order._prepare_picking_RES() -# else: -# res = order._prepare_picking() -# picking = StockPicking.with_user(SUPERUSER_ID).create(res) -# pickings = picking -# else: -# picking = pickings[0] -# moves = order.order_line._create_stock_moves(picking) -# moves = moves.filtered(lambda x: x.state not in ('done', 'cancel'))._action_confirm() -# seq = 0 -# for move in sorted(moves, key=lambda move: move.date): -# seq += 5 -# move.sequence = seq -# moves._action_assign() -# # Get following pickings (created by push rules) to confirm them as well. -# forward_pickings = self.env['stock.picking']._get_impacted_pickings(moves) -# (pickings | forward_pickings).action_confirm() -# picking.message_post_with_view('mail.message_origin_link', -# values={'self': picking, 'origin': order}, -# subtype_id=self.env.ref('mail.mt_note').id) -# return True -# -# -# class ResPurchaseOrderLine(models.Model): -# _inherit = 'purchase.order.line' -# -# def _create_stock_moves(self, picking): -# values = [] -# for line in self.filtered(lambda l: not l.display_type): -# for val in line._prepare_stock_moves(picking): -# val['production_id'] = 10 -# values.append(val) -# line.move_dest_ids.created_purchase_line_id = False -# -# return self.env['stock.move'].create(values) +class ResPurchaseOrder(models.Model): + _inherit = 'purchase.order' + + # def button_approve(self, force=False): + # result = super().button_approve(force=force) + # self._create_picking_RES() + # return result + + # @api.depends('order_line.move_ids') + # def _compute_subcontracting_resupply_picking_count(self): + # for purchase in self: + # purchase.subcontracting_resupply_picking_count = len(purchase._get_subcontracting_resupplies_new()) + # + # def _get_subcontracting_resupplies_new(self): + # moves_subcontracted = self.order_line.move_ids.filtered(lambda m: m.is_subcontract) + # # subcontracted_productions = moves_subcontracted.move_orig_ids.production_id + # return moves_subcontracted.picking_id + + def _prepare_picking_RES(self): + if not self.group_id: + self.group_id = self.group_id.create({ + 'name': self.name, + 'partner_id': self.partner_id.id + }) + if not self.partner_id.property_stock_supplier.id: + raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) + picking_type_id_res = self.env['stock.picking.type'].search( + [('sequence_code', '=', 'RES'), ('barcode', '=', 'WH-RESUPPLY')]) + return { + 'picking_type_id': picking_type_id_res.id if picking_type_id_res else self.picking_type_id.id, + 'partner_id': self.partner_id.id, + 'user_id': False, + 'date': self.date_order, + 'origin': self.name, + 'location_dest_id': self._get_destination_location(), + 'location_id': self.partner_id.property_stock_supplier.id, + 'company_id': self.company_id.id, + } + + def _create_picking(self): + StockPicking = self.env['stock.picking'] + for order in self.filtered(lambda po: po.state in ('purchase', 'done')): + if any(product.type in ['product', 'consu'] for product in order.order_line.product_id): + order = order.with_company(order.company_id) + pickings = order.picking_ids.filtered(lambda x: x.state not in ('done', 'cancel')) + if not pickings: + if order.order_line.product_id.categ_type == '胚料': + res = order._prepare_picking_RES() + else: + res = order._prepare_picking() + picking = StockPicking.with_user(SUPERUSER_ID).create(res) + pickings = picking + else: + picking = pickings[0] + moves = order.order_line._create_stock_moves(picking) + moves = moves.filtered(lambda x: x.state not in ('done', 'cancel'))._action_confirm() + seq = 0 + for move in sorted(moves, key=lambda move: move.date): + seq += 5 + move.sequence = seq + moves._action_assign() + # Get following pickings (created by push rules) to confirm them as well. + forward_pickings = self.env['stock.picking']._get_impacted_pickings(moves) + (pickings | forward_pickings).action_confirm() + picking.message_post_with_view('mail.message_origin_link', + values={'self': picking, 'origin': order}, + subtype_id=self.env.ref('mail.mt_note').id) + return True + + +class ResPurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + def _create_stock_moves(self, picking): + values = [] + for line in self.filtered(lambda l: not l.display_type): + for val in line._prepare_stock_moves(picking): + # val['production_id'] = 10 + val['is_subcontract'] = True + values.append(val) + line.move_dest_ids.created_purchase_line_id = False + + return self.env['stock.move'].create(values) diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index d751a090..5d97dbe6 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -1037,13 +1037,13 @@ class sfProductionProcessParameter(models.Model): brand.name = item['name'], brand.code = item['code'], brand.active = item['active'], - brand.price = item['price'], + # brand.price = item['price'], else: self.env['sf.production.process.parameter'].create({ "name": item['name'], "code": item['code'], "active": item['active'], - "price": item['price'], + # "price": item['price'], "process_id": self.env['sf.production.process'].search( [('process_encode', '=', item['process_id_code'])]).id, 'materials_model_ids': self.env['sf.materials.model'].search( @@ -1073,7 +1073,7 @@ class sfProductionProcessParameter(models.Model): self.env['sf.production.process.parameter'].create({ "name": item['name'], "code": item['code'], - "price": item['price'], + # "price": item['price'], "active": item['active'], "process_id": self.env['sf.production.process'].search( [('process_encode', '=', item['process_id_code'])]).id, From a008dbb76a082cbc093c93b22df9b98233c07463 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Thu, 30 Mar 2023 17:52:05 +0800 Subject: [PATCH 06/13] =?UTF-8?q?1.sf=E7=9A=84=E5=B7=A5=E4=BD=9C=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E6=96=B0=E5=A2=9E=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=B7=A5=E5=BA=8F=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E4=B8=94=E5=BD=93=E5=B7=A5=E5=BA=8F=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=B8=BA=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=88=99=E6=98=BE=E7=A4=BA=E8=A1=A8=E9=9D=A2=E5=B7=A5?= =?UTF-8?q?=E8=89=BA=EF=BC=8C=E5=85=B6=E4=BB=96=E5=88=99=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=202.sf=E7=9A=84=E5=B7=A5=E4=BD=9C=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B7=A5=E8=89=BA=E5=A4=96=E5=8D=8F=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=8C=E8=AF=A5=E5=AD=97=E6=AE=B5=E8=8B=A5=E8=A2=AB?= =?UTF-8?q?=E5=8B=BE=E9=80=89=E5=88=99=E4=B8=BA=E8=A1=A8=E9=9D=A2=E5=B7=A5?= =?UTF-8?q?=E8=89=BA=E7=9A=84=E5=A4=96=E5=8D=8F=E5=8A=A0=E5=B7=A5=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=203.sf=E7=9A=84=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E4=B8=8A=E7=82=B9=E5=87=BB=E7=94=9F=E6=88=90=E5=88=B6=E9=80=A0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=97=B6=E5=9C=A8=E5=B7=B2=E6=9C=89=E7=9A=84?= =?UTF-8?q?=E6=88=90=E5=93=81=E5=B7=A5=E5=BA=8F=E5=90=8E=E7=B4=AF=E5=8A=A0?= =?UTF-8?q?=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E5=B7=A5=E5=BA=8F=EF=BC=8C?= =?UTF-8?q?=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E7=9A=84=E5=B7=A5=E5=BA=8F?= =?UTF-8?q?=E7=94=9F=E6=88=90=E8=A7=84=E5=88=99=E9=9C=80=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E6=89=80=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E7=B1=BB=E5=88=AB=E7=9A=84=E6=8E=92=E5=BA=8F=E6=9D=A5?= =?UTF-8?q?=E4=BE=9D=E6=AC=A1=E7=94=9F=E6=88=90=EF=BC=8C=E5=B9=B6=E4=B8=94?= =?UTF-8?q?=E5=B7=A5=E5=BA=8F=E9=87=8C=E7=9A=84=E5=B7=A5=E4=BD=9C=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E7=9A=84=E5=8C=B9=E9=85=8D=E8=A7=84=E5=88=99=E9=9C=80?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E7=9A=84?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E5=8F=82=E6=95=B0=E9=87=8C=E7=9A=84=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=96=B9=E5=BC=8F=E5=AD=97=E6=AE=B5=E7=9A=84=E5=80=BC?= =?UTF-8?q?=E6=9D=A5=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 8 ++- sf_manufacturing/models/model_type.py | 6 +- sf_manufacturing/models/mrp_production.py | 58 +++++++++++++------ .../models/mrp_routing_workcenter.py | 13 ++++- sf_manufacturing/models/mrp_workcenter.py | 7 ++- sf_manufacturing/models/mrp_workorder.py | 12 ++-- .../views/mrp_routing_workcenter_view.xml | 2 + .../views/mrp_workcenter_views.xml | 3 + 8 files changed, 79 insertions(+), 30 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 02d1237b..758a9950 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -66,7 +66,6 @@ class MrsProductionProcess(models.Model): # workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) - class MrsProcessingTechnology(models.Model): _name = 'sf.processing.technology' _description = '加工工艺' @@ -123,4 +122,9 @@ class MrsProductionProcessParameter(models.Model): # price = fields.Float('单价') process_id = fields.Many2one('sf.production.process', string='表面工艺') materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料') - active = fields.Boolean('有效', default=True) \ No newline at end of file + active = fields.Boolean('有效', default=True) + + # 获取表面工艺的获取方式 + def get_gain_way(self, item): + process_parameter = self.env['sf.production.process.parameter'].search([('id', '=', item.id)]) + return process_parameter diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index 2787d28e..c37711ed 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -29,7 +29,7 @@ class ProductModelTypeRoutingSort(models.Model): ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), - ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') + ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') product_model_type_id = fields.Many2one('sf.model.type') @@ -52,7 +52,7 @@ class EmbryoModelTypeRoutingSort(models.Model): ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), - ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') + ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') embryo_model_type_id = fields.Many2one('sf.model.type') @@ -75,7 +75,7 @@ class SurfaceTechnicsModelTypeRoutingSort(models.Model): ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), - ('解除装夹', '解除装夹'), ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') + ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') surface_technics_model_type_id = fields.Many2one('sf.model.type') diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index b371fd29..d027b157 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -23,7 +23,7 @@ class MrpProduction(models.Model): for production in self: production.maintenance_count = len(production.request_ids) - #维修模块按钮 + # 维修模块按钮 def button_maintenance_req(self): self.ensure_one() return { @@ -37,7 +37,8 @@ class MrpProduction(models.Model): }, 'domain': [('production_id', '=', self.id)], } - #打开维修模块请求 + + # 打开维修模块请求 def open_maintenance_request_mo(self): self.ensure_one() action = { @@ -59,7 +60,8 @@ class MrpProduction(models.Model): def action_generate_serial(self): self.ensure_one() - iot_code = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial') + iot_code = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[ + 'ir.sequence'].next_by_code('stock.lot.serial') iot_code_name = re.sub('[\u4e00-\u9fa5]', "", iot_code) self.lot_producing_id = self.env['stock.lot'].create({ 'product_id': self.product_id.id, @@ -127,10 +129,33 @@ class MrpProduction(models.Model): if i == processing_panel_len and route.routing_type == '解除装夹': workorders_values.append( self.env['mrp.workorder'].json_workorder_str(k, production, route)) - # 表面工艺 - # for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: - # workorders_values.append( - # self.env['mrp.workorder']._json_workorder_surface_process_str(production, item)) + # 表面工艺工序 + # 获取表面工艺id + surface_technics_arr = [] + #工序id + route_workcenter_arr = [] + for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: + surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id) + route_workcenter_arr.append(item.route_workcenter_id) + if surface_technics_arr: + production_process = self.env['sf.production.process.category'].search( + [('production_process_ids.id', 'in', surface_technics_arr)], + order='sequence asc' + ) + if production_process: + for p in production_process: + for pitem in p.production_process_ids: + if pitem.id in surface_technics_arr: + process_parameter = self.env['sf.production.process.parameter'].search( + [('id', '=', pitem.id)]) + for ritem in route_workcenter_arr: + route_production_process = self.env['mrp.routing.workcenter'].search( + [('surface_technics_id', '=', pitem.id), ('id', '=', ritem)]) + if route_production_process: + workorders_values.append( + self.env['mrp.workorder']._json_workorder_surface_process_str( + production, route_production_process, + process_parameter)) elif production.product_id.categ_id.type == '胚料': embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( [('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)], @@ -143,8 +168,7 @@ class MrpProduction(models.Model): for workorder in production.workorder_ids: workorder.duration_expected = workorder._get_duration_expected() - - #在之前的销售单上重新生成制造订单 + # 在之前的销售单上重新生成制造订单 def create_production1_values(self, production): production_values_str = {'origin': production.origin, 'product_id': production.product_id.id, @@ -166,7 +190,7 @@ class MrpProduction(models.Model): 'user_id': production.user_id.id} return production_values_str - #工单排序 + # 工单排序 def _reset_work_order_sequence1(self, k): sequen = 0 for rec in self: @@ -183,7 +207,7 @@ class MrpProduction(models.Model): if work.name == 'CNC加工(返工)' and work.processing_panel == k: work.sequence = sequen + 1 - #在制造订单上新增工单 + # 在制造订单上新增工单 def _create_workorder1(self, k): for production in self: if not production.bom_id or not production.product_id: @@ -217,9 +241,9 @@ class MrpProduction(models.Model): production.product_id.model_processing_panel = k for k in (production.product_id.model_processing_panel.split(',')): routingworkcenter = self.env['sf.product.model.type.routing.sort'].search( - [('product_model_type_id', '=', production.product_id.product_model_type_id.id)], - order='sequence asc' - ) + [('product_model_type_id', '=', production.product_id.product_model_type_id.id)], + order='sequence asc' + ) i += 1 for route in routingworkcenter: @@ -251,10 +275,10 @@ class MrpProduction(models.Model): current_sequence += 1 if work.name == '获取CNC加工程序': work.button_start() - #work.button_finish() - #work.fetchCNC() + # work.button_finish() + # work.fetchCNC() - #创建工单并进行排序 + # 创建工单并进行排序 def _create_workorder(self): res = self._create_workorder3() self._reset_work_order_sequence() diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index 8eb22ca5..7f7a98d7 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -1,4 +1,5 @@ from odoo import fields, models +import logging class ResMrpRoutingWorkcenter(models.Model): @@ -12,12 +13,13 @@ class ResMrpRoutingWorkcenter(models.Model): ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), ('切割', '切割'), - ('绑定表面工艺', '绑定表面工艺') + ('表面工艺', '表面工艺') ], string="工序类型") is_repeat = fields.Boolean('重复', default=False) workcenter_id = fields.Many2one('mrp.workcenter', required=False) workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True) bom_id = fields.Many2one('mrp.bom', required=False) + surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺") # 获得当前登陆者公司 def get_company_id(self): @@ -25,6 +27,7 @@ class ResMrpRoutingWorkcenter(models.Model): company_id = fields.Many2one('res.company', compute="get_company_id", related=False) + # 排产的时候, 根据胚料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床). # 工单对应的工作中心,根据工序中的工作中心去匹配, # 如果只配置了一个工作中心,则默认采用该工作中心; @@ -40,7 +43,7 @@ class ResMrpRoutingWorkcenter(models.Model): workcenter = self.env['mrp.workcenter'].search([('id', 'in', workcenter_ids)]) workcenter_ids = [] for item in workcenter: - print(item.name) + logging.info('get_workcenter-vals:%s' % item.machine_tool_id.name) if item.machine_tool_id: machine_tool = self.env['sf.machine_tool'].search( [('x_axis', '>', product.bom_ids.bom_line_ids.product_id.length), @@ -55,5 +58,9 @@ class ResMrpRoutingWorkcenter(models.Model): SELECT workcenter_id FROM mrp_workorder where workcenter_id in %s group by workcenter_id order by count(*),workcenter_id asc limit 1 """, [tuple(workcenter_ids)]) - workcenter_id = self.env.cr.dictfetchall()[0].get('workcenter_id') + res = self.env.cr.fetchone() + if res: + workcenter_id = self.env.cr.dictfetchall()[0].get('workcenter_id') + else: + workcenter_id = workcenter_ids[0] return workcenter_id diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index 5b266a20..fcfe04ce 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -7,13 +7,18 @@ from odoo.addons.resource.models.resource import Intervals class ResWorkcenter(models.Model): _inherit = "mrp.workcenter" machine_tool_id = fields.Many2one('sf.machine_tool', '机床') - + is_process_outsourcing = fields.Boolean('工艺外协') users_ids = fields.Many2many("res.users", 'users_workcenter') equipment_ids = fields.One2many( 'maintenance.equipment', 'workcenter_id', string="Maintenance Equipment", check_company=True) + # 查询工艺外协加工中心 + def get_process_outsourcing_workcenter(self): + outsourcing_workcenter = self.env['mrp.workcenter'].search([('is_process_outsourcing', '=', True)]) + return outsourcing_workcenter.id + @api.onchange('machine_tool_id') def update_machine_tool_is_binding(self): machine_tool = self.env["sf.machine_tool"].search([('is_binding', '=', True)]) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 6b0d5b2a..5a049d0d 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -29,7 +29,7 @@ class ResMrpWorkOrder(models.Model): ('CNC加工', 'CNC加工'), ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), - ('切割', '切割'), ('绑定表面工艺', '绑定表面工艺') + ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型") results = fields.Char('检测结果') @@ -158,16 +158,20 @@ class ResMrpWorkOrder(models.Model): return workorders_values_str # 拼接工单对象属性值(表面工艺) - def _json_workorder_surface_process_str(self, production, route): + def _json_workorder_surface_process_str(self, production, route, process_parameter): workorders_values_str = [0, '', { 'product_uom_id': production.product_uom_id.id, 'qty_producing': 0, 'operation_id': False, 'name': route.name, 'processing_panel': '', - 'routing_type': '绑定表面工艺', + 'routing_type': '表面工艺', 'work_state': '', - 'workcenter_id': '', + 'workcenter_id': self.env[ + 'mrp.workcenter'].get_process_outsourcing_workcenter() if process_parameter.gain_way == '外协' else + self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, + route.routing_type, + production.product_id), 'date_planned_start': False, 'date_planned_finished': False, 'duration_expected': 60, diff --git a/sf_manufacturing/views/mrp_routing_workcenter_view.xml b/sf_manufacturing/views/mrp_routing_workcenter_view.xml index b854160a..d0db3a7b 100644 --- a/sf_manufacturing/views/mrp_routing_workcenter_view.xml +++ b/sf_manufacturing/views/mrp_routing_workcenter_view.xml @@ -8,6 +8,8 @@ + diff --git a/sf_manufacturing/views/mrp_workcenter_views.xml b/sf_manufacturing/views/mrp_workcenter_views.xml index cc6f1ba9..8c16f783 100644 --- a/sf_manufacturing/views/mrp_workcenter_views.xml +++ b/sf_manufacturing/views/mrp_workcenter_views.xml @@ -109,6 +109,9 @@ + + +
From 6ff307f3640c729b5221cc2c7e17ecc1fae3f926 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Mon, 3 Apr 2023 17:42:31 +0800 Subject: [PATCH 07/13] =?UTF-8?q?1.=E4=BC=98=E5=8C=96sf=E7=9A=84=E4=BA=A7?= =?UTF-8?q?=E5=93=81=E9=A1=B5=E9=9D=A2=E5=B1=95=E7=A4=BA=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=9C=8D=E5=8A=A1=E4=BA=A7=E5=93=81=E7=9A=84=E5=B7=A5?= =?UTF-8?q?=E8=89=BA=E5=8F=82=E6=95=B0=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=BD=93?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=B1=BB=E5=88=AB=E4=B8=BA=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=AF=A5=E5=AD=97=E6=AE=B5=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=EF=BC=8C=E6=9D=90=E6=96=99=E5=92=8C=E5=9E=8B?= =?UTF-8?q?=E5=8F=B7=E9=9A=90=E8=97=8F=EF=BC=9B=E5=8A=A0=E5=B7=A5=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E9=87=8C=E7=9A=84=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=AD=97=E6=AE=B5=E7=9A=84=E5=80=BC=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=B8=BA=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA+?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E5=8F=82=E6=95=B0=202.=E4=BF=AE=E5=A4=8Dsf?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA=E5=B7=A5=E5=8D=95?= =?UTF-8?q?=E5=8F=8A=E5=AE=8C=E6=88=90=E5=90=8E=E7=9A=84=E8=AF=A2=E4=BB=B7?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 9 ++- sf_base/security/ir.model.access.csv | 1 - sf_dlm/data/product_data.xml | 8 +-- sf_dlm/models/product_template.py | 27 +++---- sf_dlm/views/product_template_view.xml | 21 +++--- sf_manufacturing/models/mrp_production.py | 24 ++++--- .../models/mrp_routing_workcenter.py | 2 +- sf_manufacturing/models/mrp_workorder.py | 70 ++++++++++++++++++- 8 files changed, 119 insertions(+), 43 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 758a9950..f741c0ed 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -65,7 +65,6 @@ class MrsProductionProcess(models.Model): category_id = fields.Many2one('sf.production.process.category') # workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True) - class MrsProcessingTechnology(models.Model): _name = 'sf.processing.technology' _description = '加工工艺' @@ -115,6 +114,7 @@ class SupplierSort(models.Model): class MrsProductionProcessParameter(models.Model): _name = 'sf.production.process.parameter' _description = '可选参数' + # _display_name = 'name' code = fields.Char("编码") name = fields.Char('名称') @@ -124,6 +124,13 @@ class MrsProductionProcessParameter(models.Model): materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料') active = fields.Boolean('有效', default=True) + def name_get(self): + result = [] + for parameter in self: + name = parameter.process_id.name + ',' + parameter.name + result.append((parameter.id, name)) + return result + # 获取表面工艺的获取方式 def get_gain_way(self, item): process_parameter = self.env['sf.production.process.parameter'].search([('id', '=', item.id)]) diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 816341ee..7c13d58d 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -13,7 +13,6 @@ access_sf_materials_model,sf_materials_model,model_sf_materials_model,base.group access_sf_processing_technology,sf_processing_technology,model_sf_processing_technology,base.group_user,1,1,1,1 access_sf_tray,sf_tray,model_sf_tray,base.group_user,1,1,1,1 access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,1 - access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,1 access_sf_production_process_category,sf_production_process_category,model_sf_production_process_category,base.group_user,1,1,1,1 diff --git a/sf_dlm/data/product_data.xml b/sf_dlm/data/product_data.xml index 8e01b270..04e16c70 100644 --- a/sf_dlm/data/product_data.xml +++ b/sf_dlm/data/product_data.xml @@ -15,10 +15,10 @@ 原材料 - - - - + + 表面工艺 + 表面工艺 + CNC加工产品模板 diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index d37e2887..3e3bdfb2 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -15,7 +15,8 @@ class ResProductTemplate(models.Model): # 模型的长,宽,高,体积,精度,材料 model_name = fields.Char('模型名称') categ_type = fields.Selection( - [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料")], string='产品的类别', related='categ_id.type', + [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料"), ("表面工艺", "表面工艺"), ("服务", "服务")], + string='产品的类别', related='categ_id.type', store=True) model_long = fields.Float('模型长[mm]', digits=(16, 3)) model_width = fields.Float('模型宽[mm]', digits=(16, 3)) @@ -31,9 +32,11 @@ class ResProductTemplate(models.Model): embryo_model_type_id = fields.Many2one('sf.model.type', string='胚料模型类型') model_processing_panel = fields.Char('模型加工面板') # model_surface_process_category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别') - model_surface_process_ids = fields.Many2many('sf.production.process', 'rel_product_process', string='表面工艺') - model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'rel_product_parameter', - string='工艺参数') + # model_surface_process_ids = fields.Many2many('sf.production.process', 'rel_product_process', string='表面工艺') + server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter', + string='表面工艺参数(服务产品)') + model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', 'process_parameter_rel', + string='表面工艺参数') # model_price = fields.Float('模型单价', digits=(16, 3)) model_remark = fields.Char('模型备注说明') length = fields.Float('长[mm]', digits=(16, 3)) @@ -109,7 +112,7 @@ class ResProductTemplate(models.Model): [('materials_no', '=', item['texture_code'])]).id, 'materials_type_id': self.env['sf.materials.model'].search( [('materials_no', '=', item['texture_type_code'])]).id, - 'model_surface_process_ids': self.get_production_process_id(item['surface_process_code']), + # 'model_surface_process_ids': self.get_production_process_id(item['surface_process_code']), 'model_process_parameters_ids': self.get_process_parameters_id(item['process_parameters_code']), 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), @@ -121,12 +124,12 @@ class ResProductTemplate(models.Model): # product_id.product_tmpl_id.active = False return copy_product_id - def get_production_process_id(self, surface_process_code): - production_process_ids = [] - for item in surface_process_code: - production_process = self.env['sf.production.process'].search([('process_encode', '=', item)]) - production_process_ids.append(production_process.id) - return [(6, 0, production_process_ids)] + # def get_production_process_id(self, surface_process_code): + # production_process_ids = [] + # for item in surface_process_code: + # production_process = self.env['sf.production.process'].search([('process_encode', '=', item)]) + # production_process_ids.append(production_process.id) + # return [(6, 0, production_process_ids)] def get_process_parameters_id(self, process_parameters_code): process_parameters_ids = [] @@ -340,7 +343,7 @@ class ResProductCategory(models.Model): _inherit = "product.category" type = fields.Selection( - [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料")], + [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料"), ("表面工艺", "表面工艺"), ("服务", "服务")], default="", string="类型") # @api.constrains('type') diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index 75345845..8a01ce61 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -22,17 +22,13 @@ - + - - - - - - + domain="[('materials_id', '=', materials_id)]" + attrs="{'invisible': [('categ_type', '=', '表面工艺')]}"/> + @@ -73,8 +69,9 @@ - - + +
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index d027b157..ec4c4e56 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -136,7 +136,7 @@ class MrpProduction(models.Model): route_workcenter_arr = [] for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id) - route_workcenter_arr.append(item.route_workcenter_id) + route_workcenter_arr.append(item.route_workcenter_id.id) if surface_technics_arr: production_process = self.env['sf.production.process.category'].search( [('production_process_ids.id', 'in', surface_technics_arr)], @@ -146,16 +146,18 @@ class MrpProduction(models.Model): for p in production_process: for pitem in p.production_process_ids: if pitem.id in surface_technics_arr: - process_parameter = self.env['sf.production.process.parameter'].search( - [('id', '=', pitem.id)]) - for ritem in route_workcenter_arr: - route_production_process = self.env['mrp.routing.workcenter'].search( - [('surface_technics_id', '=', pitem.id), ('id', '=', ritem)]) - if route_production_process: - workorders_values.append( - self.env['mrp.workorder']._json_workorder_surface_process_str( - production, route_production_process, - process_parameter)) + for param in production.product_id.model_process_parameters_ids: + process_parameter = self.env['sf.production.process.parameter'].search( + [('process_id.id', '=', pitem.id), ('id', '=', param.id)]) + if process_parameter: + for ritem in route_workcenter_arr: + route_production_process = self.env['mrp.routing.workcenter'].search( + [('surface_technics_id', '=', pitem.id), ('id', '=', ritem)]) + if route_production_process: + workorders_values.append( + self.env['mrp.workorder']._json_workorder_surface_process_str( + production, route_production_process, + process_parameter)) elif production.product_id.categ_id.type == '胚料': embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( [('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)], diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index 7f7a98d7..1ab52f61 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -60,7 +60,7 @@ class ResMrpRoutingWorkcenter(models.Model): order by count(*),workcenter_id asc limit 1 """, [tuple(workcenter_ids)]) res = self.env.cr.fetchone() if res: - workcenter_id = self.env.cr.dictfetchall()[0].get('workcenter_id') + workcenter_id = res[0] else: workcenter_id = workcenter_ids[0] return workcenter_id diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 5a049d0d..0efdc981 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -91,6 +91,8 @@ class ResMrpWorkOrder(models.Model): cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工") tray_code = fields.Char(string="托盘") glb_file = fields.Binary("glb模型文件") + is_subcontract = fields.Boolean(string='是否外协') + surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") # 计算配料中心点和与x轴倾斜度方法 def getcenter(self): @@ -163,10 +165,12 @@ class ResMrpWorkOrder(models.Model): 'product_uom_id': production.product_uom_id.id, 'qty_producing': 0, 'operation_id': False, - 'name': route.name, + 'name': '%s-%s' % (route.name, process_parameter.name), 'processing_panel': '', 'routing_type': '表面工艺', + 'surface_technics_parameters_id': process_parameter.id, 'work_state': '', + 'is_subcontract': True if process_parameter.gain_way == '外协' else False, 'workcenter_id': self.env[ 'mrp.workcenter'].get_process_outsourcing_workcenter() if process_parameter.gain_way == '外协' else self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, @@ -465,6 +469,51 @@ class ResMrpWorkOrder(models.Model): else: raise UserError(_('请先完成上一步工单')) + def button_finish(self): + end_date = datetime.now() + for workorder in self: + if workorder.state in ('done', 'cancel'): + continue + workorder.end_all() + vals = { + 'qty_produced': workorder.qty_produced or workorder.qty_producing or workorder.qty_production, + 'state': 'done', + 'date_finished': end_date, + 'date_planned_finished': end_date, + 'costs_hour': workorder.workcenter_id.costs_hour + } + if not workorder.date_start: + vals['date_start'] = end_date + if not workorder.date_planned_start or end_date < workorder.date_planned_start: + vals['date_planned_start'] = end_date + workorder.with_context(bypass_duration_calculation=True).write(vals) + self.env.cr.commit() + finish_workorder_count = self.env['mrp.workorder'].search_count( + [('production_id', '=', workorder.production_id.id), + ('is_subcontract', '=', True)]) + subcontract_workorder_count = self.env['mrp.workorder'].search_count( + [('production_id', '=', workorder.production_id.id), ('is_subcontract', '=', True), + ('state', '=', 'done')]) + if len(finish_workorder_count) == len(subcontract_workorder_count): + subcontract_workorder = self.env['mrp.workorder'].search( + [('production_id', '=', workorder.production_id.id), ('is_subcontract', '=', True), + ('state', '=', 'done')]) + for item in subcontract_workorder: + order_line_ids = [] + server_product = self.env['product.template'].search( + [('server_product_process_parameters_id', '=', item.surface_technics_parameters_id.id), + ('categ_type', '=', '服务'), ('detailed_type', '=', 'service')]) + order_line_ids.append((0, 0, { + 'product_id': server_product.id, + 'product_qty': 1, + 'product_uom': server_product.uom_id.id + })) + self.env['purchase.order'].create({ + 'partner_id': server_product.seller_ids[0].id, + 'state': 'draft', + 'order_line': order_line_ids, + }) + class CNCprocessing(models.Model): _name = 'sf.cnc.processing' @@ -569,6 +618,25 @@ class CNCprocessing(models.Model): else: return False + # end_date = datetime.now() + # for workorder in self: + # if workorder.state in ('done', 'cancel'): + # continue + # workorder.end_all() + # vals = { + # 'qty_produced': workorder.qty_produced or workorder.qty_producing or workorder.qty_production, + # 'state': 'done', + # 'date_finished': end_date, + # 'date_planned_finished': end_date, + # 'costs_hour': workorder.workcenter_id.costs_hour + # } + # if not workorder.date_start: + # vals['date_start'] = end_date + # if not workorder.date_planned_start or end_date < workorder.date_planned_start: + # vals['date_planned_start'] = end_date + # workorder.with_context(bypass_duration_calculation=True).write(vals) + return True + class SfWorkOrderBarcodes(models.Model): """ From d80b4b616987dcee26c28effc00f67bbb1a925bc Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 12 Apr 2023 17:33:15 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E4=BD=8D=E7=BD=AE=EF=BC=8C=E5=A4=96?= =?UTF-8?q?=E5=8D=8F=E5=87=BA=E5=BA=93=EF=BC=8C=E5=A4=96=E5=8D=8F=E5=85=A5?= =?UTF-8?q?=E5=BA=93=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/__manifest__.py | 3 ++- sf_manufacturing/data/stock_data.xml | 35 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 sf_manufacturing/data/stock_data.xml diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 2db63e1b..2f181b42 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -10,8 +10,9 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['mrp', 'sf_base', 'maintenance', 'web_widget_model_viewer'], + 'depends': ['mrp', 'sf_base', 'maintenance', 'web_widget_model_viewer', 'stock'], 'data': [ + 'data/stock_data.xml', 'security/group_security.xml', 'security/ir.model.access.csv', 'report/tray_report.xml', diff --git a/sf_manufacturing/data/stock_data.xml b/sf_manufacturing/data/stock_data.xml new file mode 100644 index 00000000..5253db20 --- /dev/null +++ b/sf_manufacturing/data/stock_data.xml @@ -0,0 +1,35 @@ + + + + + 外协 + + internal + VL-OC + true + + + + + 外协入库 + internal + true + + OCIN + + + + + + 外协出库 + internal + true + + OCOUT + + + + + From a5c707bf433095c66e4ff25b48279c2534737b6c Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Fri, 14 Apr 2023 17:54:20 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=20=E5=88=A4=E6=96=AD=E5=A4=96=E5=8D=8F?= =?UTF-8?q?=E5=B7=A5=E5=BA=8F=E6=98=AF=E5=90=A6=E8=BF=9E=E7=BB=AD=E6=9C=89?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E5=A4=96=E5=8D=8F=E5=B7=A5=E5=BA=8F=E4=B8=BA?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E4=B8=AA=E4=BE=9B=E5=BA=94=E5=95=86=EF=BC=88?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E4=B8=BA=E8=A1=A8=E9=9D=A2=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=9A=84=E4=BE=9B=E5=BA=94=E5=95=86=EF=BC=89?= =?UTF-8?q?,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 3 +- sf_dlm/models/product_template.py | 2 +- sf_dlm/views/product_template_view.xml | 2 +- sf_manufacturing/models/mrp_production.py | 23 +++++++- sf_manufacturing/models/mrp_workorder.py | 44 ++++++++------- sf_manufacturing/models/stock.py | 53 ++++++++----------- sf_manufacturing/views/mrp_workorder_view.xml | 9 ++-- sf_manufacturing/views/stock_picking_view.xml | 12 +++++ 8 files changed, 89 insertions(+), 59 deletions(-) create mode 100644 sf_manufacturing/views/stock_picking_view.xml diff --git a/sf_base/models/common.py b/sf_base/models/common.py index f741c0ed..ff7262e3 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -119,6 +119,7 @@ class MrsProductionProcessParameter(models.Model): code = fields.Char("编码") name = fields.Char('名称') gain_way = fields.Selection([("自加工", "自加工"), ("外协", "外协")], default="", string="获取方式") + is_check = fields.Boolean(default=True) # price = fields.Float('单价') process_id = fields.Many2one('sf.production.process', string='表面工艺') materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料') @@ -127,7 +128,7 @@ class MrsProductionProcessParameter(models.Model): def name_get(self): result = [] for parameter in self: - name = parameter.process_id.name + ',' + parameter.name + name = parameter.process_id.name + '-' + parameter.name result.append((parameter.id, name)) return result diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index 3e3bdfb2..1b6539df 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -15,7 +15,7 @@ class ResProductTemplate(models.Model): # 模型的长,宽,高,体积,精度,材料 model_name = fields.Char('模型名称') categ_type = fields.Selection( - [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料"), ("表面工艺", "表面工艺"), ("服务", "服务")], + [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料"), ("表面工艺", "表面工艺")], string='产品的类别', related='categ_id.type', store=True) model_long = fields.Float('模型长[mm]', digits=(16, 3)) diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index 8a01ce61..c071f40b 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -28,7 +28,7 @@ attrs="{'invisible': [('categ_type', '=', '表面工艺')]}"/> + attrs="{'invisible': ['|',('categ_type', '!=', '表面工艺'),('categ_type', '=', False)]}"/> diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index ec4c4e56..75dfae84 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -132,7 +132,7 @@ class MrpProduction(models.Model): # 表面工艺工序 # 获取表面工艺id surface_technics_arr = [] - #工序id + # 工序id route_workcenter_arr = [] for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id) @@ -149,6 +149,9 @@ class MrpProduction(models.Model): for param in production.product_id.model_process_parameters_ids: process_parameter = self.env['sf.production.process.parameter'].search( [('process_id.id', '=', pitem.id), ('id', '=', param.id)]) + # 产品为表面工艺服务的供应商 + product_production_process = self.env['product.template'].search( + [('server_product_process_parameters_id', '=', process_parameter.id)]) if process_parameter: for ritem in route_workcenter_arr: route_production_process = self.env['mrp.routing.workcenter'].search( @@ -157,7 +160,8 @@ class MrpProduction(models.Model): workorders_values.append( self.env['mrp.workorder']._json_workorder_surface_process_str( production, route_production_process, - process_parameter)) + process_parameter, + product_production_process.seller_ids[0].id)) elif production.product_id.categ_id.type == '胚料': embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( [('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)], @@ -167,8 +171,23 @@ class MrpProduction(models.Model): workorders_values.append( self.env['mrp.workorder'].json_workorder_str('', production, route)) production.workorder_ids = workorders_values + process_parameter_workorder = self.env['mrp.workorder'].search( + [('surface_technics_parameters_id', '!=', False), ('production_id', '=', 58)]) + if process_parameter_workorder: + + # for st in process_parameter_workorder: + consecutive_workorders = [] + sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id) + for i in range(len(sorted_workorders) - 1): + if sorted_workorders[i].supplier_id == sorted_workorders[i + 1].supplier_id and \ + sorted_workorders[i].id == sorted_workorders[i + 1].id - 1: + consecutive_workorders.append(sorted_workorders[i]) + consecutive_workorders.append(sorted_workorders[i + 1]) for workorder in production.workorder_ids: workorder.duration_expected = workorder._get_duration_expected() + # 判断外协工序是否连续有多个外协工序为同一个供应商(产品为表面工艺服务的供应商), + # 如果有的话,则将连续的多个外协工序(ID),绑定同一张外协出入库单,单独的供应商工序则生成单独的外协出入库单 + # 如果没有连续的外协工序为同一个供应商,则根据规则生成多张外协出入库单,并绑定不同的工序ID # 在之前的销售单上重新生成制造订单 def create_production1_values(self, production): diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 0efdc981..5c3fdf38 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -93,6 +93,9 @@ class ResMrpWorkOrder(models.Model): glb_file = fields.Binary("glb模型文件") is_subcontract = fields.Boolean(string='是否外协') surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") + stock_picking_in_ids = fields.One2many('stock.picking', 'workorder_in_id',string='库存外协入库单') + stock_picking_out_ids = fields.One2many('stock.picking', 'workorder_out_id', string='库存外协出库单') + supplier_id = fields.Integer('供应商Id') # 计算配料中心点和与x轴倾斜度方法 def getcenter(self): @@ -160,7 +163,7 @@ class ResMrpWorkOrder(models.Model): return workorders_values_str # 拼接工单对象属性值(表面工艺) - def _json_workorder_surface_process_str(self, production, route, process_parameter): + def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id): workorders_values_str = [0, '', { 'product_uom_id': production.product_uom_id.id, 'qty_producing': 0, @@ -170,6 +173,7 @@ class ResMrpWorkOrder(models.Model): 'routing_type': '表面工艺', 'surface_technics_parameters_id': process_parameter.id, 'work_state': '', + 'supplier_id': supplier_id, 'is_subcontract': True if process_parameter.gain_way == '外协' else False, 'workcenter_id': self.env[ 'mrp.workcenter'].get_process_outsourcing_workcenter() if process_parameter.gain_way == '外协' else @@ -494,25 +498,25 @@ class ResMrpWorkOrder(models.Model): subcontract_workorder_count = self.env['mrp.workorder'].search_count( [('production_id', '=', workorder.production_id.id), ('is_subcontract', '=', True), ('state', '=', 'done')]) - if len(finish_workorder_count) == len(subcontract_workorder_count): - subcontract_workorder = self.env['mrp.workorder'].search( - [('production_id', '=', workorder.production_id.id), ('is_subcontract', '=', True), - ('state', '=', 'done')]) - for item in subcontract_workorder: - order_line_ids = [] - server_product = self.env['product.template'].search( - [('server_product_process_parameters_id', '=', item.surface_technics_parameters_id.id), - ('categ_type', '=', '服务'), ('detailed_type', '=', 'service')]) - order_line_ids.append((0, 0, { - 'product_id': server_product.id, - 'product_qty': 1, - 'product_uom': server_product.uom_id.id - })) - self.env['purchase.order'].create({ - 'partner_id': server_product.seller_ids[0].id, - 'state': 'draft', - 'order_line': order_line_ids, - }) + if finish_workorder_count > 0 and subcontract_workorder_count > 0: + subcontract_workorder = self.env['mrp.workorder'].search( + [('production_id', '=', workorder.production_id.id), ('is_subcontract', '=', True), + ('state', '=', 'done')]) + for item in subcontract_workorder: + order_line_ids = [] + server_product = self.env['product.template'].search( + [('server_product_process_parameters_id', '=', item.surface_technics_parameters_id.id), + ('categ_type', '=', '服务'), ('detailed_type', '=', 'service')]) + order_line_ids.append((0, 0, { + 'product_id': server_product.product_variant_id.id, + 'product_qty': 1, + 'product_uom': server_product.uom_id.id + })) + self.env['purchase.order'].create({ + 'partner_id': server_product.seller_ids.partner_id.id, + 'state': 'draft', + 'order_line': order_line_ids, + }) class CNCprocessing(models.Model): diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index ef1805eb..767b8a1d 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -3,8 +3,9 @@ from collections import defaultdict, namedtuple from odoo.addons.stock.models.stock_rule import ProcurementException from re import findall as regex_findall from re import split as regex_split -from odoo import SUPERUSER_ID, _, api, models +from odoo import SUPERUSER_ID, _, api, fields,models from odoo.tools import float_compare + from odoo.exceptions import UserError @@ -229,36 +230,29 @@ class ProductionLot(models.Model): return "%s-%03d" % (product.name, 1) +class ResStockPicking(models.Model): + _inherit = 'stock.picking' + + workorder_in_id = fields.Many2one('mrp.workorder') + workorder_out_id = fields.Many2one('mrp.workorder') + + class ResPurchaseOrder(models.Model): _inherit = 'purchase.order' - # def button_approve(self, force=False): - # result = super().button_approve(force=force) - # self._create_picking_RES() - # return result + # 外协出库、入库单 + def _prepare_picking_outcontract(self, sequence_code): + # if not self.group_id: + # self.group_id = self.group_id.create({ + # 'name': self.name, + # 'partner_id': self.partner_id.id + # }) + # if not self.partner_id.property_stock_supplier.id: + # raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) - # @api.depends('order_line.move_ids') - # def _compute_subcontracting_resupply_picking_count(self): - # for purchase in self: - # purchase.subcontracting_resupply_picking_count = len(purchase._get_subcontracting_resupplies_new()) - # - # def _get_subcontracting_resupplies_new(self): - # moves_subcontracted = self.order_line.move_ids.filtered(lambda m: m.is_subcontract) - # # subcontracted_productions = moves_subcontracted.move_orig_ids.production_id - # return moves_subcontracted.picking_id - - def _prepare_picking_RES(self): - if not self.group_id: - self.group_id = self.group_id.create({ - 'name': self.name, - 'partner_id': self.partner_id.id - }) - if not self.partner_id.property_stock_supplier.id: - raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) - picking_type_id_res = self.env['stock.picking.type'].search( - [('sequence_code', '=', 'RES'), ('barcode', '=', 'WH-RESUPPLY')]) + picking_type_id_oc = self.env['stock.picking.type'].search([('sequence_code', '=', sequence_code)]) return { - 'picking_type_id': picking_type_id_res.id if picking_type_id_res else self.picking_type_id.id, + 'picking_type_id': picking_type_id_oc.id if picking_type_id_oc else self.picking_type_id.id, 'partner_id': self.partner_id.id, 'user_id': False, 'date': self.date_order, @@ -268,17 +262,14 @@ class ResPurchaseOrder(models.Model): 'company_id': self.company_id.id, } - def _create_picking(self): + def _create_picking_outcontract(self): StockPicking = self.env['stock.picking'] for order in self.filtered(lambda po: po.state in ('purchase', 'done')): if any(product.type in ['product', 'consu'] for product in order.order_line.product_id): order = order.with_company(order.company_id) pickings = order.picking_ids.filtered(lambda x: x.state not in ('done', 'cancel')) if not pickings: - if order.order_line.product_id.categ_type == '胚料': - res = order._prepare_picking_RES() - else: - res = order._prepare_picking() + res = order._prepare_picking_outcontract() picking = StockPicking.with_user(SUPERUSER_ID).create(res) pickings = picking else: diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 702e9f9e..6c97ec0f 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -5,6 +5,10 @@ mrp.workorder + + + + @@ -113,8 +117,7 @@ ('is_user_working', '!=', False),('user_permissions','=',False),('name','=','获取CNC加工程序')]}"/>