From 8e51654f178176634a2aaeb3d6594b7e3904304d Mon Sep 17 00:00:00 2001 From: gqh Date: Wed, 11 Jan 2023 14:51:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6sf=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm/models/product_template.py | 104 ++++---- sf_machine_connect/__manifest__.py | 4 +- sf_machine_connect/models/data_collection.py | 44 ---- sf_machine_connect/models/ftp_client.py | 238 +++++++++++------- sf_machine_connect/models/ftp_operate.py | 71 +++--- sf_machine_connect/models/py2opcua.py | 42 ++-- .../static/src/css/many2one_field.scss | 13 + sf_machine_connect/static/src/js/test.js | 82 ++++++ .../static/src/xml/many2one_field.xml | 27 +- sf_machine_connect/views/Barcode_Scan.xml | 14 -- .../views/SfWorkOrderBarcodes.xml | 1 + sf_machine_connect/views/compensation.xml | 7 +- sf_machine_connect/views/flush_template.xml | 23 -- sf_machine_connect/views/ftp_button.xml | 5 +- sf_machine_connect/views/machine_monitor.xml | 101 ++++++-- sf_machine_connect/views/purchase_barcode.xml | 25 -- .../views/sf_machine_connnect.xml | 176 ------------- sf_machine_connect/views/views.xml | 45 ---- .../views/views_test_barcode.xml | 15 -- sf_machine_connect/views/workorder_button.xml | 18 -- sf_manufacturing/models/mrp_workorder.py | 95 ++++--- sf_manufacturing/views/mrp_workorder_view.xml | 17 +- sf_sale/models/sale_order.py | 1 - 23 files changed, 547 insertions(+), 621 deletions(-) delete mode 100644 sf_machine_connect/models/data_collection.py create mode 100644 sf_machine_connect/static/src/css/many2one_field.scss create mode 100644 sf_machine_connect/static/src/js/test.js delete mode 100644 sf_machine_connect/views/Barcode_Scan.xml delete mode 100644 sf_machine_connect/views/flush_template.xml delete mode 100644 sf_machine_connect/views/purchase_barcode.xml delete mode 100644 sf_machine_connect/views/sf_machine_connnect.xml delete mode 100644 sf_machine_connect/views/views.xml delete mode 100644 sf_machine_connect/views/views_test_barcode.xml delete mode 100644 sf_machine_connect/views/workorder_button.xml diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index f80f0437..40fcac15 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -3,9 +3,10 @@ from odoo.exceptions import ValidationError import logging import base64 import os -from OCC.Extend.DataExchange import read_step_file, write_stl_file +# from OCC.Extend.DataExchange import read_step_file, write_stl_file from odoo.modules import get_resource_path + class ResProductTemplate(models.Model): _inherit = 'product.template' @@ -16,11 +17,11 @@ class ResProductTemplate(models.Model): model_height = fields.Float('模型高[mm]', digits=(16, 3)) model_volume = fields.Float('模型体积[m³]') model_machining_precision = fields.Selection([ - ('±0.10mm', '±0.10mm'), - ('±0.05mm', '±0.05mm'), - ('±0.03mm', '±0.03mm'), - ('±0.02mm', '±0.02mm'), - ('±0.01mm', '±0.01mm')], string='加工精度') + ('0.10', '±0.10mm'), + ('0.05', '±0.05mm'), + ('0.03', '±0.03mm'), + ('0.02', '±0.02mm'), + ('0.01', '±0.01mm')], string='加工精度') model_type_id = fields.Many2one('sf.model.type', string='模型类型') model_processing_panel = fields.Char('模型加工面板') model_surface_process_id = fields.Many2one('sf.production.process', string='表面工艺') @@ -34,6 +35,15 @@ class ResProductTemplate(models.Model): materials_type_id = fields.Many2one('sf.materials.model', string='材料型号') single_manufacturing = fields.Boolean(string="单个制造") upload_model_file = fields.Many2many('ir.attachment', 'upload_model_file_attachment_ref', string='上传模型文件') + model_code = fields.Char('模型编码') + + 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') + # model_file = fields.Binary('模型文件') # 胚料的库存路线设置 @@ -70,18 +80,19 @@ class ResProductTemplate(models.Model): 'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( item['model_width'] + model_type.embryo_tolerance) * ( item['model_height'] + model_type.embryo_tolerance), - 'model_type_id': 1, - # 'model_machining_precision': item['model_machining_precision'], - 'model_processing_panel': 'A', - 'model_machining_precision': '±0.10mm', + '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': base64.b64decode(item['model_file']), + 'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']), 'model_name': attachment.name, 'upload_model_file': [(6, 0, [attachment.id])], # '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( @@ -94,26 +105,26 @@ class ResProductTemplate(models.Model): # [('process_encode', '=', item['process_parameters_code'])]).id, 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), - #'barcode': item['barcode'], + # 'barcode': item['barcode'], 'active': True, # 'route_ids': self._get_routes('') } copy_product_id.sudo().write(vals) - print(len(copy_product_id.model_file)) - product_id.product_tmpl_id.active = False + # product_id.product_tmpl_id.active = False return copy_product_id def attachment_create(self, name, data): attachment = self.env['ir.attachment'].create({ - 'datas': base64.b64decode(data), + '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): + 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( @@ -124,9 +135,10 @@ class ResProductTemplate(models.Model): 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' % ( - order_id.name, materials_id.name, materials_type_id.name, item['model_long'], item['model_width'], - item['model_height']), + 'name': '%s-%s %s %s %s * %s * %s' % ( + 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, @@ -150,40 +162,38 @@ class ResProductTemplate(models.Model): 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, 'is_subcontractor': True})] - logging.info('no_bom_copy_product_id-seller_ids-vals:%s' % no_bom_copy_product_id.seller_ids) elif 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})] - logging.info('no_bom_copy_product_id-seller_ids-vals:%s' % no_bom_copy_product_id.seller_ids) no_bom_copy_product_id.write(vals) logging.info('no_bom_copy_product_id-vals:%s' % vals) - product_id.product_tmpl_id.active = False + # product_id.product_tmpl_id.active = False return no_bom_copy_product_id - @api.onchange('upload_model_file') - def onchange_model_file(self): - for item in self: - if len(item.upload_model_file) > 1: - raise ValidationError('只允许上传一个文件') - if item.upload_model_file: - file_attachment_id = item.upload_model_file[0] - item.model_name = file_attachment_id.name - # 附件路径 - report_path = file_attachment_id._full_path(file_attachment_id.store_fname) - shapes = read_step_file(report_path) - output_file = get_resource_path('sf_dlm', 'static/file', 'out.stl') - write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) - # 转化为glb - output_glb_file = get_resource_path('sf_dlm', 'static/file', 'out.glb') - util_path = get_resource_path('sf_dlm', 'static/util') - cmd = 'python %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) - item.model_file = base64_data + # @api.onchange('upload_model_file') + # def onchange_model_file(self): + # for item in self: + # if len(item.upload_model_file) > 1: + # raise ValidationError('只允许上传一个文件') + # if item.upload_model_file: + # file_attachment_id = item.upload_model_file[0] + # item.model_name = file_attachment_id.name + # # 附件路径 + # report_path = file_attachment_id._full_path(file_attachment_id.store_fname) + # shapes = read_step_file(report_path) + # output_file = get_resource_path('sf_dlm', 'static/file', 'out.stl') + # write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) + # # 转化为glb + # output_glb_file = get_resource_path('sf_dlm', 'static/file', 'out.glb') + # util_path = get_resource_path('sf_dlm', 'static/util') + # cmd = 'python %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) + # item.model_file = base64_data class ResMrpBom(models.Model): @@ -244,8 +254,6 @@ class ResMrpBom(models.Model): # 匹配bom def get_bom(self, product): - logging.info('get_bom-product:%s' % product) - logging.info('get_bom-product:%s' % product.materials_type_id.id) embryo_has = self.env['product.product'].search( [('categ_id.type', '=', '胚料'), ('materials_type_id', '=', product.materials_type_id.id), ('length', '>', product.length), ('width', '>', product.width), @@ -257,7 +265,7 @@ class ResMrpBom(models.Model): 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: + if rate_of_waste <= 20: return embryo_has else: return diff --git a/sf_machine_connect/__manifest__.py b/sf_machine_connect/__manifest__.py index b74437dc..52fee05c 100644 --- a/sf_machine_connect/__manifest__.py +++ b/sf_machine_connect/__manifest__.py @@ -14,7 +14,6 @@ 'data': [ # 定义权限组放在最上面 # 权限组 - "security/ir.model.access.csv", 'views/compensation.xml', 'views/ftp_button.xml', 'views/SfWorkOrderBarcodes.xml', @@ -23,6 +22,9 @@ 'views/machine_monitor.xml', ], + 'assets': { + }, + 'installable': True, 'application': True, # 'auto_install': False, diff --git a/sf_machine_connect/models/data_collection.py b/sf_machine_connect/models/data_collection.py deleted file mode 100644 index 8f860c37..00000000 --- a/sf_machine_connect/models/data_collection.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, fields, models - -# ---------------------------------------------------------- -# Models for Simulation -# ---------------------------------------------------------- -class Simulation(models.Model): - _name = 'simulation' - _description = 'SIMULATION' - - name = fields.Char('Name', size=50, readonly=True) - place_value = fields.Boolean(String="位值") - place_value_random = fields.Boolean(String="位值随机") - place_value_ai = fields.Boolean(String="位值自增") - place_value_list = fields.Boolean(String="位值列表") - - unsigned_integer_8_DO = fields.Integer(Sting="无符号8位整数D0") - unsigned_integer_8_D1 = fields.Integer(Sting="无符号8位整数D1") - unsigned_integer_8_random = fields.Integer(Sting="无符号8位整数随机") - unsigned_integer_8_ai = fields.Integer(Sting="无符号8位整数自增") - unsigned_integer_8_list = fields.Integer(Sting="无符号8位整数列表") - - integer_8 = fields.Integer(String="有符号8位整数") - integer_8_random = fields.Integer(String="有符号8位整数随机") - integer_8_ai = fields.Integer(String="有符号8位整数自增") - integer_8_ad = fields.Integer(String="有符号8位整数自减") - integer_16 = fields.Integer(String="有符号16位整数") - integer_16_random = fields.Integer(String="有符号16位整数随机") - integer_16_list = fields.Integer(String="有符号16位整数列表") - - - - -# ---------------------------------------------------------- -# Models for Mitsubishi -# ---------------------------------------------------------- -class MitsuCnc(models.Model): - _name = 'mitsu.cnc' - _description = 'Mitsubishi CNC' - - name = fields.Char('Name', size=50, readonly=True) - status = fields.Boolean(string="状态") diff --git a/sf_machine_connect/models/ftp_client.py b/sf_machine_connect/models/ftp_client.py index 9f943dca..6744ca1a 100644 --- a/sf_machine_connect/models/ftp_client.py +++ b/sf_machine_connect/models/ftp_client.py @@ -1,22 +1,21 @@ # -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. import base64 - -import psycopg2 -import os import logging -from zeep.exceptions import ValidationError -from odoo import http -from ftplib import FTP -from odoo.http import request -from odoo import api, fields, models +import json +import hashlib +import time +import requests +from datetime import datetime + +from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError +from odoo.exceptions import UserError from odoo.addons.sf_machine_connect.models import py2opcua, ftp_operate -# from .ftp_operate import FtpController -# from .py2opcua import Py2opcua _logger = logging.getLogger(__name__) + # ---------------------------------------------------------- # Models for client # ---------------------------------------------------------- @@ -24,8 +23,13 @@ _logger = logging.getLogger(__name__) class FtpButton(models.Model): _inherit = 'sf.cnc.processing' + button_state = fields.Boolean(string='是否已经下发') + def pri(self): - print('11111111111111111') + """ + 一个测试函数,用于检测能否从”获取cnc程序“处获得NC代码文件 + :return: + """ s = self.cnc_id s1 = self.cnc_id._filestore() print(s1) @@ -36,72 +40,115 @@ class FtpButton(models.Model): ftp_operate.FtpController.prin(self) def up(self): - # self.env['mrp.workorder'].check_compensation_before_up() - ftp = ftp_operate.FtpController() - # ftp.delAllfile('C://Users//马广威//Desktop//ftp') - a = self.cnc_id - print(a.display_name) - _logger.info(a.display_name) - datas = base64.standard_b64decode(a.datas) - # file_path = '{}\{}\{}'.format(a._filestore(), a.store_fname.split('/'[0]), a.display_name) + """ + 此函数用于将NC代码下发到机床 + :return: + """ + # 点击下发按钮自动补偿三元检测偏差值 - # 此方法不走ftp,直接文件写入,暂不确定能否写入ftp服务器,但可以转成ftp方法,只是要把文件暂存到本地,再上传 - # file_path_local = '{}\{}'.format('C://Users//马广威//Desktop//ftp', a.display_name) - file_path_local = '{}/{}'.format('/nc2machine', a.display_name) - file_path_remote = '{}\{}'.format('//(192,168,2,141)//DS', a.display_name) + try: + try: + if self.sequence_number == '1': + self.check_compensation_before_up() + except Exception: + raise UserError("补偿值写入执行超时,请检查机床状态或者写入状态") + ftp = ftp_operate.FtpController() + # ftp.delAllfile('C://Users//马广威//Desktop//ftp') + a = self.cnc_id + _logger.info(a.public) + _logger.info(a.display_name) + datas = base64.standard_b64decode(a.datas) - with open(file_path_local, mode='wb+') as file: - file.write(datas) + # file_path = '{}\{}\{}'.format(a._filestore(), a.store_fname.split('/'[0]), a.display_name) + file_path_local = '{}/{}'.format('/nc2machine', a.display_name) + file_path_remote = '{}\{}'.format('//(192,168,2,141)//DS', a.display_name) - # file = open(file_path_local, 'wb+') - # file.write(datas) - # file.close() + with open(file_path_local, mode='wb+') as file: + file.write(datas) + # 存在本地的文件下发到机床 + ftp.upload_file(remotepath=file_path_remote, localpath=file_path_local) + except Exception as e: + _logger.info("=====================================", e) + raise UserError('NC下发执行超时, 请检查下发状态') - # 存在本地的文件下发到机床 - ftp.upload_file(remotepath=file_path_remote, localpath=file_path_local) + # 补偿下发都执行完毕后,按钮标志位变为true + self.button_state = True + # 新增,下发完成返回当前工单位置 + # return { + # 'name': _("工单"), + # 'view_mode': 'form', + # 'res_model': 'mrp.workorder', + # 'res_id': self.workorder_id, + # 'type': 'ir.actions.act_window', + # 'target': 'new' + # } -class FtpClient(models.Model): - _name = "ftp.client" - _description = 'Ftp Client' - - name = fields.Char('Name', size=50, readonly=True) - description = fields.Char(size=50) - mobile = fields.Char(size=50) - - def up(self): - ftp = ftp_operate.FtpController() - # FtpController.__init__(self, host="127.0.0.1", port=2121, username="admin", password="123456") - ftp.upload_file(remotepath='/(192,168,199,2)/DS/02-222.NC', localpath='D:/ftp/up/02-222.NC') - - # def delete(self): - # ftp = FtpController() - # ftp.del_file() - - # - # def _compute_ip_url(self): - # for box in self: - # if not box.ip: - # box.ip_url = False - # else: - # url = 'https://%s' if box.get_base_url()[:5] == 'https' else 'http://%s:8069' - # box.ip_url = url % box.ip - # - # def _compute_device_count(self): - # for box in self: - # box.device_count = len(box.device_ids) + def check_compensation_before_up(self): + """ + 下发NC代码前自动补偿三元检测偏差值 + :return: + """ + try: + temp_dict = {} + temp_dict[ + 'ns=1;s=Project_Default.Group1.Mitsubishi_NC2.hongbianliang550'] = self.workorder_id.compensation_value_x + temp_dict[ + 'ns=1;s=Project_Default.Group1.Mitsubishi_NC2.hongbianliang551'] = self.workorder_id.compensation_value_y + temp = py2opcua.Py2opcua() + # temp.connect() + temp.write(temp_dict) + # temp.disconnect() + except Exception as e: + _logger.info("=====================================", e) + raise UserError('补偿值获取失败,或机床未连接,请检查') class Machine_ftp(models.Model): - # _name = 'data.collection' + """ + 数据采集类 + """ _inherit = 'sf.machine_tool' timestamp = fields.Datetime('时间戳', readonly=True) signed = fields.Integer('刷新间隔', readonly=True) status = fields.Boolean('在线状态', readonly=True) + time_on = fields.Char('总在线时长', readonly=True) + time_on_now = fields.Char('本次在线时长', readonly=True) tool_num = fields.Integer('当前刀具', readonly=True) program = fields.Char('当前程序', readonly=True) + run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '等待中')], string='运行状态', + readonly=True, default='0') + run_time = fields.Char('总运行时长', readonly=True) + cut_time = fields.Char('总切削时长', readonly=True) + cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='切削状态', + readonly=True, default='0') + + tool_num_process_time1 = fields.Char('刀位1', readonly=True, default='0') + tool_num_process_time2 = fields.Char('刀位2', readonly=True, default='0') + tool_num_process_time3 = fields.Char('刀位3', readonly=True, default='0') + tool_num_process_time4 = fields.Char('刀位4', readonly=True, default='0') + tool_num_process_time5 = fields.Char('刀位5', readonly=True, default='0') + tool_num_process_time6 = fields.Char('刀位6', readonly=True, default='0') + tool_num_process_time7 = fields.Char('刀位7', readonly=True, default='0') + tool_num_process_time8 = fields.Char('刀位8', readonly=True, default='0') + tool_num_process_time9 = fields.Char('刀位9', readonly=True, default='0') + tool_num_process_time10 = fields.Char('刀位10', readonly=True, default='0') + tool_num_process_time11 = fields.Char('刀位11', readonly=True, default='0') + tool_num_process_time12 = fields.Char('刀位12', readonly=True, default='0') + tool_num_process_time13 = fields.Char('刀位13', readonly=True, default='0') + tool_num_process_time14 = fields.Char('刀位14', readonly=True, default='0') + tool_num_process_time15 = fields.Char('刀位15', readonly=True, default='0') + tool_num_process_time16 = fields.Char('刀位16', readonly=True, default='0') + tool_num_process_time17 = fields.Char('刀位17', readonly=True, default='0') + tool_num_process_time18 = fields.Char('刀位18', readonly=True, default='0') + tool_num_process_time19 = fields.Char('刀位19', readonly=True, default='0') + tool_num_process_time20 = fields.Char('刀位20', readonly=True, default='0') + tool_num_process_time21 = fields.Char('刀位21', readonly=True, default='0') + tool_num_process_time22 = fields.Char('刀位22', readonly=True, default='0') + tool_num_process_time23 = fields.Char('刀位23', readonly=True, default='0') + tool_num_process_time24 = fields.Char('刀位24', readonly=True, default='0') class WorkCenterBarcode(models.Model): @@ -109,45 +156,56 @@ class WorkCenterBarcode(models.Model): 扫码托盘码可查到制造订单,由制造订单查工单 """ _inherit = "mrp.workorder" + compensation_value_x = fields.Float(string='X轴补偿值') compensation_value_y = fields.Float(string='Y轴补偿值') + button_compensation_state = fields.Boolean(string='是否已经补偿') def compensation(self): - ''' + """ 将节点与其值放入字典,字典作为参数传入 :return: - ''' - temp_dict = {} - temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang520'] = self.compensation_value_x - temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang521'] = self.compensation_value_y - print("测试补偿能够执行") - temp = py2opcua.Py2opcua() - _logger.info(temp) - temp.connect() - temp.write(temp_dict) - temp.disconnect() - - def check_compensation_before_up(self): - temp_value = self.env['mrp.workorder'].getcenter() - _logger.info("====================================================================================") - _logger.info(temp_value) - if temp_value[0] == 0 or temp_value[1] != 0: + """ + try: temp_dict = {} - # temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang520'] = temp_value[0] - temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang520'] = 111 - temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang521'] = 111 - # temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC.hongbianliang521'] = temp_value[1] - print("测试补偿能够执行") + temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC2.hongbianliang550'] = self.compensation_value_x + temp_dict['ns=1;s=Project_Default.Group1.Mitsubishi_NC2.hongbianliang551'] = self.compensation_value_y temp = py2opcua.Py2opcua() - _logger.info(temp) - temp.connect() + # temp.connect() temp.write(temp_dict) - temp.disconnect() + self.button_compensation_state = True + # temp.disconnect() + except Exception as e: + _logger.info("=====================================", e) + raise UserError('补偿值获取失败,或机床未连接,请检查') + def get__state(self): + pay_time = str(datetime.now()) + json = { + 'params': { + 'model_name': 'jikimo.process.order', + 'field_name': 'name', + 'default_code': 'PO-2022-1207-0020', + 'state': '待付款', + # 'pay_time': pay_time, + # 'get_order_sf': 21, + }, + } + # res_str = json.dumps(vals) + url = 'https://bfm.cs.jikimo.com/api/get/state' + requests.post(url, json=json, data=None) + def process_control(self): - def test(self, barcode): - # 托盘对象 - tray = self.env('sf.tray').search("code", "=", barcode) - product = tray.product_id \ No newline at end of file + if self.routing_type == '获取CNC加工程序' and self.state == '进行中': + json = { + 'params': { + 'model_name': 'jikimo.process.order', + 'field_name': 'name', + 'default_code': 'PO-2022-1123-0014', + 'state': '加工中', + }, + } + url = 'https://bfm.cs.jikimo.com/api/get/state' + requests.post(url, json=json, data=None) diff --git a/sf_machine_connect/models/ftp_operate.py b/sf_machine_connect/models/ftp_operate.py index 052c6e1c..18838684 100644 --- a/sf_machine_connect/models/ftp_operate.py +++ b/sf_machine_connect/models/ftp_operate.py @@ -2,13 +2,18 @@ import os from ftplib import FTP + class FTP_P(FTP): + """ + 重写FTP类,重写dirs方法 + """ + def dirs(self, *args): - '''List a directory in long form. + """List a directory in long form. By default list current directory to stdout. Optional last argument is callback function; all non-empty arguments before it are concatenated to the - LIST command. (This *should* only be used for a pathname.)''' + LIST command. (This *should* only be used for a pathname.)""" cmd = 'LIST' templist = [] tempdic = {} @@ -19,7 +24,6 @@ class FTP_P(FTP): if arg: cmd = cmd + (' ' + arg) self.retrlines(cmd, templist.append) - # print(templist) # 处理返回结果,只需要目录名称 r_files = [file.split(" ")[-1] for file in templist] tempdic['name'] = [file for file in r_files if file != "." and file != ".."] @@ -27,13 +31,14 @@ class FTP_P(FTP): return tempdic # return [file for file in r_files if file != "." and file != ".."] -# FTP接口类 -class FtpController(): - ''' +# FTP接口类 +class FtpController: + """ 这是ftp接口类,在类初始化的时候就连接了ftp服务器,能否成功连接有反馈。 类中定义了两个接口:上传接口和删除接口 - ''' + """ + # 三菱机床连接 def __init__(self, host="192.168.2.158", port=8080, username="MITSUBISHI", password="CNC"): self.host = host @@ -42,47 +47,41 @@ class FtpController(): self.password = password ftp = FTP_P() # self.ftp.set_debuglevel(2) #打开调试级别2,显示详细信息 - ftp.set_pasv(0) #0主动模式 1 #被动模式 + ftp.set_pasv(0) # 0主动模式 1 #被动模式 try: ftp.connect(self.host, self.port) ftp.login(self.username, self.password) print("连接成功") self.ftp = ftp - except: - print("连接失败") + except Exception as e: + print("连接失败" + str(e)) # 试验接口 def prin(self): print("这是试验接口") - # 试验ftp服务器连接 - # def connect(self, host="127.0.0.1", port=2121, username="admin", password="123456"): - # ftp = FTP_P() - # try: - # ftp.connect(host, port) - # ftp.login(username, password) - # print("连接成功") - # ftp1 = ftp - # return ftp1 - # except: - # print("连接失败") - - # 三菱代码下发 def upload_file(self, remotepath='/(192,168,199,2)/DS/Z4.5.NC', localpath='D:/ftp/up/Z4.5.NC'): - ''' + """ 第一个是要上传到ftp服务器路径下的文件,第二个是本地要上传的的路径文件 :param remotepath: 上传和下载都需要设置工作目录,注意只能使用文件名,不能有路径中的冒号 :param localpath: :return: - ''' + """ bufsize = 1024 - fp = open(localpath, 'rb') - self.ftp.storbinary('STOR ' + remotepath, fp, bufsize) - fp.close() - # return "上传成功" + # fp = open(localpath, 'rb') + # self.ftp.storbinary('STOR ' + remotepath, fp, bufsize) + # fp.close() + with open(localpath, mode='rb') as file: + self.ftp.storbinary('STOR ' + remotepath, file, bufsize) + def delAllfile(self, ftppath): + """ + 删除ftp服务器端全部文件 + :param ftppath: + :return: + """ dir_res = [] try: print(ftppath) @@ -106,13 +105,13 @@ class FtpController(): # print("删除FTP目录:" + ftppath + "下存在文件:" + f) # ftp.delete(f) except Exception as e: - raise e + print("删除失败" + str(e)) - # 删除远端ftp文件 # 出现550 not found file是路径不对 - # def del_file(self, delpath='./YIN.NC'): def del_file(self, delpath='/(192,168,199,2)/DS/Z4.5.NC'): - self.ftp.delete(delpath) # 删除远程文件 - - - + """ + 删除ftp服务器端指定文件 + :param delpath: + :return: + """ + self.ftp.delete(delpath) diff --git a/sf_machine_connect/models/py2opcua.py b/sf_machine_connect/models/py2opcua.py index 992f3f72..479fa91c 100644 --- a/sf_machine_connect/models/py2opcua.py +++ b/sf_machine_connect/models/py2opcua.py @@ -2,22 +2,35 @@ from opcua import ua, Client class Py2opcua: + """ + 将三元检测补偿值写入opcua服务器 + """ def __init__(self, url='opc.tcp://192.168.2.99:4840'): self.client = Client(url) - def connect(self): - - try: - # 连接客户端 - self.client.connect() - print("opcua服务器连接成功,可以写入") - return self.client - except: - print("opcua服务器连接失败,请检查") + # 连接客户端 + # def connect(self): + # try: + # self.client.connect() + # print("opcua服务器连接成功,可以写入") + # return self.client + # except Exception as e: + # print("opcua服务器连接失败,请检查" + str(e)) def write(self, temp_dict): - temp_dict = temp_dict + """ + 补偿值写入方法,参数是一个字典,键是节点名,值是补偿值 + :param temp_dict: + :return: + """ + # try: + self.client.connect() + # print("opcua服务器连接成功,可以写入") + # return self.client + # except Exception as e: + # print("opcua服务器连接失败,请检查" + str(e)) + # temp_dict = temp_dict temp_list = list(temp_dict.items()) for i in range(len(temp_list)): # 寻找节点上的变量 @@ -25,8 +38,9 @@ class Py2opcua: # var.set_value(ua.Variant(1.234, ua.VariantType.Float)) # 通过set_value写值 var.set_value(ua.Variant(temp_list[i][1], ua.VariantType.Double)) - print("%s 已写入" % var.get_value()) - - def disconnect(self): - # 断开连接 + # print("%s 已写入" % var.get_value()) self.client.disconnect() + + # 断开连接 + # def disconnect(self): + # self.client.disconnect() diff --git a/sf_machine_connect/static/src/css/many2one_field.scss b/sf_machine_connect/static/src/css/many2one_field.scss new file mode 100644 index 00000000..00b8d1ae --- /dev/null +++ b/sf_machine_connect/static/src/css/many2one_field.scss @@ -0,0 +1,13 @@ +.o_form_view:not(.o_field_highlight) { + .o_field_many2one_selection { + .o_external_button, .o_dropdown_button { + visibility: hidden; + } + + &:hover, &:focus-within { + .o_external_button, .o_dropdown_button { + visibility: visible; + } + } + } +} diff --git a/sf_machine_connect/static/src/js/test.js b/sf_machine_connect/static/src/js/test.js new file mode 100644 index 00000000..1f1c1d58 --- /dev/null +++ b/sf_machine_connect/static/src/js/test.js @@ -0,0 +1,82 @@ +/** @odoo-module **/ + +import { browser } from "@web/core/browser/browser"; +import { Dialog } from "@web/core/dialog/dialog"; +import { _lt } from "@web/core/l10n/translation"; +import { useChildRef, useOwnedDialogs, useService } from "@web/core/utils/hooks"; +import { sprintf } from "@web/core/utils/strings"; +import { isMobileOS } from "@web/core/browser/feature_detection"; +import * as BarcodeScanner from "@web/webclient/barcode/barcode_scanner"; + +const {xml, Component} = owl; +import { standardFieldProps } from "@web/views/fields/standard_field_props"; +// Import the registry +import {registry} from "@web/core/registry"; + + +export class CodeField extends Component { + setup() { + super.setup(); + } + async onBarcodeBtnClick() { + const barcode = await BarcodeScanner.scanBarcode(); + if (barcode) { + await this.onBarcodeScanned(barcode); + if ("vibrate" in browser.navigator) { + browser.navigator.vibrate(100); + } + } else { + this.notification.add(this.env._t("Please, scan again !"), { + type: "warning", + }); + } + } + async search(barcode) { + const results = await this.orm.call("sf.tray", "name_search", [code], { + name: barcode, + args: this.getDomain(), + operator: "ilike", + limit: 2, // If one result we set directly and if more than one we use normal flow so no need to search more + context: this.context, + }); + return results.map((result) => { + const [id, displayName] = result; + return { + id, + name: displayName, + }; + }); + } + async onBarcodeScanned(barcode) { + const results = await this.search(barcode); + const records = results.filter((r) => !!r.id); + if (records.length === 1) { + this.update([{ id: records[0].id, name: records[0].name }]); + } else { + const searchInput = this.autocompleteContainerRef.el.querySelector("input"); + searchInput.value = barcode; + searchInput.dispatchEvent(new Event("input")); + if (this.env.isSmall) { + searchInput.click(); + } + } + } +} + +CodeField.template = xml` + - - - - - - - - - - - - - mrp.production - -
- - - - - - -
-
-
- - - 数据采集 - ftp.client - list,form,kanban - -

