# -*- coding: utf-8 -*- # Part of SmartGo. See LICENSE file for full copyright and licensing details. import base64 import logging import math import json import requests from io import BytesIO from odoo import api, fields, models, SUPERUSER_ID from pystrich.code128 import Code128Encoder from odoo.exceptions import ValidationError from odoo.addons.sf_base.commons.common import Common _logger = logging.getLogger(__name__) class CNCprocessing(models.Model): _inherit = 'cnc.processing' _description = "CNC加工" workorder_id = fields.Many2one('mrp.workorder', string="工单") class Tray(models.Model): _inherit = 'sf.tray' _description = '托盘' qr_image = fields.Binary(string="托盘二维码", compute='compute_qr_image') production_id = fields.Many2one('mrp.production', string='制造订单', related='workorder_id.production_id' ) workorder_id = fields.Many2one('mrp.workorder', string="工单" ) @api.onchange('production_id') def updateTrayState(self): if self.workorder_id != False: self.state = '占用' else: self.state = '空闲' def unclamp(self): self.workorder_id = False self.production_id = False self.state = '空闲' @api.depends('code') def compute_qr_image(self): for item in self: if not item.code: item.qr_image = False continue # 根据code动态生成二维码图片 # qr = qrcode.QRCode( # version=1, # error_correction=qrcode.constants.ERROR_CORRECT_L, # box_size=10, # border=4, # ) # qr.add_data(item.code) # qr.make(fit=True) # img = qr.make_image() # 生成条形码文件 # bar = barcode.get("ean13", "123456789102", writer=ImageWriter()) # a = bar.get_fullcode() # b = bar.save('occ') # 生成条形码图片 partner_encoder = Code128Encoder(item.code) # 转换bytes流 temp = BytesIO() partner_encoder.save(temp) # img.save(temp, format='PNG') qr_image = base64.b64encode(temp.getvalue()) item.qr_image = qr_image ''' 工单绑定托盘信息 ''' class MrpWorkOrder(models.Model): _inherit = 'mrp.workorder' _description = '工单' tray_ids = fields.One2many('sf.tray', 'workorder_id', string='托盘') # def get_tray_info(self): # @api.onchange('X_axis', 'Y_axis', 'Z_axis') # def get_center_point(self): # return 'X:%s,Y:%s,Z:%s' % (self.X_axis, self.Y_axis, self.Z_axis) # 加工面 # surface = fields.Selection([("前面", "前面"), ("后面", "后面"), ("左面", "左面"), ("右面", "右面"), # ("上面", "上面")], string="加工面1") material_center_point = fields.Char(string='配料中心点') X1_axis = fields.Float(string='Lx1', default=0) Y1_axis = fields.Float(string='Ly1', default=0) Z1_axis = fields.Float(string='Lz1', default=0) X2_axis = fields.Float(string='Lx2', default=0) Y2_axis = fields.Float(string='Ly2', default=0) Z2_axis = fields.Float(string='Lz2', default=0) X3_axis = fields.Float(string='Fx3', default=0) Y3_axis = fields.Float(string='Fy3', default=0) Z3_axis = fields.Float(string='Fz3', default=0) X4_axis = fields.Float(string='Fx4', default=0) Y4_axis = fields.Float(string='Fy4', default=0) Z4_axis = fields.Float(string='Fz4', default=0) X5_axis = fields.Float(string='Rx5', default=0) Y5_axis = fields.Float(string='Ry5', default=0) Z5_axis = fields.Float(string='Rz5', default=0) X6_axis = fields.Float(string='Rx6', default=0) Y6_axis = fields.Float(string='Ry6', default=0) Z6_axis = fields.Float(string='Rz6', default=0) X7_axis = fields.Float(string='Bx7', default=0) Y7_axis = fields.Float(string='By7', default=0) Z7_axis = fields.Float(string='Bz7', default=0) X8_axis = fields.Float(string='Bx8', default=0) Y8_axis = fields.Float(string='By8', default=0) Z8_axis = fields.Float(string='Bz8', default=0) X9_axis = fields.Float(string='Uz9', default=0) Y9_axis = fields.Float(string='Uz9', default=0) Z9_axis = fields.Float(string='Uz9', default=0) X10_axis = fields.Float(string='Uz10', default=0) Y10_axis = fields.Float(string='Uz10', default=0) Z10_axis = fields.Float(string='Uz10', default=0) # 计算配料中心点和与x轴倾斜度方法 def getcenter(self): x1 = self.X1_axis x2 = self.X2_axis x3 = self.X3_axis x4 = self.X4_axis x5 = self.X5_axis x6 = self.X6_axis x7 = self.X7_axis x8 = self.X8_axis y1 = self.Y1_axis y2 = self.Y2_axis y3 = self.Y3_axis y4 = self.Y4_axis y5 = self.Y5_axis y6 = self.Y6_axis y7 = self.Y7_axis y8 = self.Y8_axis z1 = self.Z9_axis x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / ( (x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4)) y0 = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / ( (y3 - y4) * (x1 - x2) - (y1 - y2) * (x3 - x4)) x1 = ((x7 - x8) * (x6 * y5 - x5 * y7) - (x5 - x6) * (x8 * y7 - x7 * y8)) / ( (x7 - x8) * (y5 - y6) - (x5 - x6) * (y7 - y8)); y1 = ((y7 - y8) * (y6 * x5 - y5 * x7) - (y5 - y6) * (y8 * x7 - y7 * x8)) / ( (y7 - y8) * (x5 - x6) - (y5 - y6) * (x7 - x8)) x = (x0 + x1) / 2 y = (y0 + y1) / 2 z = z1 / 2 jd = math.atan2((x7 - x8), (y7 - y8)) jdz = jd * 180 / math.pi print("(%s,%s)" % (x, y)) self.material_center_point = ("(%s,%s,%s)" % (x, y, z)) self.X_deviation_angle = jdz X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], string="检测结果") cnc_ids = fields.One2many("cnc.processing", 'workorder_id', string="CNC加工") tray_code = fields.Char(string="托盘") # 扫码绑定托盘方法 def gettray(self): if self.tray_code != False: values = self.env['sf.tray'].search([("code", "=", self.tray_code)]) if values: if values.state == "占用": raise ValidationError('该托盘已占用') if values.state == "报损": raise ValidationError('该托盘已损坏') else: values.update({ 'workorder_id': self, 'production_id': self.production_id, 'state': '占用', }) else: raise ValidationError('该托盘编码已失效') else:return "" # 解除托盘绑定 def unbindtray(self): tray = self.env['sf.tray'].search([("production_id", "=", self.production_id.id)]) if tray: tray.unclamp() return "" def recreateManufacturing(self): """ 重新生成制造订单 """ values = self.env['mrp.production'].create_production1_values(self.production_id) productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( self.production_id.company_id).create( values) self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) productions._create_workorder() productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ ( p.move_dest_ids.procure_method != 'make_to_order' and not p.move_raw_ids and not p.workorder_ids)).action_confirm() for production in productions: origin_production = production.move_dest_ids and production.move_dest_ids[ 0].raw_material_production_id or False orderpoint = production.orderpoint_id if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual': production.message_post( body=_('This production order has been created from Replenishment Report.'), message_type='comment', subtype_xmlid='mail.mt_note') elif orderpoint: production.message_post_with_view( 'mail.message_origin_link', values={'self': production, 'origin': orderpoint}, subtype_id=self.env.ref('mail.mt_note').id) elif origin_production: production.message_post_with_view( 'mail.message_origin_link', values={'self': production, 'origin': origin_production}, subtype_id=self.env.ref('mail.mt_note').id) # print(productions) return "" def recreateWorkerOrder(self): """ 返工重新生成工单 """ productions = self.production_id self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) productions.create_workorder1(self.processing_panel) return "" # cnc程序获取 def fetchCNC(self): cnc_process = self.env['mrp.workorder'].search( [("routing_type", '=', 'CNC加工'), ("production_id", '=', self.production_id.id)], limit=1, order='id asc' ) vals = { 'model_long': cnc_process.product_id.model_long, 'model_width': cnc_process.product_id.model_width, 'model_height': cnc_process.product_id.model_height, 'model_volume': cnc_process.product_id.model_volume, 'model_price': cnc_process.product_id.model_price, 'model_total_amount': cnc_process.product_id.model_total_amount, 'model_materials_code': cnc_process.product_id.materials_id.materials_no, 'model_materials_type_code': cnc_process.product_id.materials_type_id.materials_no, 'model_surface_process_code': cnc_process.product_id.model_surface_process_id.process_encode, 'model_process_parameters_code': cnc_process.product_id.model_process_parameters_id.process_encode, 'model_remark': cnc_process.product_id.model_remark } res = [{'order_no': self.product_id.barcode, 'production_no': self.production_id.name, 'intelligent_programming_str': vals, 'machine_tool_code': cnc_process.workcenter_id.machine_tool_id.code}] configsettings = self.env['res.config.settings'].get_values() token = configsettings['token'] mrs_secret_key = configsettings['mrs_secret_key'] config_header = Common.get_headers(self, token, mrs_secret_key) url = '/api/intelligent_programming/create' config_url = configsettings['mrs_url'] + url res_str = json.dumps(res) ret = requests.post(config_url, json={"result": res_str}, data=None, headers=config_header) return "" ''' 制造订单绑定托盘信息 ''' class MrpProduction(models.Model): _inherit = 'mrp.production' _description = "制造订单" tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘") def create_production1_values(self, production): production_values_str = {'origin': production.origin, 'product_id': production.product_id.id, 'product_description_variants': production.product_description_variants, 'product_qty': production.product_qty, 'product_uom_id': production.product_uom_id.id, 'location_src_id': production.location_src_id.id, 'location_dest_id': production.location_dest_id.id, 'bom_id': production.bom_id.id, 'date_deadline': production.date_deadline, 'date_planned_start': production.date_planned_start, 'date_planned_finished': production.date_planned_finished, 'procurement_group_id': False, 'propagate_cancel': production.propagate_cancel, 'orderpoint_id': production.orderpoint_id.id, 'picking_type_id': production.picking_type_id.id, 'company_id': production.company_id.id, 'move_dest_ids': production.move_dest_ids.ids, 'user_id': production.user_id.id} return production_values_str def create_workorder1(self, k): for production in self: if not production.bom_id or not production.product_id: continue workorders_values = [] product_qty = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id) exploded_boms, dummy = production.bom_id.explode(production.product_id, product_qty / production.bom_id.product_qty, picking_type=production.bom_id.picking_type_id) for bom, bom_data in exploded_boms: # If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders. if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[ 'parent_line'].bom_id.operation_ids != bom.operation_ids)): continue for operation in bom.operation_ids: if operation._skip_operation_line(bom_data['product']): continue workorders_values += [{ 'name': operation.name, 'production_id': production.id, 'workcenter_id': operation.workcenter_id.id, 'product_uom_id': production.product_uom_id.id, 'operation_id': operation.id, 'state': 'pending', }] # 根据加工面板的面数及对应的工序模板生成工单 i = 0 production.product_id.model_processing_panel = k processing_panel_len = len(k) for k in (production.product_id.model_processing_panel.split(',')): routingworkcenter = self.env['sf.model.type.routing.sort'].search( [('model_type_id', '=', production.product_id.model_type_id.id)], order='sequence asc' ) i += 1 for route in routingworkcenter: if route.routing_type == 'CNC加工': workorders_values.append( self.env['mrp.workorder'].json_workorder_str(k, production, route)) if route.routing_type == '后置三元质量检测': workorders_values.append( self.env['mrp.workorder'].json_workorder_str(k, production, route)) production.workorder_ids = workorders_values for workorder in production.workorder_ids: workorder.duration_expected = workorder._get_duration_expected() class Attachment(models.Model): _inherit = 'ir.attachment' cnc_model = fields.Binary('cnc文件', attachment=False) model_name = fields.Char('模型名称')