from odoo import models, fields, api from odoo.exceptions import ValidationError from odoo.modules import get_resource_path from odoo.addons.sf_base.commons.common import Common # from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import write_stl_file import logging import base64 import hashlib import os import requests import json class ResProductMo(models.Model): _inherit = 'product.template' model_file = fields.Binary('模型文件') # categ_type = fields.Selection( # [("成品", "成品"), ("坯料", "坯料"), ("原材料", "原材料"), ("表面工艺", "表面工艺"), ("刀具", "刀具"), # ("夹具", "夹具")], # string='产品的类别', compute='_compute_categ_id', # store=True) # # @api.depends('categ_id') # def _compute_categ_id(self): # for record in self: # if record: # record.categ_type = record.categ_id.type categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True) model_name = fields.Char('模型名称') model_long = fields.Float('模型长(mm)', digits=(16, 3)) model_width = fields.Float('模型宽(mm)', digits=(16, 3)) model_height = fields.Float('模型高(mm)', digits=(16, 3)) model_volume = fields.Float('模型体积(m³)') model_machining_precision = fields.Selection([ ('0.10', '±0.10mm'), ('0.05', '±0.05mm'), ('0.03', '±0.03mm'), ('0.02', '±0.02mm'), ('0.01', '±0.01mm')], string='加工精度') model_processing_panel = fields.Char('模型加工面板') model_remark = fields.Char('模型备注说明') length = fields.Float('长(mm)', digits=(16, 3)) width = fields.Float('宽(mm)', digits=(16, 3)) height = fields.Float('高(mm)', digits=(16, 3)) single_manufacturing = fields.Boolean(string="单个制造") model_code = fields.Char('模型编码') is_bfm = fields.Boolean('业务平台是否自动创建', default=False) upload_model_file = fields.Many2many('ir.attachment', 'upload_model_file_attachment_ref', string='上传模型文件') product_model_type_id = fields.Many2one('sf.model.type', string='产品模型类型') embryo_model_type_id = fields.Many2one('sf.model.type', string='坯料模型类型') materials_id = fields.Many2one('sf.production.materials', string='材料') materials_type_id = fields.Many2one('sf.materials.model', 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='表面工艺参数') cutting_tool_material_id = fields.Many2one('sf.cutting.tool.material', string='刀具物料') cutting_tool_type = fields.Char(string="刀具物料类型", related='cutting_tool_material_id.name', store=True) cutting_tool_model_id = fields.Many2one('sf.cutting.tool.model', string='型号', ) cutting_tool_model = fields.Char('型号') cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型', domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") brand_id = fields.Many2one('sf.machine.brand', '品牌') tool_length = fields.Float('长度(mm)') tool_width = fields.Float('宽度(mm)') tool_height = fields.Float('高度(mm)') tool_thickness = fields.Integer('厚度(mm)') tool_weight = fields.Float('重量(kg)') tool_hardness = fields.Integer('硬度(hrc)') coating_material = fields.Char('涂层材质') # 整体式刀具特有字段 cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1)) cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1)) cutting_tool_blade_length = fields.Float('刃部长度(mm)', digits=(6, 1)) cutting_tool_blade_number = fields.Selection( [('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')], '刃数(个)') # 整体式刀具新增字段 cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1)) cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1)) cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1)) cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1)) cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)') cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)') cutting_tool_blade_type = fields.Char('刃部类型') cutting_tool_coarse_medium_fine = fields.Selection([('粗', '粗'), ('中', '中'), ('精', '精')], '粗/中/精') cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1)) cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1)) suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image', 'rel_machining_product_template', '适合加工方式', domain=[('type', '=', '加工能力')]) blade_tip_characteristics_ids = fields.Many2many('maintenance.equipment.image', 'rel_blade_tip_product_template', '刀尖特征', domain=[('type', '=', '刀尖特征')]) handle_type_ids = fields.Many2many('maintenance.equipment.image', 'rel_handle_product_template', '柄部类型', domain=[('type', '=', '柄部类型')]) cutting_direction_ids = fields.Many2many('maintenance.equipment.image', 'rel_cutting_product_template', '走刀方向', domain=[('type', '=', '走刀方向')]) suitable_coolant_ids = fields.Many2many('maintenance.equipment.image', 'rel_coolant_product_template', '适合冷却液', domain=[('type', '=', '冷却液')]) # @api.constrains('suitable_machining_method_ids') # def _check_suitable_machining_method_ids(self): # for record in self: # if len(record.suitable_machining_method_ids) == 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("适合加工方式不能为空!") # # @api.constrains('blade_tip_characteristics_ids') # def _check_blade_tip_characteristics_ids(self): # for record in self: # if len(record.blade_tip_characteristics_ids) == 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("刀尖特征不能为空!") # if len(record.blade_tip_characteristics_ids) > 1 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("刀尖特征只能单选!") # # @api.constrains('handle_type_ids') # def _check_handle_type_ids(self): # for record in self: # if len(record.handle_type_ids) == 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("柄部类型不能为空!") # if len(record.handle_type_ids) > 1 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("柄部类型只能单选!") # # @api.constrains('cutting_direction_ids') # def _check_cutting_direction_ids(self): # for record in self: # if len(record.cutting_direction_ids) == 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("走刀方向不能为空!") # # @api.constrains('suitable_coolant_ids') # def _check_suitable_coolant_ids(self): # for record in self: # if not record.suitable_coolant_ids and self.cutting_tool_type == '整体式刀具': # raise ValidationError("适合冷却液不能为空!") # # @api.constrains('cutting_tool_total_length') # def _check_cutting_tool_total_length(self): # if self.cutting_tool_total_length <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("总长度不能为0") # # @api.constrains('cutting_tool_shank_length') # def _check_cutting_tool_shank_length(self): # if self.cutting_tool_shank_length <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("柄部长度不能为0") # # @api.constrains('cutting_tool_blade_length') # def _check_cutting_tool_blade_length(self): # if self.cutting_tool_blade_length <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("刃部长度不能为0") # # @api.constrains('cutting_tool_blade_number') # def _check_cutting_tool_blade_number(self): # if self.cutting_tool_blade_number <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("刃数不能为0") # # @api.constrains('integral_shank_diameter') # def _check_integral_shank_diameter(self): # if self.integral_shank_diameter <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("柄部直径不能为0") # # @api.constrains('integral_blade_diameter') # def _check_integral_blade_diameter(self): # if self.integral_blade_diameter <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("刃部直径不能为0") # # @api.constrains('integral_run_out_accuracy_min') # def _check_integral_blade_diameter(self): # if self.integral_run_out_accuracy_min <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("端跳精度最小(min)不能为0") # cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc') # feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz') # @api.constrains('suitable_machining_method_ids') # def _check_suitable_machining_method_ids(self): # for record in self: # if len(record.suitable_machining_method_ids) == 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("适合加工方式不能为空!") # @api.constrains('integral_run_out_accuracy_max') # def _check_integral_run_out_accuracy_max(self): # if self.integral_run_out_accuracy_max <= 0 and self.cutting_tool_type == '整体式刀具': # raise ValidationError("端跳精度最大(max)不能为0") cutting_tool_diameter = fields.Float('直径(mm)') cutting_tool_front_angle = fields.Integer('前角(°)') cutting_tool_rear_angle = fields.Integer('后角(°)') cutting_tool_main_included_angle = fields.Integer('主偏角(°)') # cutting_tool_material_model_id = fields.Many2one('sf.materials.model', '材料型号') cutting_tool_nut = fields.Float('配对螺母(mm)') # 适用夹头型号可以多选 cutting_tool_chuck_ids = fields.Many2many( 'sf.cutting.tool.model', relation='product_cutting_tool_model_handle_chuck_rel', column1='model_id_1', column2='model_id_2', domain="[('cutting_tool_type', '=', '夹头')]", string='适用夹头型号') # 刀片参数 cutting_tool_top_angle = fields.Integer('顶角(°)') cutting_tool_jump_accuracy = fields.Float('径跳精度(mm)') cutting_tool_working_hardness = fields.Char('加工硬度(hrc)') cutting_tool_cutter_bar_ids = fields.Many2many( 'sf.cutting.tool.model', relation='product_cutting_tool_model_blade_cutter_bar_rel', column1='model_id_1', column2='model_id_2', domain="[('cutting_tool_type', '=', '刀杆')]", string='适用刀杆型号' ) cutting_tool_cutter_pad_ids = fields.Many2many( 'sf.cutting.tool.model', relation='product_cutting_tool_model_blade_cutter_pad_rel', column1='model_id_1', column2='model_id_2', domain="[('cutting_tool_type', '=', '刀盘')]", string='适用刀盘型号' # 使用空列表作为默认值 ) # 刀杆/参数 cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)') cutting_tool_blade_ids = fields.Many2many( 'sf.cutting.tool.model', relation='product_cutting_tool_model_pad_blade_rel', column1='model_id_1', column2='model_id_2', domain="[('cutting_tool_type', '=', '刀片')]", string='适用刀片型号' # 使用空列表作为默认值 ) cutting_tool_wrench = fields.Float('配对扳手(mm)') # cutting_tool_screw = fields.Float('配备螺丝(mm)') cutting_tool_accuracy_level = fields.Char('精度等级') # 刀柄参数 cutting_tool_head_diameter = fields.Float('头部直径') cutting_tool_diameter_max = fields.Float('最大直径(mm)') cutting_tool_clamping_diameter = fields.Float('夹持直径(mm)') cutting_tool_clamping_length = fields.Float('夹持长度(mm)') cutting_tool_clamping_tolerance = fields.Float('夹持公差(mm)') cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径') cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径') cutting_tool_flange_length = fields.Float('法兰柄长(mm)') cutting_tool_flange_diameter = fields.Float('法兰直径(mm)') cutting_tool_is_rough_finish = fields.Boolean('可粗加工', default=False) cutting_tool_is_finish = fields.Boolean('可精加工', default=False) cutting_tool_is_drill_hole = fields.Boolean('可钻孔', default=False) cutting_tool_is_safety_lock = fields.Boolean('安全锁', default=False) cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False) cutting_tool_dynamic_balance_class = fields.Char('动平衡等级') cutting_tool_change_time = fields.Integer('换刀时间(s)') cutting_tool_clamping_way = fields.Char('夹持方式') cutting_tool_standard_speed = fields.Integer('标准转速(n/min)') cutting_tool_speed_max = fields.Integer('最大转速(n/min)') cutting_tool_cooling_type = fields.Char('冷却类型') cutting_tool_body_accuracy = fields.Float('本体精度(mm)') apply_lock_nut_model = fields.Char('适用锁紧螺母型号') apply_lock_wrench_model = fields.Char('适用锁紧扳手型号') cutting_tool_detection_accuracy_max = fields.Float('最大检测精度(mm)') cutting_tool_detection_accuracy_min = fields.Float('最小检测精度(mm)') # 夹头参数 cutting_tool_taper = fields.Integer('锥度(°)') cutting_tool_outer_diameter = fields.Float('外径(mm)') cutting_tool_inner_diameter = fields.Float('内径(mm)') cooling_suit_type_ids = fields.Char('适用冷却套型号') # cooling_suit_type_ids = fields.Many2many('冷却类型') cutting_tool_er_size_model = fields.Char('ER尺寸型号') # cutting_tool_handle_ids = fields.Many2many( # 'sf.cutting.tool.model', # relation='product_cutting_tool_model_chuck_handle_rel', # column1='model_id_1', # column2='model_id_2', # domain="[('cutting_tool_type', '=', '刀柄')]", # string='适用刀柄型号' # ) # 夹具参数 fixture_material_id = fields.Many2one('sf.fixture.material', string="夹具物料") fixture_model_id = fields.Many2one('sf.fixture.model', string="夹具型号") fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name') fixture_multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型") fixture_clamping_way = fields.Char(string="装夹方式") fixture_port_type = fields.Char(string="接口类型") fixture_model_file = fields.Binary(string="3D模型图") fixture_clamp_workpiece_length_max = fields.Integer(string="夹持工件长度max(mm)") fixture_clamp_workpiece_width_max = fields.Integer(string="夹持工件宽度max(mm)") fixture_clamp_workpiece_height_max = fields.Integer(string="夹持工件高度max(mm)") fixture_clamp_workpiece_diameter_max = fields.Float(string="夹持工件直径max(mm)", digits=(16, 6)) fixture_maximum_carrying_weight = fields.Float(string="最大承载重量(kg)", digits=(16, 4)) fixture_maximum_clamping_force = fields.Integer(string="最大夹持力(n)") fixture_driving_way = fields.Char(string="驱动方式") fixture_apply_machine_tool_type_ids = fields.Many2many('sf.machine_tool.type', 'rel_product_machine_tool_type', string="适用机床型号") fixture_through_hole_size = fields.Integer(string="过孔大小(mm)") fixture_screw_size = fields.Integer(string="螺牙大小(mm)") # 注册状态 register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')], string='注册状态', default='未注册') industry_code = fields.Char('行业编码', readonly=True) @api.constrains('tool_length') def _check_tool_length_size(self): if self.tool_length > 1000000: raise ValidationError("长度不能超过1000000") @api.constrains('tool_width') def _check_tool_width_size(self): if self.tool_width > 1000000: raise ValidationError("宽度不能超过1000000") @api.constrains('tool_height') def _check_tool_height_size(self): if self.tool_height > 1000000: raise ValidationError("高度不能超过1000000") @api.constrains('tool_thickness') def _check_tool_thickness_size(self): if self.tool_thickness > 1000000: raise ValidationError("厚度不能超过1000000") @api.constrains('fixture_clamp_workpiece_length_max') def _check_fixture_clamp_workpiece_length_max_size(self): if self.fixture_clamp_workpiece_length_max > 1000000: raise ValidationError("夹持工件长度MAX不能超过1000000") @api.constrains('fixture_clamp_workpiece_width_max') def _check_fixture_clamp_workpiece_width_max_size(self): if self.fixture_clamp_workpiece_width_max > 1000000: raise ValidationError("夹持工件宽度MAX不能超过1000000") @api.constrains('fixture_clamp_workpiece_height_max') def _check_fixture_clamp_workpiece_height_max_size(self): if self.fixture_clamp_workpiece_height_max > 1000000: raise ValidationError("夹持工件高度MAX不能超过1000000") @api.constrains('fixture_maximum_clamping_force') def _check_fixture_maximum_clamping_force_size(self): if self.fixture_maximum_clamping_force > 100000000: raise ValidationError("最大夹持力不能超过100000000") @api.constrains('fixture_through_hole_size') def _check_fixture_through_hole_size_size(self): if self.fixture_through_hole_size > 1000000: raise ValidationError("过孔大小不能超过1000000") @api.constrains('fixture_screw_size') def _check_fixture_through_hole_size_size(self): if self.fixture_screw_size > 1000000: raise ValidationError("螺牙大小不能超过1000000") def _json_apply_machine_tool_type_item_code(self, item): code_arr = [] for i in item.product_id.fixture_apply_machine_tool_type_ids: code_arr.append(i.code) return code_arr def _json_chuck_item_code(self, item): code_arr = [] for i in item.product_id.cutting_tool_chuck_ids: code_arr.append(i.code) return code_arr def _json_cutter_bar_item_code(self, item): code_arr = [] for i in item.product_id.cutting_tool_cutter_bar_ids: code_arr.append(i.code) return code_arr def _json_cutter_pad_item_code(self, item): code_arr = [] for i in item.product_id.cutting_tool_cutter_pad_ids: code_arr.append(i.code) return code_arr def _json_blade_item_code(self, item): code_arr = [] for i in item.product_id.cutting_tool_blade_ids: code_arr.append(i.code) return code_arr def _json_handle_item_code(self, item): code_arr = [] for i in item.product_id.cutting_tool_handle_ids: code_arr.append(i.code) return code_arr def _get_ids(self, param): type_ids = [] if not param: return [] for item in param: type_ids.append(item.id) return [(6, 0, type_ids)] @api.onchange('categ_id') def _onchange_categ_id(self): if self.categ_type in ('刀具', '夹具'): self.invoice_policy = 'delivery' self.detailed_type = 'product' self.sale_ok = False @api.onchange('cutting_tool_material_id') def _onchange_cutting_tool_material_id(self): if self.cutting_tool_material_id: try: config = self.env['res.config.settings'].get_values() headers = Common.get_headers(self, config['token'], config['sf_secret_key']) url = config['sf_url'] + '/api/cutting_model/list' res = {'token': config['token'], 'cutting_tool_material_code': self.cutting_tool_material_id.code} result = requests.post(url, json={}, data=res, headers=headers) result = result.json() if result['status'] == 1: data = result['data'] model_ids = [] for item in data: model_ids.append((0, 0, { 'name': item['name'] })) self.cutting_tool_model = model_ids return {} except Exception as e: logging.info("获取刀具标准库失败") @api.depends('cutting_tool_material_id') def _get_cutting_tool_model(self): try: config = self.env['res.config.settings'].get_values() headers = Common.get_headers(self, config['token'], config['sf_secret_key']) url = config['sf_url'] + '/api/cutting_model/list' res = {'token': config['token'], 'cutting_tool_material_code': self.cutting_tool_material_id.code} result = requests.post(url, json=res, data=None, headers=headers) cutting_model_data = result.json() if result['state'] == 1: return {'cutting_model_data': cutting_model_data} except Exception as e: logging.info("获取刀具标准库失败") @api.onchange('fixture_material_id') def _onchange_fixture_material_id(self): for item in self: if item.fixture_material_id.id != item.fixture_model_id.fixture_material_id.id: item.fixture_model_id = False @api.onchange('fixture_model_id') def _onchange_fixture_model_id(self): for item in self: if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具', '虎钳夹具', '零点卡盘']: item.brand_id = item.fixture_model_id.brand_id.id item.fixture_multi_mounting_type_id = item.fixture_model_id.multi_mounting_type_id.id item.fixture_model_file = item.fixture_model_id.model_file item.tool_length = item.fixture_model_id.length item.tool_width = item.fixture_model_id.width item.tool_height = item.fixture_model_id.height item.tool_weight = item.fixture_model_id.weight item.materials_type_id = item.fixture_model_id.materials_model_id.id item.fixture_maximum_carrying_weight = item.fixture_model_id.maximum_carrying_weight item.fixture_maximum_clamping_force = item.fixture_model_id.maximum_clamping_force if self.fixture_material_type in ['零点卡盘', '转接板(锁板)夹具']: item.fixture_clamping_way = item.fixture_model_id.clamping_way item.fixture_port_type = item.fixture_model_id.port_type if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具']: item.fixture_driving_way = item.fixture_model_id.driving_way if self.fixture_material_type in ['气动夹具', '磁吸夹具', '虎钳夹具', '零点卡盘']: item.fixture_through_hole_size = item.fixture_model_id.through_hole_size item.fixture_screw_size = item.fixture_model_id.screw_size if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具', '虎钳夹具']: item.fixture_clamp_workpiece_length_max = item.fixture_model_id.clamp_workpiece_length_max item.fixture_clamp_workpiece_width_max = item.fixture_model_id.clamp_workpiece_width_max item.fixture_clamp_workpiece_height_max = item.fixture_model_id.clamp_workpiece_height_max item.fixture_clamp_workpiece_diameter_max = item.fixture_model_id.clamp_workpiece_diameter_max item.fixture_apply_machine_tool_type_ids = self._get_ids( item.fixture_model_id.apply_machine_tool_type_ids) # @api.onchange('cutting_tool_model_id') # def _onchange_cutting_tool_model_id(self): # for item in self: # if self.cutting_tool_type is not False: # item.brand_id = item.cutting_tool_model_id.brand_id.id # item.cutting_tool_type_id = item.cutting_tool_model_id.cutting_tool_type_id.id # item.tool_length = item.cutting_tool_model_id.tool_length # item.tool_width = item.cutting_tool_model_id.tool_width # item.tool_height = item.cutting_tool_model_id.tool_height # item.tool_thickness = item.cutting_tool_model_id.tool_thickness # item.tool_weight = item.cutting_tool_model_id.tool_weight # item.coating_material = item.cutting_tool_model_id.coating_material # item.cutting_tool_total_length = item.cutting_tool_model_id.total_length # item.cutting_tool_shank_length = item.cutting_tool_model_id.shank_length # item.cutting_tool_neck_length = item.cutting_tool_model_id.cutting_tool_neck_length # item.cutting_tool_shank_diameter = item.cutting_tool_model_id.cutting_tool_shank_diameter # item.cutting_tool_blade_diameter = item.cutting_tool_model_id.cutting_tool_blade_diameter # item.cutting_tool_neck_diameter = item.cutting_tool_model_id.cutting_tool_neck_diameter # item.cutting_tool_blade_tip_diameter = item.cutting_tool_model_id.cutting_tool_blade_tip_diameter # item.cutting_tool_blade_tip_taper = item.cutting_tool_model_id.cutting_tool_blade_tip_taper # item.cutting_tool_blade_helix_angle = item.cutting_tool_model_id.cutting_tool_blade_helix_angle # item.cutting_tool_blade_type = item.cutting_tool_model_id.cutting_tool_blade_type # item.cutting_tool_coarse_medium_fine = item.cutting_tool_model_id.cutting_tool_coarse_medium_fine # item.tool_hardness = item.cutting_tool_model_id.tool_hardness # item.cutting_tool_run_out_accuracy_max = item.cutting_tool_model_id.cutting_tool_run_out_accuracy_max # item.cutting_tool_run_out_accuracy_min = item.cutting_tool_model_id.cutting_tool_run_out_accuracy_min # item.suitable_machining_method_ids = self._get_ids( # item.cutting_tool_model_id.suitable_machining_method_ids) # item.blade_tip_characteristics_ids = self._get_ids( # item.cutting_tool_model_id.blade_tip_characteristics_ids) # item.handle_type_ids = self._get_ids(item.cutting_tool_model_id.handle_type_ids) # item.cutting_direction_ids = self._get_ids(item.cutting_tool_model_id.cutting_direction_ids) # item.suitable_coolant_ids = self._get_ids(item.cutting_tool_model_id.suitable_coolant_ids) # item.cutting_tool_diameter = item.cutting_tool_model_id.diameter # item.cutting_tool_blade_number = item.cutting_tool_model_id.blade_number # item.cutting_tool_front_angle = item.cutting_tool_model_id.front_angle # item.cutting_tool_rear_angle = item.cutting_tool_model_id.rear_angle # item.cutting_tool_main_included_angle = item.cutting_tool_model_id.main_included_angle # item.materials_type_id = item.cutting_tool_model_id.material_model_id.id # item.cutting_tool_nut = item.cutting_tool_model_id.nut # item.cutting_tool_top_angle = item.cutting_tool_model_id.top_angle # item.cutting_tool_jump_accuracy = item.cutting_tool_model_id.jump_accuracy # item.cutting_tool_working_hardness = item.cutting_tool_model_id.working_hardness # item.cutting_tool_blade_diameter = item.cutting_tool_model_id.blade_diameter # item.cutting_tool_wrench = item.cutting_tool_model_id.wrench # # item.cutting_tool_screw = item.cutting_tool_model_id.screw # item.cutting_tool_accuracy_level = item.cutting_tool_model_id.accuracy_level # item.cutting_tool_diameter_max = item.cutting_tool_model_id.diameter_max # item.cutting_tool_clamping_diameter = item.cutting_tool_model_id.clamping_diameter # item.cutting_tool_flange_length = item.cutting_tool_model_id.flange_length # item.cutting_tool_flange_diameter = item.cutting_tool_model_id.flange_diameter # item.cutting_tool_outer_diameter = item.cutting_tool_model_id.outer_diameter # item.cutting_tool_inner_diameter = item.cutting_tool_model_id.inner_diameter # item.cutting_tool_chuck_ids = self._get_ids(item.cutting_tool_model_id.chuck_ids) # item.cutting_tool_cutter_bar_ids = self._get_ids(item.cutting_tool_model_id.cutter_bar_ids) # item.cutting_tool_cutter_pad_ids = self._get_ids(item.cutting_tool_model_id.cutter_pad_ids) # item.cutting_tool_blade_ids = self._get_ids(item.cutting_tool_model_id.blade_ids) # item.cutting_tool_handle_ids = self._get_ids(item.cutting_tool_model_id.handle_ids) # else: # item.brand_id = False # item.cutting_tool_type_id = False # item.brand_id = False # item.tool_length = False # item.tool_width = False # item.tool_height = False # item.tool_thickness = False # item.tool_weight = False # item.coating_material = False # item.cutting_tool_total_length = False # item.cutting_tool_shank_length = False # item.cutting_tool_blade_length = False # item.cutting_tool_neck_length = False # item.cutting_tool_shank_diameter = False # item.cutting_tool_blade_diameter = False # item.cutting_tool_neck_diameter = False # item.cutting_tool_blade_tip_diameter = False # item.cutting_tool_blade_tip_taper = False # item.cutting_tool_blade_helix_angle = False # item.cutting_tool_blade_type = False # item.cutting_tool_coarse_medium_fine = False # item.tool_hardness = False # item.cutting_tool_run_out_accuracy_max = False # item.cutting_tool_run_out_accuracy_min = False # item.suitable_machining_method_ids = False # item.blade_tip_characteristics_ids = False # item.handle_type_ids = False # item.cutting_direction_ids = False # item.suitable_coolant_ids = False # item.cutting_tool_diameter = False # item.cutting_tool_blade_number = False # item.cutting_tool_front_angle = False # item.cutting_tool_rear_angle = False # item.cutting_tool_main_included_angle = False # item.materials_type_id = False # item.cutting_tool_nut = False # item.cutting_tool_top_angle = False # item.cutting_tool_jump_accuracy = False # item.cutting_tool_working_hardness = False # item.cutting_tool_blade_diameter = False # item.cutting_tool_wrench = False # # item.cutting_tool_screw = False # item.cutting_tool_accuracy_level = False # item.cutting_tool_diameter_max = False # item.cutting_tool_clamping_diameter = False # item.cutting_tool_flange_length = False # item.cutting_tool_flange_diameter = False # item.cutting_tool_outer_diameter = False # item.cutting_tool_inner_diameter = False # item.cutting_tool_chuck_ids = False # item.cutting_tool_cutter_bar_ids = False # item.cutting_tool_cutter_pad_ids = False # item.cutting_tool_blade_ids = False # item.cutting_tool_handle_ids = False def _get_volume_uom_id_from_ir_config_parameter(self): product_length_in_feet_param = self.env['ir.config_parameter'].sudo().get_param('product.volume_in_cubic_feet') if product_length_in_feet_param == '1': return self.env.ref('uom.product_uom_cubic_foot') else: return self.env.ref('sf_dlm.product_uom_cubic_millimeter') # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 def product_create(self, product_id, item, order_id, order_number, i): copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy() copy_product_id.product_tmpl_id.active = True model_type = self.env['sf.model.type'].search([], limit=1) attachment = self.attachment_create(item['model_name'], item['model_data']) vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), 'model_long': item['model_long'] + model_type.embryo_tolerance, 'model_width': item['model_width'] + model_type.embryo_tolerance, 'model_height': item['model_height'] + model_type.embryo_tolerance, 'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( item['model_width'] + model_type.embryo_tolerance) * ( item['model_height'] + model_type.embryo_tolerance), 'product_model_type_id': model_type.id, 'model_processing_panel': 'R', 'model_machining_precision': item['model_machining_precision'], 'model_code': item['barcode'], 'length': item['model_long'], 'width': item['model_width'], 'height': item['model_height'], 'volume': item['model_long'] * item['model_width'] * item['model_height'], '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'], # 'categ_id': self.env.ref('sf_dlm.product_category_finished_sf').id, 'materials_id': self.env['sf.production.materials'].search( [('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_process_parameters_ids': [(6, 0, [])] if not item.get( 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), # 'barcode': item['barcode'], 'active': True, # 'route_ids': self._get_routes('') } copy_product_id.sudo().write(vals) # product_id.product_tmpl_id.active = False return copy_product_id def _get_ids(self, param): type_ids = [] if not param: return [] for item in param: type_ids.append(item.id) return [(6, 0, type_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), 'type': 'binary', 'public': True, 'description': '模型文件', 'name': name }) return attachment # 创建坯料 def no_bom_product_create(self, product_id, item, order_id, route_type, i): no_bom_copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy() no_bom_copy_product_id.product_tmpl_id.active = True materials_id = self.env['sf.production.materials'].search( [('materials_no', '=', item['texture_code'])]) materials_type_id = self.env['sf.materials.model'].search( [('materials_no', '=', item['texture_type_code'])]) model_type = self.env['sf.model.type'].search([], limit=1) supplier = self.env['mrp.bom'].get_supplier(materials_type_id) logging.info('no_bom_copy_product_supplier-vals:%s' % supplier) vals = { 'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R', order_id.name, i, materials_id.name, materials_type_id.name, item['model_long'] + model_type.embryo_tolerance, item['model_width'] + model_type.embryo_tolerance, item['model_height'] + model_type.embryo_tolerance), 'length': item['model_long'] + model_type.embryo_tolerance, 'width': item['model_width'] + model_type.embryo_tolerance, 'height': item['model_height'] + model_type.embryo_tolerance, 'volume': (item['model_long'] + model_type.embryo_tolerance) * ( item['model_width'] + model_type.embryo_tolerance) * ( item['model_height'] + model_type.embryo_tolerance), 'embryo_model_type_id': model_type.id, 'list_price': item['price'], 'materials_id': materials_id.id, 'materials_type_id': materials_type_id.id, 'is_bfm': True, # 'route_ids': self._get_routes(route_type), # 'categ_id': self.env.ref('sf_dlm.product_category_embryo_sf').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, 'active': True } # 外协和采购生成的坯料需要根据材料型号绑定供应商 if route_type == 'subcontract' or route_type == 'purchase': no_bom_copy_product_id.purchase_ok = True no_bom_copy_product_id.seller_ids = [ (0, 0, {'partner_id': supplier.partner_id.id, 'delay': 1.0})] if route_type == 'subcontract': partner = self.env['res.partner'].search([('id', '=', supplier.partner_id.id)]) partner.is_subcontractor = True no_bom_copy_product_id.write(vals) logging.info('no_bom_copy_product_id-vals:%s' % vals) # product_id.product_tmpl_id.active = False return no_bom_copy_product_id @api.model_create_multi def create(self, vals_list): for vals in vals_list: 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']: logging.info('create-attachment:%s' % int(item[2][0])) 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) logging.info('create-model_file:%s' % len(vals['model_file'])) self._sanitize_vals(vals) templates = super(ResProductMo, self).create(vals_list) if "create_product_product" not in self._context: templates._create_variant_ids() # This is needed to set given values to first variant after creation for template, vals in zip(templates, vals_list): related_vals = {} for field_name in self._get_related_fields_variant_template(): if vals.get(field_name): related_vals[field_name] = vals[field_name] if related_vals: template.write(related_vals) return templates @api.onchange('upload_model_file') def onchange_model_file(self): for item in self: if item.upload_model_file: if len(item.upload_model_file) > 1: raise ValidationError('只允许上传一个文件') manufacturing_order = self.env['mrp.production'].search([('product_id', '=', self.id)]) if manufacturing_order: raise ValidationError('该产品已生成制造订单,无法进行修改') file_attachment_id = item.upload_model_file[0] # 附件路径 report_path = file_attachment_id._full_path(file_attachment_id.store_fname) base64_data = base64.b64encode(file_attachment_id.datas) base64_datas = base64_data.decode('utf-8') model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest() item.model_file = self.transition_glb_file(report_path, model_code) # 将attach的datas内容转为glb文件 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) # 转化为glb output_glb_file = os.path.join('/tmp', str(code) + '.glb') util_path = get_resource_path('sf_dlm', 'static/util') cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file) os.system(cmd) # 转base64 with open(output_glb_file, 'rb') as fileObj: image_data = fileObj.read() base64_data = base64.b64encode(image_data) return base64_data class ResMrpBomMo(models.Model): _inherit = 'mrp.bom' subcontractor_id = fields.Many2one('res.partner', string='外包商') def bom_create_line_has(self, embryo): vals = { 'bom_id': self.id, 'product_id': embryo.id, 'product_tmpl_id': embryo.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': 1 } return self.env['mrp.bom.line'].create(vals) # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom def bom_create(self, product, bom_type, product_type): bom_id = self.env['mrp.bom'].create({ 'product_tmpl_id': product.product_tmpl_id.id, 'type': bom_type, # 'subcontractor_id': '' or subcontract.partner_id.id, 'product_qty': 1, 'product_uom_id': 1 }) if bom_type == 'subcontract' and product_type is not False: subcontract = self.get_supplier(product.materials_type_id) bom_id.subcontractor_id = subcontract.partner_id.id return bom_id # 坯料BOM组件:选取当前坯料原材料, # 然后根据当前的坯料的体积得出需要的原材料重量(立方米m³) *材料密度 * 1000 = 所需原材料重量KG(公斤) # 坯料所需原材料公式:当前的坯料的体积(立方米m³) *材料密度 * 1000 = 所需原材料重量KG(公斤) def bom_create_line(self, embryo): # 选取当前坯料原材料 raw_bom_line = self.get_raw_bom(embryo) if raw_bom_line: qty = 1 if round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000) > 1: qty = round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000) bom_line = self.env['mrp.bom.line'].create({ 'bom_id': self.id, 'product_id': raw_bom_line.id, 'product_tmpl_id': raw_bom_line.product_tmpl_id.id, 'product_qty': qty, 'product_uom_id': raw_bom_line.uom_id.id, }) return bom_line else: return False # 查询材料型号默认排第一的供应商 def get_supplier(self, materials_type): seller_id = self.env['sf.supplier.sort'].search( [('materials_model_id', '=', materials_type.id)], limit=1, order='sequence asc') return seller_id # 匹配bom def get_bom(self, product): embryo_has = self.env['product.product'].search( [('categ_id.type', '=', '坯料'), ('materials_type_id', '=', product.materials_type_id.id), ('length', '>', product.length), ('width', '>', product.width), ('height', '>', product.height), ('is_bfm', '=', False) ], limit=1, order='volume desc' ) logging.info('get_bom-vals:%s' % embryo_has) if embryo_has: rate_of_waste = ((embryo_has.volume - product.model_volume) % embryo_has.volume) * 100 if rate_of_waste <= 20: return embryo_has else: return # 查bom的原材料 def get_raw_bom(self, product): raw_bom = self.env['product.product'].search( [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)]) return raw_bom class SfMaintenanceEquipmentAndProductTemplate(models.Model): _inherit = 'maintenance.equipment' _description = '设备' product_template_ids = fields.One2many('maintenance.equipment.tool', 'equipment_id', string='机床刀位') @api.model_create_multi def create(self, vals_list): vals = [] for value in vals_list: res = super(SfMaintenanceEquipmentAndProductTemplate, self).create(value) number = value.get('number_of_knife_library') for i in range(1, number + 1): self.env['maintenance.equipment.tool'].create({ 'equipment_id': res.id, 'code': 'T' + str(i) }) vals.append(res) return vals[0] class SfMaintenanceEquipmentTool(models.Model): _name = 'maintenance.equipment.tool' _description = '机床刀位' equipment_id = fields.Many2one('maintenance.equipment', string='设备') product_template_id = fields.Many2one('product.template', string='功能刀具名称', domain="[('categ_type', '=', '刀具')]") image_1920 = fields.Binary('图片', related='product_template_id.image_1920') categ_type = fields.Char(string='功能刀具类型') diameter = fields.Char('直径') precision = fields.Char('粗\中\精') tool_code = fields.Char('功能刀具编码') hilt_name = fields.Char('刀柄名称') hilt_code = fields.Char('刀柄编码') life_value_max = fields.Char('最大寿命值') alarm_value = fields.Char('报警值') used_value = fields.Char('已使用值') code = fields.Char('机床刀位号')