# -*- coding: utf-8 -*- import logging import requests import base64 import hashlib import os import re from odoo import models, fields, api, _ from odoo.exceptions import ValidationError, UserError from odoo.modules import get_resource_path from OCC.Extend.DataExchange import read_step_file from OCC.Extend.DataExchange import write_stl_file class ResProductMo(models.Model): _inherit = 'product.template' def _get_machining_precision(self): machinings = self.env['sf.machining.accuracy'].sudo().search([]) list = [(m.sync_id, m.name) for m in machinings] return list model_file = fields.Binary('模型文件') 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_area = fields.Float('模型表面积(m²)') model_machining_precision = fields.Selection(selection=_get_machining_precision, 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='上传模型文件') model_file = fields.Binary('模型文件') 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='材料型号', domain="[('materials_id', '=', materials_id)]") # materials_type_id = fields.Many2one(related='cutting_tool_model_id.material_model_id', string='材料型号', # domain="[('materials_id', '=', materials_id)]") # cutting_tool_model_id.material_model_id 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.standard.library', string='型号名称') specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号') cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型', domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") # cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型', # domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") # brand_id = fields.Many2one('sf.machine.brand', '品牌') brand_id = fields.Many2one(related='cutting_tool_model_id.brand_id', string='品牌') # cutting_tool_model_id.brand_id # tool_length = fields.Float('长度(mm)') tool_length = fields.Float(related='specification_id.length', string='长度(mm)') # specification_id.length # tool_width = fields.Float('宽度(mm)') tool_width = fields.Float(related='specification_id.width', string='宽度(mm)') # specification_id.width tool_height = fields.Float('高度(mm)') # tool_thickness = fields.Float('厚度(mm)') tool_thickness = fields.Float(related='specification_id.thickness', string='厚度(mm)') # specification_id.thickness # tool_weight = fields.Float('重量(kg)') tool_weight = fields.Float(related='specification_id.weight', string='重量(kg)') # specification_id.weight # tool_hardness = fields.Integer('硬度(hrc)') tool_hardness = fields.Integer(related='cutting_tool_model_id.tool_hardness', string='硬度(hrc)') # cutting_tool_model_id.tool_hardness # coating_material = fields.Char('涂层材质') coating_material = fields.Char(related='cutting_tool_model_id.coating_material', string='涂层材质') # cutting_tool_model_id.coating_material # 整体式刀具特有字段 # cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1)) cutting_tool_total_length = fields.Float(related='specification_id.total_length', string='总长度(mm)', digits=(6, 1)) # specification_id.total_length # cutting_tool_shank_length = fields.Float('柄部长度(mm)', digits=(6, 1)) cutting_tool_shank_length = fields.Float(related='specification_id.handle_length', string='柄部长度(mm)', digits=(6, 1)) # specification_id.handle_length # cutting_tool_blade_length = fields.Float('刃部长度(mm)') cutting_tool_blade_length = fields.Float(related='specification_id.blade_length', string='刃部长度(mm)') # specification_id.blade_length # cutting_tool_blade_number = fields.Selection( # [('0', '0'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8')], # string='刃数(个)', default='0') cutting_tool_blade_number = fields.Selection(related='specification_id.blade_number', string='刃数(个)') # specification_id.blade_number # 整体式刀具新增字段 # cutting_tool_neck_length = fields.Float('颈部长度(mm)', digits=(6, 1)) cutting_tool_neck_length = fields.Float(related='specification_id.neck_length', string='颈部长度(mm)', digits=(6, 1)) # specification_id.neck_length # cutting_tool_neck_diameter = fields.Float('颈部直径(mm)', digits=(6, 1)) cutting_tool_neck_diameter = fields.Float(related='specification_id.neck_diameter', string='颈部直径(mm)', digits=(6, 1)) # specification_id.neck_diameter # cutting_tool_shank_diameter = fields.Float('柄部直径(mm)', digits=(6, 1)) cutting_tool_shank_diameter = fields.Float(related='specification_id.handle_diameter', string='柄部直径(mm)', digits=(6, 1)) # specification_id.handle_diameter # cutting_tool_blade_tip_diameter = fields.Float('刀尖直径(mm)', digits=(6, 1)) cutting_tool_blade_tip_diameter = fields.Float(related='specification_id.blade_tip_diameter', string='刀尖直径(mm)', digits=(6, 1)) # specification_id.blade_tip_diameter # cutting_tool_blade_tip_taper = fields.Integer('刀尖锥度(°)') cutting_tool_blade_tip_taper = fields.Integer(related='specification_id.blade_tip_taper', string='刀尖锥度(°)') # specification_id.blade_tip_taper # cutting_tool_blade_helix_angle = fields.Integer('刃部螺旋角(°)') cutting_tool_blade_helix_angle = fields.Integer(related='specification_id.blade_helix_angle', string='刃部螺旋角(°)') # specification_id.blade_helix_angle # cutting_tool_blade_type = fields.Char('刃部类型') cutting_tool_blade_type = fields.Char(related='cutting_tool_model_id.blade_type', string='刃部类型') # cutting_tool_pitch = fields.Float('牙距(mm)') cutting_tool_pitch = fields.Float(related='specification_id.pitch', string='牙距(mm)') # specification_id.pitch # cutting_tool_blade_width = fields.Float('刃部宽度(mm)') cutting_tool_blade_width = fields.Float(related='specification_id.blade_width', string='刃部宽度(mm)') # specification_id.blade_width # cutting_tool_blade_depth = fields.Float('刃部深度(mm)') cutting_tool_blade_depth = fields.Float(related='specification_id.blade_depth', string='刃部深度(mm)') # specification_id.blade_depth cutting_tool_cut_depth = fields.Float('切削深度(mm)') # cutting_tool_cut_depth_max = fields.Float('最大切削深度(mm)') cutting_tool_cut_depth_max = fields.Float(related='specification_id.cut_depth_max', string='最大切削深度(mm)') # specification_id.cut_depth_max # cutting_tool_coarse_medium_fine = fields.Selection([('粗', '粗'), ('中', '中'), ('精', '精')], '粗/中/精') cutting_tool_coarse_medium_fine = fields.Selection(related='cutting_tool_model_id.integral_coarse_medium_fine', string='粗/中/精') # cutting_tool_model_id.integral_coarse_medium_fine # cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1)) cutting_tool_run_out_accuracy_max = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_max', string='端跳精度max') # cutting_tool_model_id.integral_run_out_accuracy_max # cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1)) cutting_tool_run_out_accuracy_min = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_min', string='端跳精度min') # cutting_tool_model_id.integral_run_out_accuracy_min # cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20) cutting_tool_blade_tip_working_size = fields.Char(related='specification_id.blade_tip_working_size', string='刀尖倒角度(°)', size=20) # specification_id.blade_tip_working_size # cutting_tool_blade_tip_r_size = fields.Float('刀尖R角(mm)') cutting_tool_blade_tip_r_size = fields.Float(related='specification_id.tip_r_size', string='刀尖R角(mm)') # specification_id.tip_r_size fit_blade_shape_id = fields.Many2one('maintenance.equipment.image', '适配刀片形状', domain=[('type', '=', '刀片形状')]) suitable_machining_method_ids = fields.Many2many('maintenance.equipment.image', 'rel_machining_product_template', '适合加工方式', domain=[('type', '=', '加工能力')]) blade_tip_characteristics_id = fields.Many2one('maintenance.equipment.image', '刀尖特征', domain=[('type', '=', '刀尖特征')]) handle_type_id = fields.Many2one('maintenance.equipment.image', '柄部类型', 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_coolants_product_template', '适合冷却方式', domain=[('type', '=', '冷却方式')]) compaction_way_id = fields.Many2one('maintenance.equipment.image', '压紧方式', domain=[('type', '=', '压紧方式')]) name = fields.Char('产品名称', compute='_compute_tool_name', store=True, required=False) @api.constrains('seller_ids') def _check_seller_ids(self): if self.categ_type == '表面工艺': if self.seller_ids: if self.seller_ids[0].price == 0.0: raise UserError("请在该产品【采购】中的【价格】进行输入") else: raise UserError("请在【采购】中输入供应商信息") @api.depends('cutting_tool_model_id', 'specification_id') def _compute_tool_name(self): for item in self: if item.cutting_tool_model_id and item.specification_id: name = '%s%s' % (item.cutting_tool_model_id.name, item.specification_id.name) item.name = name def _get_process_parameters_product(self, production_process): return self.env['product.template'].search( [('server_product_process_parameters_id', '=', production_process.id)]).seller_ids[0] @api.onchange('cutting_tool_model_id') def _onchange_cutting_tool_model_id(self): for item in self: if item: item.specification_id = False item.cutting_tool_chuck_id = item.cutting_tool_model_id.chuck_id @api.onchange('cutting_tool_material_id') def _onchange_cutting_tool_material_id(self): for item in self: if item.cutting_tool_material_id.id != item.cutting_tool_model_id.cutting_tool_material_id.id: item.cutting_tool_model_id = False item.specification_id = False item.cutting_tool_type_id = False item.brand_id = False item.tool_hardness = False item.cutting_tool_run_out_accuracy_max = False item.cutting_tool_run_out_accuracy_min = False item.materials_type_id = False item.cutting_tool_blade_type = False item.cutting_tool_total_length = False item.cutting_tool_clamping_way = False item.cutting_tool_blade_diameter = False item.cutting_tool_shank_length = False item.cutting_tool_blade_length = False item.cutting_tool_blade_number = False item.cutting_tool_neck_length = False item.cutting_tool_neck_diameter = False item.cutting_tool_shank_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_pitch = False item.cutting_tool_blade_width = False item.cutting_tool_blade_depth = False item.cutting_tool_cut_depth = False item.cutting_tool_coarse_medium_fine = False item.cutting_tool_run_out_accuracy_max = False item.cutting_tool_run_out_accuracy_min = False item.cutting_tool_blade_tip_working_size = False item.fit_blade_shape_id = False item.suitable_machining_method_ids = False item.blade_tip_characteristics_id = False item.handle_type_id = False item.cutting_direction_ids = False item.suitable_coolant_ids = False item.compaction_way_id = False item.cutting_speed_ids = False item.feed_per_tooth_ids = False # def choice(self): # if self.cutting_tool_type == '整体式刀具': # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_integral_tree') # elif self.cutting_tool_type == '刀片': # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_blade_tree') # elif self.cutting_tool_type == '刀杆': # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_cutter_bar_tree') # elif self.cutting_tool_type == '刀盘': # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_tree') # elif self.cutting_tool_type == '刀柄': # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_tree') # else: # tree_view = self.env.ref('sf_base.view_sf_tool_materials_basic_parameters_tree') # return { # 'name': _('规格'), # 'view_mode': 'list', # 'view_id': tree_view.id, # 'type': 'ir.actions.act_window', # 'res_model': 'sf.tool.materials.basic.parameters', # 'target': 'new', # 'domain': [('cutting_tool_type', '=', self.cutting_tool_type), # ('standard_library_id', '=', self.cutting_tool_model_id.id)], # } # def name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): # # if self._context.get('is_sale_order_line'): # # domain = [('sale_ok', '=', True), ('categ_type', '=', '成品')] # # return self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) # return super(product.template, self)._name_search(name, args, operator, limit, name_get_uid) @api.onchange('specification_id') def _onchange_specification(self): if self.specification_id: self.cutting_speed_ids = False self.feed_per_tooth_ids = False self.cutting_tool_type_id = self.cutting_tool_model_id.cutting_tool_type_id.id self.brand_id = self.cutting_tool_model_id.brand_id.id self.tool_hardness = self.cutting_tool_model_id.tool_hardness self.cutting_tool_blade_type = self.cutting_tool_model_id.blade_type self.cutting_tool_coarse_medium_fine = self.cutting_tool_model_id.integral_coarse_medium_fine self.materials_type_id = self.cutting_tool_model_id.material_model_id.id self.coating_material = self.cutting_tool_model_id.coating_material if self.cutting_tool_type == '整体式刀具': self.cutting_tool_total_length = self.specification_id.total_length self.cutting_tool_run_out_accuracy_max = self.cutting_tool_model_id.integral_run_out_accuracy_max self.cutting_tool_run_out_accuracy_min = self.cutting_tool_model_id.integral_run_out_accuracy_min self.cutting_tool_blade_diameter = self.specification_id.blade_diameter self.cutting_tool_blade_length = self.specification_id.blade_length self.cutting_tool_blade_number = self.specification_id.blade_number self.cutting_tool_blade_type = self.cutting_tool_model_id.blade_type self.cutting_tool_shank_diameter = self.specification_id.handle_diameter self.cutting_tool_shank_length = self.specification_id.handle_length self.cutting_tool_neck_length = self.specification_id.neck_length self.cutting_tool_neck_diameter = self.specification_id.neck_diameter self.cutting_tool_blade_tip_diameter = self.specification_id.blade_tip_diameter self.cutting_tool_blade_tip_taper = self.specification_id.blade_tip_taper self.cutting_tool_blade_helix_angle = self.specification_id.blade_helix_angle self.cutting_tool_blade_tip_working_size = self.specification_id.blade_tip_working_size self.cutting_tool_blade_tip_r_size = self.specification_id.tip_r_size self.cutting_tool_pitch = self.specification_id.pitch self.cutting_tool_blade_width = self.specification_id.blade_width self.cutting_tool_blade_depth = self.specification_id.blade_depth self.cutting_tool_cut_depth_max = self.specification_id.cut_depth_max self.cutting_speed_ids = self.cutting_tool_model_id.cutting_speed_ids self.feed_per_tooth_ids = self.cutting_tool_model_id.feed_per_tooth_ids.filtered( lambda r: int(r.blade_diameter) == int(self.specification_id.blade_diameter)) elif self.cutting_tool_type == '夹头': self.cutting_tool_clamping_diameter_min = self.specification_id.min_clamping_diameter self.cutting_tool_clamping_diameter_max = self.specification_id.max_clamping_diameter self.cutting_tool_taper = self.specification_id.taper self.cutting_tool_top_diameter = self.specification_id.top_diameter self.cutting_tool_outer_diameter = self.specification_id.outer_diameter self.cutting_tool_inner_diameter = self.specification_id.inner_diameter self.tool_weight = self.specification_id.weight self.cutting_tool_jump_accuracy = self.specification_id.run_out_accuracy self.cutting_tool_max_load_capacity = self.specification_id.max_load_capacity self.cutting_tool_er_size_model = self.specification_id.er_size_model self.cutting_tool_handle_id = self.cutting_tool_model_id.handle_id.id self.cooling_suit_type_ids = self.specification_id.cooling_jacket elif self.cutting_tool_type == '刀片': self.cutting_tool_total_length = self.specification_id.total_length self.tool_length = self.specification_id.length self.tool_thickness = self.specification_id.thickness self.tool_width = self.specification_id.width self.cutting_tool_cut_blade_length = self.specification_id.cutting_blade_length self.cutting_tool_blade_tip_circular_arc_radius = self.specification_id.blade_tip_circular_arc_radius self.cutting_tool_blade_tip_height_tolerance = self.specification_id.blade_tip_height_tolerance self.cutting_tool_inscribed_circle_diameter = self.specification_id.inscribed_circle_diameter self.cutting_tool_inscribed_circle_tolerance = self.specification_id.inscribed_circle_tolerance self.cutting_tool_install_aperture_diameter = self.specification_id.install_aperture_diameter self.cutting_tool_chip_breaker_groove = self.specification_id.chip_breaker_groove self.cutting_tool_chip_breaker_type_code = self.specification_id.chip_breaker_type_code self.cutting_tool_blade_blade_number = self.specification_id.blade_blade_number self.cutting_tool_blade_width = self.specification_id.blade_width self.cutting_tool_rear_angle = self.specification_id.relief_angle self.cutting_tool_main_included_angle = self.specification_id.main_included_angle self.cutting_tool_top_angle = self.specification_id.top_angle self.cutting_tool_pitch = self.specification_id.pitch self.cutting_tool_bladed_teeth_model = self.specification_id.blade_teeth_model self.cutting_tool_thickness_tolerance = self.specification_id.thickness_tolerance self.cutting_tool_thread_model = self.specification_id.thread_model self.cutting_tool_thread_num = self.specification_id.thread_num self.cutting_tool_cutter_bar_ids = self.cutting_tool_model_id.cutter_bar_ids.ids self.cutting_tool_cutter_pad_ids = self.cutting_tool_model_id.cutter_pad_ids.ids self.cutting_speed_ids = self.cutting_tool_model_id.cutting_speed_ids self.feed_per_tooth_ids = self.cutting_tool_model_id.feed_per_tooth_ids elif self.cutting_tool_type in ('刀盘', '刀杆'): self.cutting_tool_blade_diameter = self.specification_id.blade_diameter self.cutting_tool_total_length = self.specification_id.total_length self.tool_length = self.specification_id.length self.tool_thickness = self.specification_id.thickness self.tool_width = self.specification_id.width self.cutting_tool_cut_blade_length = self.specification_id.cutting_blade_length self.cutting_tool_blade_tip_circular_arc_radius = self.specification_id.blade_tip_circular_arc_radius self.cutting_tool_blade_tip_height_tolerance = self.specification_id.blade_tip_height_tolerance self.cutting_tool_inscribed_circle_diameter = self.specification_id.inscribed_circle_diameter self.cutting_tool_inscribed_circle_tolerance = self.specification_id.inscribed_circle_tolerance self.cutting_tool_install_aperture_diameter = self.specification_id.install_aperture_diameter self.cutting_tool_chip_breaker_groove = self.specification_id.chip_breaker_groove self.cutting_tool_chip_breaker_type_code = self.specification_id.chip_breaker_type_code self.cutting_tool_blade_blade_number = self.specification_id.blade_blade_number self.cutting_tool_blade_width = self.specification_id.blade_width self.cutting_tool_rear_angle = self.specification_id.relief_angle self.cutting_tool_main_included_angle = self.specification_id.main_included_angle self.cutting_tool_top_angle = self.specification_id.top_angle self.cutting_tool_screw = self.specification_id.screw self.cutting_tool_wrench = self.specification_id.spanner self.cutting_tool_blade_id = self.specification_id.blade_id.id self.cutting_tool_is_cooling_hole = self.specification_id.is_cooling_hole self.cutting_tool_locating_slot_code = self.specification_id.locating_slot_code self.cutting_tool_install_blade_tip_num = self.specification_id.install_blade_tip_num self.cutting_tool_installing_structure = self.specification_id.installing_structure self.cutting_tool_cut_depth_max = self.specification_id.cut_depth_max if self.cutting_tool_type == '刀盘': self.cutting_tool_blade_length = self.specification_id.blade_length self.cutting_tool_cutter_head_diameter = self.specification_id.cutter_head_diameter self.cutting_tool_interface_diameter = self.specification_id.interface_diameter else: self.cutting_tool_cutter_arbor_diameter = self.specification_id.cutter_arbor_diameter self.cutting_tool_knife_head_height = self.specification_id.knife_head_height self.cutting_tool_knife_head_width = self.specification_id.knife_head_width self.cutting_tool_knife_head_length = self.specification_id.knife_head_length self.cutting_tool_tool_shim = self.specification_id.tool_shim self.cutting_tool_cotter_pin = self.specification_id.cotter_pin self.cutting_tool_pressing_plate = self.specification_id.pressing_plate self.cutting_tool_min_machining_aperture = self.specification_id.min_machining_aperture self.cutting_tool_rear_angle = self.specification_id.relief_angle elif self.cutting_tool_type == '刀柄': self.cutting_tool_total_length = self.specification_id.total_length self.cutting_tool_shank_diameter = self.specification_id.shank_diameter self.cutting_tool_shank_length = self.specification_id.shank_length self.cutting_tool_speed_max = self.specification_id.max_rotate_speed self.cutting_tool_change_time = self.specification_id.tool_changing_time self.cutting_tool_total_length = self.specification_id.total_length self.cutting_tool_clamping_diameter_max = self.specification_id.max_clamping_diameter self.cutting_tool_clamping_diameter_min = self.specification_id.min_clamping_diameter self.cutting_tool_flange_length = self.specification_id.flange_shank_length self.cutting_tool_flange_diameter = self.specification_id.flange_diameter self.cutting_tool_fit_chuck_size = self.specification_id.fit_chuck_size self.cutting_tool_dynamic_balance_class = self.specification_id.dynamic_balance_class self.cutting_tool_is_high_speed_cutting = self.specification_id.is_quick_cutting self.cutting_tool_is_safety_lock = self.specification_id.is_safe_lock self.cutting_tool_fit_nut_model = self.specification_id.nut self.cutting_tool_wrench = self.specification_id.spanner self.cutting_tool_jump_accuracy = self.specification_id.diameter_slip_accuracy self.cutting_tool_taper_shank_model = self.specification_id.taper_shank_model self.cutting_tool_cooling_type = self.specification_id.cooling_model self.cutting_tool_clamping_way = self.specification_id.clamping_mode self.suitable_machining_method_ids = [(6, 0, [])] if not \ self.cutting_tool_model_id.suitable_machining_method_ids \ else [(6, 0, self.cutting_tool_model_id.suitable_machining_method_ids.ids)] self.blade_tip_characteristics_id = self.cutting_tool_model_id.blade_tip_characteristics_id.id self.handle_type_id = self.cutting_tool_model_id.handle_type_id.id self.cutting_direction_ids = [(6, 0, [])] if not self.cutting_tool_model_id.cutting_direction_ids else [ (6, 0, self.cutting_tool_model_id.cutting_direction_ids.ids)] self.suitable_coolant_ids = [(6, 0, [])] if not self.cutting_tool_model_id.suitable_coolant_ids else [ (6, 0, self.cutting_tool_model_id.suitable_coolant_ids.ids)] self.compaction_way_id = self.cutting_tool_model_id.compaction_way_id.id self.fit_blade_shape_id = self.cutting_tool_model_id.fit_blade_shape_id.id self.image_1920 = self.cutting_tool_model_id.image else: self.cutting_tool_type_id = False self.brand_id = False self.tool_hardness = False self.cutting_tool_run_out_accuracy_max = False self.cutting_tool_run_out_accuracy_min = False self.materials_type_id = False self.cutting_tool_blade_type = False self.cutting_tool_total_length = False self.cutting_tool_clamping_way = False self.cutting_tool_blade_diameter = False self.cutting_tool_shank_length = False self.cutting_tool_blade_length = False self.cutting_tool_blade_number = False self.cutting_tool_neck_length = False self.cutting_tool_neck_diameter = False self.cutting_tool_shank_diameter = False self.cutting_tool_blade_tip_diameter = False self.cutting_tool_blade_tip_taper = False self.cutting_tool_blade_helix_angle = False self.cutting_tool_blade_type = False self.cutting_tool_pitch = False self.cutting_tool_blade_width = False self.cutting_tool_blade_depth = False self.cutting_tool_cut_depth = False self.cutting_tool_coarse_medium_fine = False self.cutting_tool_run_out_accuracy_max = False self.cutting_tool_run_out_accuracy_min = False self.cutting_tool_blade_tip_working_size = False self.fit_blade_shape_id = False self.suitable_machining_method_ids = False self.blade_tip_characteristics_id = False self.handle_type_id = False self.cutting_direction_ids = False self.suitable_coolant_ids = False self.compaction_way_id = False self.cutting_speed_ids = False self.feed_per_tooth_ids = False # @api.constrains('fit_blade_shape_id', 'suitable_machining_method_ids', 'blade_tip_characteristics_id', # 'handle_type_id', 'cutting_direction_ids', 'suitable_coolant_ids', 'compaction_way_id') # def _check_cutting_tool_ability(self): # if self.cutting_tool_type in ['整体式刀具', '刀片', '刀杆', '刀盘']: # if self.cutting_tool_type in ['刀片', '刀杆', '刀盘']: # if not self.fit_blade_shape_id: # raise ValidationError("请选择适配刀片形状") # if self.cutting_tool_type in ['刀杆', '刀盘']: # if not self.compaction_way_id: # raise ValidationError("请选择压紧方式") # if self.cutting_tool_type == '刀片': # if not self.suitable_coolant_ids: # raise ValidationError("请选择适合冷却方式") # elif self.cutting_tool_type == '整体式刀具': # if not self.handle_type_id: # raise ValidationError("请选择柄部类型") # if not self.suitable_coolant_ids: # raise ValidationError("请选择适合冷却方式") # if not self.suitable_machining_method_ids: # raise ValidationError("请选择适合加工方式") # if not self.blade_tip_characteristics_id: # raise ValidationError("请选择刀尖特征") # if not self.cutting_direction_ids: # raise ValidationError("请选择走刀方向") # cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc') cutting_speed_ids = fields.One2many(related='cutting_tool_model_id.cutting_speed_ids', string='切削速度Vc') # cutting_tool_model_id.cutting_speed_ids feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz') cutting_tool_diameter = fields.Float('刀具直径(mm)') # cutting_tool_rear_angle = fields.Integer('后角(°)') cutting_tool_rear_angle = fields.Integer(related='specification_id.relief_angle', string='后角(°)') # specification_id.relief_angle # cutting_tool_main_included_angle = fields.Integer('主偏角(°)') cutting_tool_main_included_angle = fields.Integer(related='specification_id.main_included_angle', string='主偏角(°)') # specification_id.main_included_angle # 适用夹头型号可以多选 cutting_tool_chuck_id = fields.Many2one( 'sf.cutting_tool.standard.library', domain="[('cutting_tool_type', '=', '夹头')]", string='适用夹头型号') # 刀片参数 # cutting_tool_cut_blade_length = fields.Float('切削刃长(mm)') cutting_tool_cut_blade_length = fields.Float(related='specification_id.cutting_blade_length', string='切削刃长(mm)') # specification_id.cutting_blade_length # cutting_tool_blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20) cutting_tool_blade_tip_circular_arc_radius = fields.Char(related='specification_id.blade_tip_circular_arc_radius', string='刀尖圆弧半径(mm)') # specification_id.blade_tip_circular_arc_radius # cutting_tool_top_angle = fields.Integer('顶角(°)') cutting_tool_top_angle = fields.Integer(related='specification_id.top_angle', string='顶角(°)') # specification_id.top_angle # cutting_tool_inscribed_circle_diameter = fields.Float('内接圆直径(mm)') cutting_tool_inscribed_circle_diameter = fields.Float(related='specification_id.inscribed_circle_diameter', string='内接圆直径(mm)') # specification_id.inscribed_circle_diameter # cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)') cutting_tool_install_aperture_diameter = fields.Float(related='specification_id.install_aperture_diameter', string='安装孔直径(mm)') # specification_id.install_aperture_diameter # cutting_tool_chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')], # string='有无断屑槽') cutting_tool_chip_breaker_groove = fields.Selection(related='specification_id.chip_breaker_groove', string='有无断屑槽') # specification_id.chip_breaker_groove # cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号') cutting_tool_chip_breaker_type_code = fields.Char(related='specification_id.chip_breaker_type_code', string='断屑槽型代号') # specification_id.chip_breaker_type_code # cutting_tool_bladed_teeth_model = fields.Selection( # [('无', '无'), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'), # ('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'), # ('UNJ全牙型', 'UNJ全牙型'), ('DIN405圆牙型', 'DIN405圆牙型'), ('ACME梯形', 'ACME梯形'), # ('石油管螺纹刀片', '石油管螺纹刀片'), ('矮牙ACME梯形', '矮牙ACME梯形'), # ('Trapeze30° 103', 'Trapeze30° 103')], string='刀片牙型', default='无') cutting_tool_bladed_teeth_model = fields.Selection(related='specification_id.blade_teeth_model', string='断屑槽型代号') # specification_id.blade_teeth_model # cutting_tool_blade_blade_number = fields.Selection( # [('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), # ('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')], # string='刀片的刃数(个)') cutting_tool_blade_blade_number = fields.Selection(related='specification_id.blade_blade_number', string='刀片的刃数(个)') # specification_id.blade_blade_number # cutting_tool_thread_model = fields.Selection([('无', '无'), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')], # string='螺纹类型') cutting_tool_thread_model = fields.Selection(related='specification_id.thread_model', string='螺纹类型') # specification_id.thread_model # cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)') cutting_tool_thread_num = fields.Float(related='specification_id.thread_num', string='每英寸螺纹数(tpi)') # specification_id.thread_num # cutting_tool_blade_tip_height_tolerance = fields.Char('刀尖高度公差(mm)', size=20) cutting_tool_blade_tip_height_tolerance = fields.Char(related='specification_id.blade_tip_height_tolerance', string='刀尖高度公差(mm)') # specification_id.blade_tip_height_tolerance # cutting_tool_inscribed_circle_tolerance = fields.Char('内接圆公差(mm)', size=20) cutting_tool_inscribed_circle_tolerance = fields.Char(related='specification_id.inscribed_circle_tolerance', string='内接圆公差(mm)') # specification_id.inscribed_circle_tolerance # cutting_tool_thickness_tolerance = fields.Char('厚度公差(mm)', size=20) cutting_tool_thickness_tolerance = fields.Char(related='specification_id.thickness_tolerance', string='厚度公差(mm)') # specification_id.thickness_tolerance # cutting_tool_jump_accuracy = fields.Char('径跳精度(mm)') cutting_tool_jump_accuracy = fields.Char(related='specification_id.run_out_accuracy', string='径跳精度(mm)') # specification_id.run_out_accuracy cutting_tool_working_hardness = fields.Integer('加工硬度(hrc)') cutting_tool_cutter_bar_ids = fields.Many2many( 'sf.cutting_tool.standard.library', relation='product_cutting_tool_library_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.standard.library', relation='product_cutting_tool_library_cutter_pad_rel', column1='model_id_1', column2='model_id_2', domain="[('cutting_tool_type', '=', '刀盘')]", string='适用刀盘型号' # 使用空列表作为默认值 ) # 刀杆/参数 # cutting_tool_knife_head_height = fields.Float('刀头高度(mm)') cutting_tool_knife_head_height = fields.Float(related='specification_id.knife_head_height', string='刀头高度(mm)') # specification_id.knife_head_height # cutting_tool_knife_head_width = fields.Float('刀头宽度(mm)') cutting_tool_knife_head_width = fields.Float(related='specification_id.knife_head_width', string='刀头宽度(mm)') # cutting_tool_knife_head_length = fields.Float('刀头长度(mm)') cutting_tool_knife_head_length = fields.Float(related='specification_id.knife_head_length', string='刀头长度(mm)') # cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)') cutting_tool_blade_diameter = fields.Float(related='specification_id.blade_diameter', string='刃径/刃部直径(mm)') # specification_id.blade_diameter # cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)') cutting_tool_cutter_arbor_diameter = fields.Float(related='specification_id.cutter_arbor_diameter', string='刀杆直径(mm)') # specification_id.cutter_arbor_diameter # cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)') cutting_tool_min_machining_aperture = fields.Integer(related='specification_id.min_machining_aperture', string='最小加工孔径(mm)') # specification_id.min_machining_aperture # cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)') cutting_tool_install_blade_tip_num = fields.Integer(related='specification_id.install_blade_tip_num', string='可装刀片数/齿数(个)') # specification_id.install_blade_tip_num # cutting_tool_installing_structure = fields.Char('安装结构', size=20) cutting_tool_installing_structure = fields.Char(related='specification_id.installing_structure', string='安装结构') # specification_id.installing_structure cutting_tool_blade_id = fields.Many2one( 'sf.cutting_tool.standard.library', domain="[('cutting_tool_type', '=', '刀片')]", string='适用刀片型号' # 使用空列表作为默认值 ) # cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id', # domain="[('cutting_tool_type', '=', '刀片')]", # string='适用刀片型号') # specification_id.blade_id # cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50) cutting_tool_tool_shim = fields.Char(related='specification_id.tool_shim', string='适配刀垫型号') # specification_id.tool_shim # cutting_tool_cotter_pin = fields.Char('适配销钉型号', size=50) cutting_tool_cotter_pin = fields.Char(related='specification_id.cotter_pin', string='适配销钉型号') # cutting_tool_pressing_plate = fields.Char('适配压板型号', size=50) cutting_tool_pressing_plate = fields.Char(related='specification_id.pressing_plate', string='适配压板型号') # cutting_tool_screw = fields.Char('适配螺钉型号', size=50) cutting_tool_screw = fields.Char(related='specification_id.screw', string='适配螺钉型号') # specification_id.screw # cutting_tool_wrench = fields.Char('适配扳手型号') cutting_tool_wrench = fields.Char(related='specification_id.spanner', string='适配扳手型号') # specification_id.spanner # cutting_tool_is_cooling_hole = fields.Boolean('有无冷却孔', default=False) cutting_tool_is_cooling_hole = fields.Boolean(related='specification_id.is_cooling_hole', string='有无冷却孔') # specification_id.is_cooling_hole # cutting_tool_locating_slot_code = fields.Char('定位槽代号', size=20) cutting_tool_locating_slot_code = fields.Char(related='specification_id.locating_slot_code', string='定位槽代号') # specification_id.locating_slot_code # 刀盘参数 # cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)') cutting_tool_cutter_head_diameter = fields.Float(related='specification_id.cutter_head_diameter', string='刀盘直径(mm)') # specification_id.cutter_head_diameter # cutting_tool_interface_diameter = fields.Float('接口直径(mm)') cutting_tool_interface_diameter = fields.Float(related='specification_id.interface_diameter', string='接口直径(mm)') # specification_id.interface_diameter # 刀柄参数 # cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径') cutting_tool_clamping_diameter_max = fields.Float(related='specification_id.max_clamping_diameter', string='最大夹持直径') # specification_id.max_clamping_diameter # cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径') cutting_tool_clamping_diameter_min = fields.Float(related='specification_id.min_clamping_diameter', string='最小夹持直径') # specification_id.min_clamping_diameter # cutting_tool_flange_length = fields.Float('法兰柄长(mm)') cutting_tool_flange_length = fields.Float(related='specification_id.flange_shank_length', string='法兰柄长(mm)') # cutting_tool_flange_diameter = fields.Float('法兰直径(mm)') cutting_tool_flange_diameter = fields.Float(related='specification_id.flange_diameter', string='法兰直径(mm)') # cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False) cutting_tool_is_safety_lock = fields.Boolean(related='specification_id.is_safe_lock', string='有无安全锁') # cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False) cutting_tool_is_high_speed_cutting = fields.Boolean(related='specification_id.is_quick_cutting', string='可高速切削') # cutting_tool_change_time = fields.Integer('换刀时间(s)') cutting_tool_change_time = fields.Integer(related='specification_id.tool_changing_time', string='换刀时间(s)') # cutting_tool_clamping_way = fields.Char('夹持方式') cutting_tool_clamping_way = fields.Char(related='specification_id.clamping_mode', string='夹持方式') # cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸') cutting_tool_fit_chuck_size = fields.Char(related='specification_id.fit_chuck_size', string='适配夹头尺寸') # cutting_tool_taper_shank_model = fields.Char('锥柄型号') cutting_tool_taper_shank_model = fields.Char(related='specification_id.taper_shank_model', string='锥柄型号') cutting_tool_standard_speed = fields.Integer('标准转速(n/min)') # cutting_tool_speed_max = fields.Integer('最大转速(n/min)') cutting_tool_speed_max = fields.Integer(related='specification_id.max_rotate_speed', string='最大转速(n/min)') # specification_id.max_rotate_speed cutting_tool_cooling_type = fields.Char('冷却类型') cutting_tool_dynamic_balance_class = fields.Char('动平衡等级') # cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号') cutting_tool_fit_nut_model = fields.Char(related='specification_id.nut', string='适用锁紧螺母型号') # specification_id.nut # 夹头参数 # cutting_tool_taper = fields.Integer('锥度(°)') cutting_tool_taper = fields.Integer(related='specification_id.taper', string='锥度(°)') # specification_id.taper # cutting_tool_top_diameter = fields.Float('顶部直径') cutting_tool_top_diameter = fields.Float(related='specification_id.top_diameter', string='顶部直径') # specification_id.top_diameter # cutting_tool_outer_diameter = fields.Float('外径(mm)') # specification_id.outer_diameter cutting_tool_outer_diameter = fields.Float(related='specification_id.outer_diameter', string='外径(mm)') # cutting_tool_inner_diameter = fields.Float('内径(mm)') cutting_tool_inner_diameter = fields.Float(related='specification_id.inner_diameter', string='内径(mm)') # specification_id.inner_diameter # cooling_suit_type_ids = fields.Char('适用冷却套型号') cooling_suit_type_ids = fields.Char(related='specification_id.cooling_jacket', string='适用冷却套型号') # specification_id.cooling_jacket # cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)') cutting_tool_max_load_capacity = fields.Float(related='specification_id.max_load_capacity', string='最大负载能力(kg)') # specification_id.max_load_capacity # cutting_tool_er_size_model = fields.Char('尺寸型号') cutting_tool_er_size_model = fields.Char(related='specification_id.er_size_model', string='尺寸型号') # specification_id.er_size_model # cutting_tool_handle_ids = fields.Many2many( # 'sf.cutting_tool.standard.library', # relation='product_cutting_tool_library_chuck_handle_rel', # column1='model_id_1', # column2='model_id_2', # domain="[('cutting_tool_type', '=', '刀柄')]", # string='适用刀柄型号' # ) cutting_tool_handle_id = fields.Many2one( 'sf.cutting_tool.standard.library', domain="[('cutting_tool_type', '=', '刀柄')]", string='适用刀柄型号' ) # cutting_tool_handle_id = fields.Many2one(related='cutting_tool_model_id.handle_id', # domain="[('cutting_tool_type', '=', '刀柄')]", # string='适用刀柄型号') # cutting_tool_model_id.handle_id # 注册状态 register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')], string='注册状态', default='未注册') industry_code = fields.Char('行业编码', readonly=True) # bfm下单 manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) machining_drawings = fields.Binary('2D加工图纸', readonly=True) quality_standard = fields.Binary('质检标准', readonly=True) part_name = fields.Char(string='零件名称', compute='_compute_related_product', readonly=True, store=True) part_number = fields.Char(string='零件图号', compute='_compute_related_product', readonly=True, store=True) machining_drawings_name = fields.Char(string='零件图号名称', readonly=True) machining_drawings_mimetype = fields.Char(string='零件图号类型', readonly=True) model_url = fields.Char('模型文件地址') glb_url = fields.Char('glb文件地址') area = fields.Float('表面积(m²)') auto_machining = fields.Boolean('自动化加工(模型识别)', default=False) model_id = fields.Char('模型ID') @api.depends('name') def _compute_related_product(self): for record in self: if record.categ_id.name == '坯料': product_name = '' match = re.search(r'(S\d{5}-\d)', record.name) # 如果匹配成功,提取结果 if match: product_name = match.group(0) sale_order_name = '' match_sale = re.search(r'S(\d+)', record.name) if match_sale: sale_order_name = match_sale.group(0) sale_order = self.env['sale.order'].sudo().search( [('name', '=', sale_order_name)]) if sale_order: filtered_order_line = sale_order.order_line.filtered( lambda order_line: re.search(f'{product_name}$', order_line.product_id.name) ) record.part_number = filtered_order_line.product_id.part_number if filtered_order_line else None record.part_name = filtered_order_line.product_id.part_name if filtered_order_line else None @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") 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_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 _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 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 attachment_update(self, name, res_id, res_field, mimetype): attachment_info = self.env['ir.attachment'].sudo().search( [('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1) attachment_info.write({'name': name, 'mimetype': mimetype}) # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 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']) # 获取坯料冗余配置 if not item.get('embryo_redundancy'): embryo_redundancy_id = model_type.embryo_tolerance_id else: embryo_redundancy_id = item.get('embryo_redundancy') if not embryo_redundancy_id: raise UserError('请先配置模型类型内的坯料冗余') vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long), 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width), 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height), 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * ( item['model_width'] + embryo_redundancy_id.width) * ( item['model_height'] + embryo_redundancy_id.height)), 'product_model_type_id': model_type.id, 'model_processing_panel': item['processing_panel_detail'], '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_volume'], 'area': item['model_area'], # 'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']), 'model_url': item['model_url'], 'glb_url': item['glb_url'], 'model_name': item['model_name'], 'auto_machining': item['auto_machining'], # 'upload_model_file': [(6, 0, [attachment.id])] if attachment else None, 'list_price': item['price'], '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_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'], 'single_manufacturing': True, 'default_code': '%s-%s' % (order_number, i), 'manual_quotation': item['manual_quotation'] or False, 'part_number': item.get('part_number') or '', 'active': True, 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode( item['machining_drawings']), 'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']), 'part_name': item.get('part_name') or '', 'machining_drawings_name': item.get('machining_drawings_name') or '', 'machining_drawings_mimetype': item.get('machining_drawings_mimetype') or '', 'model_id': item['model_id'], } tax_id = self.env['account.tax'].sudo().search( [('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')]) if tax_id: vals.update({'taxes_id': [(6, 0, [int(tax_id)])]}) copy_product_id.sudo().write(vals) product_id.product_tmpl_id.active = False if item['machining_drawings'] and item['machining_drawings_name'] and item['machining_drawings_mimetype']: self.attachment_update(item['machining_drawings_name'], copy_product_id.product_tmpl_id.id, 'machining_drawings', item['machining_drawings_mimetype']) if item['quality_standard'] and item['quality_standard_name'] and item['quality_standard_mimetype']: self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id, 'quality_standard', item['quality_standard_mimetype']) return copy_product_id def format_float(self, value): # 将浮点数转换为字符串 value_str = str(value) # 检查小数点的位置 if '.' in value_str: # 获取小数部分 decimal_part = value_str.split('.')[1] # 判断小数位数是否超过2位 if len(decimal_part) > 2: # 超过2位则保留2位小数 return "{:.2f}".format(value) # 否则保持原来的位数 return float(value_str) 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): if not data: return None 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, finish_product): no_bom_copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy() # if finish_product.model_process_parameters_ids: # surface_technology = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')]) # if surface_technology: # no_bom_copy_product_id.route_ids |= surface_technology no_bom_copy_product_id.product_tmpl_id.active = True logging.info('no_bom_copy_product_id[is_manual_processing]:%s' % no_bom_copy_product_id.is_manual_processing) 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) # 获取坯料冗余配置 if not item.get('embryo_redundancy_id'): embryo_redundancy_id = model_type.embryo_tolerance_id else: embryo_redundancy_id = item.get('embryo_redundancy_id') if not embryo_redundancy_id: raise UserError('请先配置模型类型内的坯料冗余') 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, self.format_float(item['model_long'] + embryo_redundancy_id.long), self.format_float(item['model_width'] + embryo_redundancy_id.width), self.format_float(item['model_height'] + embryo_redundancy_id.height)), 'length': self.format_float(item['model_long'] + embryo_redundancy_id.long), 'width': self.format_float(item['model_width'] + embryo_redundancy_id.width), 'height': self.format_float(item['model_height'] + embryo_redundancy_id.height), 'volume': self.format_float(item['blank_volume']), 'area': self.format_float(item['blank_area']), 'embryo_model_type_id': model_type.id, 'list_price': item['price'], 'materials_id': materials_id.id, 'materials_type_id': materials_type_id.id, 'single_manufacturing': product_id.single_manufacturing, 'is_bfm': True, 'active': True, 'tracking': finish_product.tracking, # 坯料的跟踪方式跟随成品 } # 外协和采购生成的坯料需要根据材料型号绑定供应商 if route_type == 'subcontract' or route_type == 'purchase': no_bom_copy_product_id.purchase_ok = True if supplier: 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 else: return -3 no_bom_copy_product_id.write(vals) 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) # 产品名称唯一性校验 for item in templates: if len(self.search([('name', '=', item.name)])) > 1: raise UserError('产品名称【%s】已存在' % item.name) if item.categ_type == '表面工艺': if len(self.search([('server_product_process_parameters_id', '=', item.server_product_process_parameters_id.id),('server_product_process_parameters_id', '!=', False)])) > 1: raise UserError('表面工艺参数为【%s】的产品已存在' % item.server_product_process_parameters_id.name) 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_base', '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 ResProductFixture(models.Model): _inherit = 'product.template' _description = '夹具产品信息' fixture_model_id = fields.Many2one('sf.fixture.model', '夹具型号') specification_fixture_id = fields.Many2one('sf.fixture.materials.basic.parameters', '夹具规格') fixture_material_id = fields.Many2one('sf.fixture.material', string="夹具物料") fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name') multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型") model_file = fields.Binary(string="3D模型图") glb_url = fields.Char(string="3D模型图") # 夹具物料基本参数 diameter = fields.Float('直径(mm)', digits=(16, 2)) # '零点卡盘' 字段 weight = fields.Float('重量(kg)', digits=(16, 2)) orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2)) clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2)) clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数') chucking_power_max = fields.Float('最大夹持力(KN)', digits=(16, 2)) repeated_positioning_accuracy = fields.Char('重复定位精度(mm)', size=20) boolean_transposing_hole = fields.Boolean('是否有转位孔') unlocking_method = fields.Selection( [('手动', '手动'), ('气动', '气动'), ('液压', '液压'), ('电动', '电动'), ('其他', '其他')], string='解锁方式') boolean_chip_blowing_function = fields.Boolean('是否有吹屑功能') carrying_capacity_max = fields.Float('最大承载重量(kg)', digits=(16, 2)) rigidity = fields.Integer('硬度HRC') materials_model_id = fields.Many2one('sf.materials.model', '夹具材质') machine_tool_type_id = fields.Many2one('sf.machine_tool.type', '适用机床型号') # ’零点托盘‘ 字段 connector_diameter = fields.Selection([('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('8', '8')], string='连接头直径(mm)') way_to_install = fields.Selection( [('接口式', '接口式'), ('螺栓固定', '螺栓固定'), ('磁吸式', '磁吸式'), ('其他', '其他')], string='安装方式') type_of_drive = fields.Selection( [('气动式', '气动式'), ('液压式', '液压式'), ('机械式', '机械式'), ('电动式', '电动式'), ('其他', '其他')], string='驱动方式') # ’气动夹具‘ 字段 gripper_length_min = fields.Float('夹持工件最小长度(mm)', digits=(16, 2)) gripper_width_min = fields.Float('夹持工件最小宽度(mm)', digits=(16, 2)) gripper_height_min = fields.Float('夹持工件最小高度(mm)', digits=(16, 2)) gripper_diameter_min = fields.Float('夹持工件最小直径(mm)', digits=(16, 2)) gripper_length_max = fields.Float('夹持工件最大长度(mm)', digits=(16, 2)) gripper_width_max = fields.Float('夹持工件最大宽度(mm)', digits=(16, 2)) gripper_height_max = fields.Float('夹持工件最大高度(mm)', digits=(16, 2)) gripper_diameter_max = fields.Float('夹持工件最大直径(mm)', digits=(16, 2)) rated_air_pressure = fields.Float('额定气压(Mpa)', digits=(16, 2)) interface_materials_model_id = fields.Many2one('sf.materials.model', '接口类型') # ‘虎钳夹具' 字段 transverse_groove = fields.Float('横向配合槽n(mm)', digits=(16, 2)) longitudinal_fitting_groove = fields.Float('纵向配合槽l(mm)', digits=(16, 2)) # '磁吸夹具' 字段 height_tolerance_value = fields.Char('高度公差(mm)') rated_adsorption_force = fields.Float('额定吸附力(N/cm²)', digits=(16, 2)) magnetic_field_height = fields.Float('磁场高度(mm)', digits=(16, 2)) magnetic_pole_plate_grinding_allowance = fields.Float('磁极板磨削余量(mm)', digits=(16, 2)) # '转接板(锁板)夹具' 字段 screw_size = fields.Float('螺牙大小(mm)', digits=(16, 2)) via_hole_diameter = fields.Float('过孔直径(mm)', digits=(16, 2)) # '三爪卡盘' 字段 mounting_hole_depth = fields.Float('安装孔深度(mm)', digits=(16, 2)) centering_diameter = fields.Float('定心直径(mm)', digits=(16, 2)) @api.onchange('specification_fixture_id') def _onchange_specification_fixture_id(self): if self.specification_fixture_id: self.length = self.specification_fixture_id.length self.width = self.specification_fixture_id.width self.height = self.specification_fixture_id.height self.weight = self.specification_fixture_id.weight self.diameter = self.specification_fixture_id.diameter self.orientation_dish_diameter = self.specification_fixture_id.orientation_dish_diameter self.clamping_diameter = self.specification_fixture_id.clamping_diameter self.clamping_num = self.specification_fixture_id.clamping_num self.chucking_power_max = self.specification_fixture_id.chucking_power_max self.repeated_positioning_accuracy = self.specification_fixture_id.repeated_positioning_accuracy self.boolean_transposing_hole = self.specification_fixture_id.boolean_transposing_hole self.unlocking_method = self.specification_fixture_id.unlocking_method self.boolean_chip_blowing_function = self.specification_fixture_id.boolean_chip_blowing_function self.carrying_capacity_max = self.specification_fixture_id.carrying_capacity_max self.rigidity = self.specification_fixture_id.rigidity self.materials_model_id = self.specification_fixture_id.materials_model_id self.machine_tool_type_id = self.specification_fixture_id.machine_tool_type_id self.connector_diameter = self.specification_fixture_id.connector_diameter self.way_to_install = self.specification_fixture_id.way_to_install self.type_of_drive = self.specification_fixture_id.type_of_drive self.gripper_length_min = self.specification_fixture_id.gripper_length_min self.gripper_width_min = self.specification_fixture_id.gripper_width_min self.gripper_height_min = self.specification_fixture_id.gripper_height_min self.gripper_diameter_min = self.specification_fixture_id.gripper_diameter_min self.gripper_length_max = self.specification_fixture_id.gripper_length_max self.gripper_width_max = self.specification_fixture_id.gripper_width_max self.gripper_height_max = self.specification_fixture_id.gripper_height_max self.gripper_diameter_max = self.specification_fixture_id.gripper_diameter_max self.rated_air_pressure = self.specification_fixture_id.rated_air_pressure self.interface_materials_model_id = self.specification_fixture_id.interface_materials_model_id self.transverse_groove = self.specification_fixture_id.transverse_groove self.longitudinal_fitting_groove = self.specification_fixture_id.longitudinal_fitting_groove self.height_tolerance_value = self.specification_fixture_id.height_tolerance_value self.rated_adsorption_force = self.specification_fixture_id.rated_adsorption_force self.magnetic_field_height = self.specification_fixture_id.magnetic_field_height self.magnetic_pole_plate_grinding_allowance = self.specification_fixture_id.magnetic_pole_plate_grinding_allowance self.screw_size = self.specification_fixture_id.screw_size self.via_hole_diameter = self.specification_fixture_id.via_hole_diameter self.mounting_hole_depth = self.specification_fixture_id.mounting_hole_depth self.centering_diameter = self.specification_fixture_id.centering_diameter 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%02d" % i }) vals.append(res) return vals[0] base_coordinate_fixture_model_id = fields.Many2one('sf.fixture.model', '基坐标卡盘型号', domain=[('fixture_material_id', '=', '零点卡盘')]) base_coordinate_g_coordinate = fields.Char('G坐标') base_coordinate_x = fields.Float('x轴', digits=(12, 3)) base_coordinate_y = fields.Float('y轴', digits=(12, 3)) base_coordinate_z = fields.Float('z轴', digits=(12, 3)) # ==========获取机床基坐标接口========== def get_equipment_base_coordinate(self): headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'} crea_url = "https://x24467i973.zicp.fun/AutoDeviceApi/EquipmentBaseCoordinate" params = {"DeviceId": self.name} r = requests.get(crea_url, params=params, headers=headers) ret = r.json() logging.info('register_equipment_tool:%s' % ret) self.write({ 'base_coordinate_fixture_model_id': ret['base_coordinate_fixture_model_id'], 'base_coordinate_g_coordinate': ret['base_coordinate_g_coordinate'], 'base_coordinate_x': ret['base_coordinate_x'], 'base_coordinate_y': ret['base_coordinate_y'], 'base_coordinate_z': ret['base_coordinate_z'], }) if ret['Succeed']: return "机床基坐标获取成功" else: raise ValidationError("机床基坐标获取失败") class SfMaintenanceEquipmentTool(models.Model): _name = 'maintenance.equipment.tool' _description = '机床刀位' equipment_id = fields.Many2one('maintenance.equipment', string='设备') code = fields.Char('机床刀位号') name = fields.Char('刀位号', compute='_compute_name') # 待删除字段 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('已使用值') @api.depends('code') def _compute_name(self): for record in self: if record.code: record.name = record.code