- 这是我们的数据采集与程序管理页面! -

-
-
- - 扫码 - mrp.production - list,form,kanban - -

- 这是我们的扫码页面! -

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sf_machine_connect/views/views.xml b/sf_machine_connect/views/views.xml deleted file mode 100644 index 6b4e447d..00000000 --- a/sf_machine_connect/views/views.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - sale.order.form.inherit - sf.machine_tool - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sf_machine_connect/views/views_test_barcode.xml b/sf_machine_connect/views/views_test_barcode.xml deleted file mode 100644 index c346ae36..00000000 --- a/sf_machine_connect/views/views_test_barcode.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - sale.order.form.inherit - mrp.workorder - - - - -
- - - - - \ No newline at end of file diff --git a/sf_machine_connect/views/workorder_button.xml b/sf_machine_connect/views/workorder_button.xml deleted file mode 100644 index 5e4c0d9d..00000000 --- a/sf_machine_connect/views/workorder_button.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - mrp.workcenter.view.kanban.inherit.mrpworkorder - mrp.workcenter - - - - - -
+ + + diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index 899e2126..9bf6f2b1 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -44,7 +44,6 @@ class ReSaleOrder(models.Model): product.model_machining_precision, product.materials_id.name), 'price_unit': product.list_price, - 'route_id': product.route_ids, 'product_uom_qty': item['number'] } return self.env['sale.order.line'].create(vals)