From 311c7c723aaa8158c4539c5198360d7c0badba4f Mon Sep 17 00:00:00 2001 From: gqh Date: Mon, 9 Jan 2023 23:04:53 +0800 Subject: [PATCH] sf1.0 --- sf_base/views/base_view.xml | 2 +- sf_bf_connect/controllers/controllers.py | 9 +- sf_dlm/__manifest__.py | 3 +- sf_dlm/data/tt.xml | 57 +++ sf_dlm/models/product_template.py | 86 +++-- sf_dlm/views/product_template_view.xml | 47 ++- sf_machine_connect/__init__.py | 1 + sf_machine_connect/__manifest__.py | 30 ++ sf_machine_connect/models/__init__.py | 3 + sf_machine_connect/models/data_collection.py | 44 +++ sf_machine_connect/models/ftp_client.py | 153 +++++++++ sf_machine_connect/models/ftp_operate.py | 118 +++++++ sf_machine_connect/models/py2opcua.py | 32 ++ sf_machine_connect/security/iot_security.xml | 20 ++ .../security/ir.model.access.csv | 2 + .../static/description/icon.png | Bin 0 -> 9677 bytes .../static/src/css/MyWidget.css | 30 ++ sf_machine_connect/static/src/css/iot.css | 5 + .../static/src/xml/Barcode_Scan_template.xml | 94 +++++ sf_machine_connect/static/src/xml/Flush.xml | 10 + .../static/src/xml/MyComponent.xml | 27 ++ .../static/src/xml/MyWidget.xml | 4 + .../static/src/xml/PartnerOrderSummary2.xml | 32 ++ .../static/src/xml/barcodes.xml | 15 + .../src/xml/iot_scan_progress_template.xml | 17 + .../static/src/xml/many2one_field.xml | 17 + sf_machine_connect/static/src/xml/stack.xml | 17 + sf_machine_connect/views/Barcode_Scan.xml | 14 + .../views/SfWorkOrderBarcodes.xml | 15 + .../views/Stock_picking_Barcodes.xml | 18 + .../views/WorkCenterBarcodes.xml | 20 ++ sf_machine_connect/views/compensation.xml | 23 ++ sf_machine_connect/views/flush_template.xml | 23 ++ sf_machine_connect/views/ftp_button.xml | 19 + sf_machine_connect/views/machine_monitor.xml | 43 +++ 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/__manifest__.py | 2 +- sf_manufacturing/models/mrp_production.py | 4 +- sf_manufacturing/models/mrp_workcenter.py | 6 + sf_manufacturing/models/mrp_workorder.py | 325 +++++++++--------- sf_manufacturing/models/tray.py | 37 +- .../views/mrp_workcenter_views.xml | 2 +- sf_manufacturing/views/mrp_workorder_view.xml | 48 ++- sf_mrs_connect/controllers/controllers.py | 81 +++-- sf_mrs_connect/models/ftp_operate.py | 4 +- sf_mrs_connect/models/res_config_setting.py | 23 +- .../views/res_config_settings_views.xml | 41 ++- sf_sale/models/sale_order.py | 1 - 52 files changed, 1572 insertions(+), 331 deletions(-) create mode 100644 sf_dlm/data/tt.xml create mode 100644 sf_machine_connect/__init__.py create mode 100644 sf_machine_connect/__manifest__.py create mode 100644 sf_machine_connect/models/__init__.py create mode 100644 sf_machine_connect/models/data_collection.py create mode 100644 sf_machine_connect/models/ftp_client.py create mode 100644 sf_machine_connect/models/ftp_operate.py create mode 100644 sf_machine_connect/models/py2opcua.py create mode 100644 sf_machine_connect/security/iot_security.xml create mode 100644 sf_machine_connect/security/ir.model.access.csv create mode 100644 sf_machine_connect/static/description/icon.png create mode 100644 sf_machine_connect/static/src/css/MyWidget.css create mode 100644 sf_machine_connect/static/src/css/iot.css create mode 100644 sf_machine_connect/static/src/xml/Barcode_Scan_template.xml create mode 100644 sf_machine_connect/static/src/xml/Flush.xml create mode 100644 sf_machine_connect/static/src/xml/MyComponent.xml create mode 100644 sf_machine_connect/static/src/xml/MyWidget.xml create mode 100644 sf_machine_connect/static/src/xml/PartnerOrderSummary2.xml create mode 100644 sf_machine_connect/static/src/xml/barcodes.xml create mode 100644 sf_machine_connect/static/src/xml/iot_scan_progress_template.xml create mode 100644 sf_machine_connect/static/src/xml/many2one_field.xml create mode 100644 sf_machine_connect/static/src/xml/stack.xml create mode 100644 sf_machine_connect/views/Barcode_Scan.xml create mode 100644 sf_machine_connect/views/SfWorkOrderBarcodes.xml create mode 100644 sf_machine_connect/views/Stock_picking_Barcodes.xml create mode 100644 sf_machine_connect/views/WorkCenterBarcodes.xml create mode 100644 sf_machine_connect/views/compensation.xml create mode 100644 sf_machine_connect/views/flush_template.xml create mode 100644 sf_machine_connect/views/ftp_button.xml create mode 100644 sf_machine_connect/views/machine_monitor.xml create mode 100644 sf_machine_connect/views/purchase_barcode.xml create mode 100644 sf_machine_connect/views/sf_machine_connnect.xml create mode 100644 sf_machine_connect/views/views.xml create mode 100644 sf_machine_connect/views/views_test_barcode.xml create mode 100644 sf_machine_connect/views/workorder_button.xml diff --git a/sf_base/views/base_view.xml b/sf_base/views/base_view.xml index 7d4854d3..ff85bfda 100644 --- a/sf_base/views/base_view.xml +++ b/sf_base/views/base_view.xml @@ -359,7 +359,7 @@
-
diff --git a/sf_bf_connect/controllers/controllers.py b/sf_bf_connect/controllers/controllers.py index 5227592f..27fb0758 100644 --- a/sf_bf_connect/controllers/controllers.py +++ b/sf_bf_connect/controllers/controllers.py @@ -49,6 +49,7 @@ class Sf_Bf_Connect(http.Controller): logging.info('product:%s' % product) bom_data = request.env['mrp.bom'].with_user(request.env.ref("base.user_admin")).get_bom(product) logging.info('bom_data:%s' % bom_data) + i += 1 if bom_data: bom = request.env['mrp.bom'].with_user(request.env.ref("base.user_admin")).bom_create(product, 'normal', @@ -60,7 +61,7 @@ class Sf_Bf_Connect(http.Controller): self_machining_embryo = request.env['product.template'].sudo().no_bom_product_create( self_machining_id, item, - order_id, 'self_machining') + order_id, 'self_machining', i) # 创建胚料的bom self_machining_bom = request.env['mrp.bom'].with_user( request.env.ref("base.user_admin")).bom_create( @@ -79,7 +80,8 @@ class Sf_Bf_Connect(http.Controller): outsource_embryo = request.env['product.template'].sudo().no_bom_product_create(outsource_id, item, order_id, - 'subcontract') + 'subcontract', + i) # 创建胚料的bom outsource_bom = request.env['mrp.bom'].with_user(request.env.ref("base.user_admin")).bom_create( outsource_embryo, @@ -95,14 +97,13 @@ class Sf_Bf_Connect(http.Controller): purchase_embryo = request.env['product.template'].sudo().no_bom_product_create(purchase_id, item, order_id, - 'purchase') + 'purchase', i) # 产品配置bom product_bom_purchase = request.env['mrp.bom'].with_user( request.env.ref("base.user_admin")).bom_create(product, 'normal', False) product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has( purchase_embryo) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) - i += 1 res['factory_order_no'] = order_id.name except Exception as e: logging.info('get_bfm_process_order_list error:%s' % e) diff --git a/sf_dlm/__manifest__.py b/sf_dlm/__manifest__.py index da6dba4b..32d84919 100644 --- a/sf_dlm/__manifest__.py +++ b/sf_dlm/__manifest__.py @@ -10,9 +10,10 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['mrp', 'base', 'sf_manufacturing'], + 'depends': ['mrp', 'base', 'sf_manufacturing', 'purchase', 'mrp_subcontracting', 'uom'], 'data': [ 'data/product_data.xml', + 'data/uom_data.xml', 'views/product_template_view.xml' ], 'demo': [ diff --git a/sf_dlm/data/tt.xml b/sf_dlm/data/tt.xml new file mode 100644 index 00000000..847e6a80 --- /dev/null +++ b/sf_dlm/data/tt.xml @@ -0,0 +1,57 @@ + + + + + CNC加工产品模板 + + delivery + product + false + + + + False + + + + 胚料 + 胚料 + + + + 自加工 + + delivery + product + false + + + + False + + + + 外协 + + delivery + product + false + + + + False + + + + 采购 + + delivery + product + false + + + + False + + + \ No newline at end of file diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index f80f0437..13321df6 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' @@ -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('模型文件') # 胚料的库存路线设置 @@ -72,16 +82,18 @@ class ResProductTemplate(models.Model): item['model_height'] + model_type.embryo_tolerance), 'model_type_id': 1, # 'model_machining_precision': item['model_machining_precision'], - 'model_processing_panel': 'A', + 'model_processing_panel': 'R', 'model_machining_precision': '±0.10mm', + '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,18 +106,17 @@ 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', 'description': '模型文件', 'name': name @@ -113,7 +124,7 @@ class ResProductTemplate(models.Model): 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, @@ -158,32 +170,32 @@ class ResProductTemplate(models.Model): 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 +256,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 +267,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_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index c563f728..652b05a3 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -6,13 +6,13 @@ product.template - - - - + + + + - + @@ -36,18 +36,31 @@ - - - - - - - - - - - + + + diff --git a/sf_machine_connect/__init__.py b/sf_machine_connect/__init__.py new file mode 100644 index 00000000..9a7e03ed --- /dev/null +++ b/sf_machine_connect/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/sf_machine_connect/__manifest__.py b/sf_machine_connect/__manifest__.py new file mode 100644 index 00000000..b74437dc --- /dev/null +++ b/sf_machine_connect/__manifest__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': 'sf_machine_connect', + 'version': '1.0', + 'summary': '智能工厂机床连接模块', + 'sequence': 10, + 'description': """ +这是一个模块 +==================== + """, + 'category': 'Tools', + 'depends': ['sf_base', 'sf_manufacturing', 'barcodes', ], + 'data': [ + # 定义权限组放在最上面 + # 权限组 + "security/ir.model.access.csv", + 'views/compensation.xml', + 'views/ftp_button.xml', + 'views/SfWorkOrderBarcodes.xml', + 'views/WorkCenterBarcodes.xml', + 'views/Stock_picking_Barcodes.xml', + 'views/machine_monitor.xml', + ], + + 'installable': True, + 'application': True, + # 'auto_install': False, + 'license': 'LGPL-3', +} diff --git a/sf_machine_connect/models/__init__.py b/sf_machine_connect/models/__init__.py new file mode 100644 index 00000000..30087503 --- /dev/null +++ b/sf_machine_connect/models/__init__.py @@ -0,0 +1,3 @@ +from . import ftp_client +from . import ftp_operate +from . import py2opcua diff --git a/sf_machine_connect/models/data_collection.py b/sf_machine_connect/models/data_collection.py new file mode 100644 index 00000000..8f860c37 --- /dev/null +++ b/sf_machine_connect/models/data_collection.py @@ -0,0 +1,44 @@ +# -*- 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 new file mode 100644 index 00000000..9f943dca --- /dev/null +++ b/sf_machine_connect/models/ftp_client.py @@ -0,0 +1,153 @@ +# -*- 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 +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 +# ---------------------------------------------------------- + +class FtpButton(models.Model): + _inherit = 'sf.cnc.processing' + + def pri(self): + print('11111111111111111') + s = self.cnc_id + s1 = self.cnc_id._filestore() + print(s1) + v = self.cnc_id.display_name + a = self.cnc_id.datas + print(v) + print(a) + 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) + + # 此方法不走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) + + + with open(file_path_local, mode='wb+') as file: + file.write(datas) + + # file = open(file_path_local, 'wb+') + # file.write(datas) + # file.close() + + # 存在本地的文件下发到机床 + ftp.upload_file(remotepath=file_path_remote, localpath=file_path_local) + + +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) + + +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) + tool_num = fields.Integer('当前刀具', readonly=True) + program = fields.Char('当前程序', readonly=True) + + +class WorkCenterBarcode(models.Model): + """ + 扫码托盘码可查到制造订单,由制造订单查工单 + """ + _inherit = "mrp.workorder" + compensation_value_x = fields.Float(string='X轴补偿值') + compensation_value_y = fields.Float(string='Y轴补偿值') + + 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: + 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 = py2opcua.Py2opcua() + _logger.info(temp) + temp.connect() + temp.write(temp_dict) + temp.disconnect() + + + + + def test(self, barcode): + # 托盘对象 + tray = self.env('sf.tray').search("code", "=", barcode) + product = tray.product_id \ No newline at end of file diff --git a/sf_machine_connect/models/ftp_operate.py b/sf_machine_connect/models/ftp_operate.py new file mode 100644 index 00000000..052c6e1c --- /dev/null +++ b/sf_machine_connect/models/ftp_operate.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +import os +from ftplib import FTP + +class FTP_P(FTP): + def dirs(self, *args): + '''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.)''' + cmd = 'LIST' + templist = [] + tempdic = {} + func = None + if args[-1:] and type(args[-1]) != type(''): + args, func = args[:-1], args[-1] + for arg in args: + 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 != ".."] + # 去除. .. + return tempdic + # return [file for file in r_files if file != "." and file != ".."] + +# FTP接口类 +class FtpController(): + + ''' + 这是ftp接口类,在类初始化的时候就连接了ftp服务器,能否成功连接有反馈。 + 类中定义了两个接口:上传接口和删除接口 + ''' + # 三菱机床连接 + def __init__(self, host="192.168.2.158", port=8080, username="MITSUBISHI", password="CNC"): + self.host = host + self.port = port + self.username = username + self.password = password + ftp = FTP_P() + # self.ftp.set_debuglevel(2) #打开调试级别2,显示详细信息 + 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("连接失败") + + # 试验接口 + 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 "上传成功" + + def delAllfile(self, ftppath): + dir_res = [] + try: + print(ftppath) + try: + self.ftp.cwd(ftppath) + except Exception as e: + print("进入ftp目录失败" + str(e)) + self.ftp.dir('.', dir_res.append) # 对当前目录进行dir(),将结果放入列表 + print(dir_res) + # for i in dir_res: + # if i.startswith("d"): + # dirName = i.split(" ")[-1] + # print("开始删除" + dirName + "文件夹") + # delAllfile(ftp, ftp.pwd() + "/" + dirName) + # ftp.cwd('..') + # print(ftppath + "/" + dirName) + # ftp.rmd(ftppath + '/' + dirName) + # else: + # filelist = ftp.getfiles(ftppath) + # for f in filelist: + # print("删除FTP目录:" + ftppath + "下存在文件:" + f) + # ftp.delete(f) + except Exception as e: + raise 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) # 删除远程文件 + + + diff --git a/sf_machine_connect/models/py2opcua.py b/sf_machine_connect/models/py2opcua.py new file mode 100644 index 00000000..992f3f72 --- /dev/null +++ b/sf_machine_connect/models/py2opcua.py @@ -0,0 +1,32 @@ +from opcua import ua, Client + + +class Py2opcua: + + 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 write(self, temp_dict): + temp_dict = temp_dict + temp_list = list(temp_dict.items()) + for i in range(len(temp_list)): + # 寻找节点上的变量 + var = self.client.get_node(temp_list[i][0]) + # 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): + # 断开连接 + self.client.disconnect() diff --git a/sf_machine_connect/security/iot_security.xml b/sf_machine_connect/security/iot_security.xml new file mode 100644 index 00000000..c673200b --- /dev/null +++ b/sf_machine_connect/security/iot_security.xml @@ -0,0 +1,20 @@ + + + + + + IoT Box multi company rule + + + ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + + + IoT Device multi company rule + + + ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + + + diff --git a/sf_machine_connect/security/ir.model.access.csv b/sf_machine_connect/security/ir.model.access.csv new file mode 100644 index 00000000..53d13813 --- /dev/null +++ b/sf_machine_connect/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_ftp_client,ftp.client,model_ftp_client,base.group_user,1,1,1,1 diff --git a/sf_machine_connect/static/description/icon.png b/sf_machine_connect/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d5c714782d7ad51c88c97799582770a255092316 GIT binary patch literal 9677 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 R_cz+O_t!K1rx4+${|`2@GEe{j literal 0 HcmV?d00001 diff --git a/sf_machine_connect/static/src/css/MyWidget.css b/sf_machine_connect/static/src/css/MyWidget.css new file mode 100644 index 00000000..12e077c3 --- /dev/null +++ b/sf_machine_connect/static/src/css/MyWidget.css @@ -0,0 +1,30 @@ +.o_int_colorpicker { + .o_color_pill { + display: inline-block; + height: 25px; + width: 25px; + margin: 4px; + border-radius: 25px; + position: relative; + @for $size from 1 through length($o-colors) { + &.o_color_#{$size - 1} { + background-color: nth($o-colors, $size); + &:not(.readonly):hover { + transform: scale(1.2); + transition: 0.3s; + cursor: pointer; + } + &.active:after{ + content: "\f00c"; + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + color: #fff; + position: absolute; + padding: 4px; + font-size: 16px; + } + } + } + } +} \ No newline at end of file diff --git a/sf_machine_connect/static/src/css/iot.css b/sf_machine_connect/static/src/css/iot.css new file mode 100644 index 00000000..2aab2fe1 --- /dev/null +++ b/sf_machine_connect/static/src/css/iot.css @@ -0,0 +1,5 @@ +.o_button_iot { + min-width: 120px; + min-height: 40px; + margin-left: 50px; +} diff --git a/sf_machine_connect/static/src/xml/Barcode_Scan_template.xml b/sf_machine_connect/static/src/xml/Barcode_Scan_template.xml new file mode 100644 index 00000000..0b5dec78 --- /dev/null +++ b/sf_machine_connect/static/src/xml/Barcode_Scan_template.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sf_machine_connect/static/src/xml/Flush.xml b/sf_machine_connect/static/src/xml/Flush.xml new file mode 100644 index 00000000..8fab7c9e --- /dev/null +++ b/sf_machine_connect/static/src/xml/Flush.xml @@ -0,0 +1,10 @@ + + + +
+

+ 显示累加字符串:aaaaaabbb +

+
+
+
\ No newline at end of file diff --git a/sf_machine_connect/static/src/xml/MyComponent.xml b/sf_machine_connect/static/src/xml/MyComponent.xml new file mode 100644 index 00000000..ae289933 --- /dev/null +++ b/sf_machine_connect/static/src/xml/MyComponent.xml @@ -0,0 +1,27 @@ + + + +
+
+

欢迎登陆页面!

+

这是一个超大屏幕(Jumbotron)的实例。

+

+ 学习更多 +

+
+
+ + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/sf_machine_connect/static/src/xml/MyWidget.xml b/sf_machine_connect/static/src/xml/MyWidget.xml new file mode 100644 index 00000000..00a6b92c --- /dev/null +++ b/sf_machine_connect/static/src/xml/MyWidget.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sf_machine_connect/static/src/xml/PartnerOrderSummary2.xml b/sf_machine_connect/static/src/xml/PartnerOrderSummary2.xml new file mode 100644 index 00000000..dc9b67a0 --- /dev/null +++ b/sf_machine_connect/static/src/xml/PartnerOrderSummary2.xml @@ -0,0 +1,32 @@ + + + + +
+ + + + + + + + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/sf_machine_connect/static/src/xml/barcodes.xml b/sf_machine_connect/static/src/xml/barcodes.xml new file mode 100644 index 00000000..4336852b --- /dev/null +++ b/sf_machine_connect/static/src/xml/barcodes.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/sf_machine_connect/static/src/xml/iot_scan_progress_template.xml b/sf_machine_connect/static/src/xml/iot_scan_progress_template.xml new file mode 100644 index 00000000..9360c22b --- /dev/null +++ b/sf_machine_connect/static/src/xml/iot_scan_progress_template.xml @@ -0,0 +1,17 @@ + + +
+

Range(s) to scan

+
    +
    + + Add +
    + +
    +

    +

    +
      +
    +
+
diff --git a/sf_machine_connect/static/src/xml/many2one_field.xml b/sf_machine_connect/static/src/xml/many2one_field.xml new file mode 100644 index 00000000..8ed9b397 --- /dev/null +++ b/sf_machine_connect/static/src/xml/many2one_field.xml @@ -0,0 +1,17 @@ + + + + + + + + +
+
+ + + +
+ + + + 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 new file mode 100644 index 00000000..6b4e447d --- /dev/null +++ b/sf_machine_connect/views/views.xml @@ -0,0 +1,45 @@ + + + + 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 new file mode 100644 index 00000000..c346ae36 --- /dev/null +++ b/sf_machine_connect/views/views_test_barcode.xml @@ -0,0 +1,15 @@ + + + + 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 new file mode 100644 index 00000000..5e4c0d9d --- /dev/null +++ b/sf_machine_connect/views/workorder_button.xml @@ -0,0 +1,18 @@ + + + + + + mrp.workcenter.view.kanban.inherit.mrpworkorder + mrp.workcenter + + + + + +
+ + + + + +
+
+
@@ -109,13 +107,11 @@ -
@@ -226,7 +222,7 @@
@@ -268,7 +264,7 @@
@@ -277,11 +273,11 @@
diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index 76fc34c5..ec1e9491 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -20,44 +20,55 @@ class Sf_Mrs_Connect(http.Controller): """ logging.info('get_cnc_processing_create:%s' % kw) try: + res = {'status': 1, 'message': '成功'} datas = request.httprequest.data ret = json.loads(datas) ret = json.loads(ret['result']) - for obj in ret: - cnc = request.env['sf.cnc.processing'].with_user( - request.env.ref("base.user_admin")).cnc_processing_create(obj) - # # 从ftp拉取对应的文件 - model_code = cnc.workorder_id.product_id.barcode - processing_panel = cnc.workorder_id.processing_panel - logging.info('model_code:%s' % model_code) - server_dir = cnc.with_user(request.env.ref("base.user_admin")).download_file_tmp(model_code, - processing_panel) - # cnc_file_path = os.path.join('/', server_dir, cnc.program_name + '.nc') - # logging.info('cnc_file_path:%s' % cnc_file_path) - # cnc.with_user(request.env.ref("base.user_admin")).write_file(cnc_file_path, cnc) - logging.info('server_dir:%s' % server_dir) - for root, dirs, files in os.walk(server_dir): - for f in files: - logging.info('f:%s' % f) - logging.info('f[0]:%s' % f.split('.')[0]) - if os.path.splitext(f)[1] == ".pdf": - full_path = os.path.join(server_dir, root, f) - logging.info('pdf:%s' % full_path) - if full_path != False: - if not cnc.workorder_id.cnc_worksheet: - cnc.workorder_id.cnc_worksheet = base64.b64encode(open(full_path, 'rb').read()) - else: - logging.info('break:%s' % 'break') - continue - else: - logging.info('cnc.program_name:%s' % cnc.program_name) - if cnc.program_name == f.split('.')[0]: - logging.info('f[0]:%s' % f[0]) - cnc_file_path = os.path.join(server_dir, root, f) - logging.info('cnc_file_path:%s' % cnc_file_path) - cnc.with_user(request.env.ref("base.user_admin")).write_file(cnc_file_path, cnc) - else: - continue + # 查询状态为进行中且类型为获取CNC加工程序的工单 + cnc_workorder = self.env['mrp.workorder'].search([('production_id.name', '=', ret['production_order_no']), + ('routing_type', '=', '获取CNC加工程序')]) + if cnc_workorder: + # 拉取所有加工面的程序文件 + # i = 1 + for r in ret['processing_panel']: + download_state = request.env['sf.cnc.processing'].with_user( + request.env.ref("base.user_admin")).download_file_tmp( + ret['folder_name'], r) + logging.info('download_state:%s' % download_state) + # i += 1 + if download_state == False: + res = {'status': -2, 'message': 'cnc文件拉取失败'} + return json.JSONEncoder().encode(res) + request.env['sf.cnc.processing'].with_user( + request.env.ref("base.user_admin")).cnc_processing_create(ret) + return json.JSONEncoder().encode(res) + else: + res = {'status': 0, 'message': '该制造订单暂未开始'} + return json.JSONEncoder().encode(res) + except Exception as e: + res = {'status': -1, 'message': '系统解析失败'} + logging.info('get_cnc_processing_create error:%s' % e) + return json.JSONEncoder().encode(res) + + @http.route('/api/cnc_processing/update_state', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_cnc_processing_state(self, **kw): + """ + 获取mrs下发的编程单的状态 + :param kw: + :return: + """ + logging.info('get_cnc_processing_state:%s' % kw) + try: + res = {'status': 1, 'message': '成功'} + datas = request.httprequest.data + ret = json.loads(datas) + ret = json.loads(ret['result']) + cnc_processing = request.env['sf.cnc.processing'].with_user( + request.env.ref("base.user_admin")).cnc_processing_create(ret['programming_list'], + ret['production_order_no']) except Exception as e: + res = {'status': -1, 'message': '系统解析失败'} logging.info('get_cnc_processing_create error:%s' % e) + return json.JSONEncoder().encode(res) diff --git a/sf_mrs_connect/models/ftp_operate.py b/sf_mrs_connect/models/ftp_operate.py index 655c50e6..316ee43d 100644 --- a/sf_mrs_connect/models/ftp_operate.py +++ b/sf_mrs_connect/models/ftp_operate.py @@ -15,7 +15,7 @@ class FtpController(): ftp = FTP() - def __init__(self, host="192.168.50.202", port=21, username="ftpuser", password="123456"): + def __init__(self, host, port, username, password): try: self.ftp.connect(host, port) self.ftp.login(username, password) @@ -34,7 +34,7 @@ class FtpController(): if file.find(".") != -1: self.download_file(server, file) else: - return + return False # 下载指定目录下的指定文件 def download_file(self, serverfile, remotefile): diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index fec87d75..dadb7de5 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -12,8 +12,12 @@ class ResConfigSettings(models.TransientModel): _inherit = 'res.config.settings' token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003') - sf_secret_key = fields.Char(string='密钥', default= 'wBmxej38OkErKhD6') - sf_url = fields.Char(string='访问地址', default= 'https://sf.cs.jikimo.com') + sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6') + sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com') + ftp_host = fields.Char(string='FTP的ip') + ftp_port = fields.Char(string='FTP端口') + ftp_user = fields.Char(string='FTP用户') + ftp_password = fields.Char(string='FTP密码') def sf_all_sync(self): self.env['sf.production.materials'].sync_all_production_materials() @@ -40,8 +44,6 @@ class ResConfigSettings(models.TransientModel): _logger.info("同步资源库刀具") # self.env['sf.processing.order'].sync_all_processing_order() - - @api.model def get_values(self): """ @@ -53,11 +55,19 @@ class ResConfigSettings(models.TransientModel): token = config.get_param('token', default='') sf_secret_key = config.get_param('sf_secret_key', default='') sf_url = config.get_param('sf_url', default='') + ftp_host = config.get_param('ftp_host', default='') + ftp_port = config.get_param('ftp_port', default='') + ftp_user = config.get_param('ftp_user', default='') + ftp_password = config.get_param('ftp_password', default='') values.update( token=token, sf_secret_key=sf_secret_key, sf_url=sf_url, + ftp_host=ftp_host, + ftp_port=ftp_port, + ftp_user=ftp_user, + ftp_password=ftp_password ) return values @@ -67,4 +77,7 @@ class ResConfigSettings(models.TransientModel): ir_config.set_param("token", self.token or "") ir_config.set_param("sf_secret_key", self.sf_secret_key or "") ir_config.set_param("sf_url", self.sf_url or "") - + ir_config.set_param("ftp_host", self.ftp_host or "") + ir_config.set_param("ftp_port", self.ftp_port or "") + ir_config.set_param("ftp_user", self.ftp_user or "") + ir_config.set_param("ftp_password", self.ftp_password or "") diff --git a/sf_mrs_connect/views/res_config_settings_views.xml b/sf_mrs_connect/views/res_config_settings_views.xml index d650d0f3..7bc7f2ad 100644 --- a/sf_mrs_connect/views/res_config_settings_views.xml +++ b/sf_mrs_connect/views/res_config_settings_views.xml @@ -14,22 +14,49 @@
-
+
+
-
-
+
+
+
+

FTP参数配置

+
-
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)