diff --git a/jikimo_workorder_exception/__init__.py b/jikimo_workorder_exception/__init__.py new file mode 100644 index 00000000..c3d410ea --- /dev/null +++ b/jikimo_workorder_exception/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import controllers diff --git a/jikimo_workorder_exception/__manifest__.py b/jikimo_workorder_exception/__manifest__.py new file mode 100644 index 00000000..4c63ed6d --- /dev/null +++ b/jikimo_workorder_exception/__manifest__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': '机企猫 工单异常记录', + 'version': '1.0', + 'summary': '记录工单的异常日志', + 'sequence': 1, + 'category': 'sf', + 'website': 'https://www.sf.jikimo.com', + 'depends': ['sf_manufacturing', 'sf_mrs_connect'], + 'data': [ + 'views/mrp_workorder_views.xml', + 'security/ir.model.access.csv', + ], + 'demo': [ + ], + 'license': 'LGPL-3', + 'installable': True, + 'application': False, + 'auto_install': False, +} diff --git a/jikimo_workorder_exception/controllers/__init__.py b/jikimo_workorder_exception/controllers/__init__.py new file mode 100644 index 00000000..deec4a8b --- /dev/null +++ b/jikimo_workorder_exception/controllers/__init__.py @@ -0,0 +1 @@ +from . import main \ No newline at end of file diff --git a/jikimo_workorder_exception/controllers/main.py b/jikimo_workorder_exception/controllers/main.py new file mode 100644 index 00000000..6a17f958 --- /dev/null +++ b/jikimo_workorder_exception/controllers/main.py @@ -0,0 +1,89 @@ +from odoo import http, fields +from odoo.http import request +import json +import logging +from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect +from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect + +_logger = logging.getLogger(__name__) + +class WorkorderExceptionConroller(http.Controller): + + @http.route('/AutoDeviceApi/BillError', type='json', auth='public', methods=['GET', 'POST'], csrf=False, + cors="*") + def workder_exception(self, **kw): + """ + 记录工单异常 + :param kw: + :return: + """ + _logger.info('workder_exception:%s' % kw) + try: + res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''} + datas = request.httprequest.data + ret = json.loads(datas)['Datas'] + if not ret.get('RfidCode') or not ret.get('ErrorType'): + res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'} + return json.JSONEncoder().encode(res) + + # 通过RfidCode获取就绪的CNC工单 + workorder = request.env['mrp.workorder'].sudo().search([ + ('rfid_code', '=', ret['RfidCode']), + ('routing_type', '=', 'CNC加工'), + ]) + if not workorder: + res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'} + return json.JSONEncoder().encode(res) + + # 创建工单异常记录,关联工单 + request.env['jikimo.workorder.exception'].sudo().create({ + 'workorder_id': workorder.id, + 'exception_code': ret.get('ErrorType'), + 'exception_content': ret.get('Error', '') + }) + + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + _logger.info('workder_exception error:%s' % e) + return json.JSONEncoder().encode(res) + + +class SfMrsConnectController(Sf_Mrs_Connect): + + @http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_cnc_processing_create(self, **kw): + """ + 更新工单异常记录【'YC001', 'YC004'】 + """ + res = super(SfMrsConnectController, self).get_cnc_processing_create(**kw) + # 如果有未完成的YC0001、YC0004异常记录,则标记为完成 + res = json.loads(res) + _logger.info('已进入工单异常:%s' % res) + if res.get('production_ids'): + try: + productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))]) + if productions.workorder_ids: + productions.workorder_ids.handle_exception(['YC0001', 'YC0004']) + except Exception as e: + _logger.info('更新工单异常记录失败:%s' % e) + return json.JSONEncoder().encode(res) + +class ManufactruingController(Manufacturing_Connect): + + @http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def button_Work_START(self, **kw): + """ + 更新工单异常记录【'YC0002', 'YC0003'】 + """ + res = super(ManufactruingController, self).button_Work_START(**kw) + res = json.loads(res) + _logger.info('已进入工单异常:%s' % res) + if res.get('workorder_id'): + try: + workorder = request.env['mrp.workorder'].sudo().browse(int(res.get('workorder_id'))) + workorder.handle_exception(['YC0002', 'YC0003']) + except Exception as e: + _logger.info('更新工单异常记录失败:%s' % e) + return json.JSONEncoder().encode(res) \ No newline at end of file diff --git a/jikimo_workorder_exception/models/__init__.py b/jikimo_workorder_exception/models/__init__.py new file mode 100644 index 00000000..9ab4d803 --- /dev/null +++ b/jikimo_workorder_exception/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import jikimo_workorder_exception +from . import mrp_workorder diff --git a/jikimo_workorder_exception/models/jikimo_workorder_exception.py b/jikimo_workorder_exception/models/jikimo_workorder_exception.py new file mode 100644 index 00000000..19dd824b --- /dev/null +++ b/jikimo_workorder_exception/models/jikimo_workorder_exception.py @@ -0,0 +1,14 @@ +from odoo import models, fields + + +class JikimoWorkorderException(models.Model): + _name = 'jikimo.workorder.exception' + _description = '工单异常记录' + _order = 'id desc' + + workorder_id = fields.Many2one('mrp.workorder', string='工单') + exception_code = fields.Char('异常编码') + exception_content = fields.Char('反馈的异常/问题信息') + completion_time = fields.Datetime('处理完成时间') + state = fields.Selection([('pending', '进行中'), ('done', '已处理')], string='状态', default='pending') + \ No newline at end of file diff --git a/jikimo_workorder_exception/models/mrp_workorder.py b/jikimo_workorder_exception/models/mrp_workorder.py new file mode 100644 index 00000000..64f0dd8f --- /dev/null +++ b/jikimo_workorder_exception/models/mrp_workorder.py @@ -0,0 +1,40 @@ +from odoo import models, fields +import logging + +_logger = logging.getLogger(__name__) + +class MrpWorkorder(models.Model): + _inherit = 'mrp.workorder' + + exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录') + + def write(self, values): + if values.get('test_results') and self.exception_ids: + pending_exception = self.exception_ids.filtered( + lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005' + ) + if pending_exception: + pending_exception.write({ + 'completion_time': fields.Datetime.now(), + 'state': 'done' + }) + return super(MrpWorkorder, self).write(values) + + def handle_exception(self, exception_codes): + """ + 处理异常 + :param exception_codes: 需要处理的异常编码列表 + """ + if not isinstance(exception_codes, list): + exception_codes = [exception_codes] + if self.exception_ids: + _logger.info('workorder.exception_ids:%s' % self.exception_ids) + pending_exception = self.exception_ids.filtered( + lambda exc: exc.state == 'pending' and exc.exception_code in exception_codes + ) + _logger.info('pending_exception:%s' % pending_exception) + if pending_exception: + pending_exception.write({ + 'completion_time': fields.Datetime.now(), + 'state': 'done' + }) diff --git a/jikimo_workorder_exception/security/ir.model.access.csv b/jikimo_workorder_exception/security/ir.model.access.csv new file mode 100644 index 00000000..bbc066e4 --- /dev/null +++ b/jikimo_workorder_exception/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_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0 diff --git a/jikimo_workorder_exception/tests/__init__.py b/jikimo_workorder_exception/tests/__init__.py new file mode 100644 index 00000000..99feb117 --- /dev/null +++ b/jikimo_workorder_exception/tests/__init__.py @@ -0,0 +1,2 @@ +from . import common +from . import test_jikimo_workorder_exception diff --git a/jikimo_workorder_exception/tests/common.py b/jikimo_workorder_exception/tests/common.py new file mode 100644 index 00000000..bbc729db --- /dev/null +++ b/jikimo_workorder_exception/tests/common.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import fields, Command +from odoo.tests.common import TransactionCase, HttpCase, tagged, Form + +import json +import time +import base64 +from lxml import etree + +@tagged('post_install', '-at_install') +class TestJikimoWorkorderExceptionCommon(TransactionCase): + + def setUp(self): + super(TestJikimoWorkorderExceptionCommon, self).setUp() + # 获取名字为“1#自动生产线”的制造中心 + workcenter = self.env['mrp.workcenter'].search([('name', '=', '1#自动生产线')], limit=1) + # 创建一个产品 + product_product = self.env['product.product'].create({ + 'name': '测试产品', + 'type': 'product', + }) + uom_unit = self.env.ref('uom.product_uom_unit') + # 创建一个bom + self.bom = self.env['mrp.bom'].create({ + 'product_id': product_product.id, + 'product_tmpl_id': product_product.product_tmpl_id.id, + 'product_uom_id': uom_unit.id, + 'product_qty': 1.0, + 'type': 'normal', + }) + # 创建一个制造订单 + self.production = self.env['mrp.production'].create({ + 'name': 'Test Production', + 'product_id': product_product.id, + 'bom_id': self.bom.id, + 'company_id': self.env.ref('base.main_company').id, + }) + # 创建一个测试工单 + self.workorder = self.env['mrp.workorder'].create({ + 'name': 'Test order', + 'workcenter_id': workcenter.id, + 'product_uom_id': self.bom.product_uom_id.id, + 'production_id': self.production.id, + 'duration_expected': 1.0, + 'rfid_code': 'test-123456', + 'routing_type': 'CNC加工' + }) \ No newline at end of file diff --git a/jikimo_workorder_exception/tests/test_jikimo_workorder_exception.py b/jikimo_workorder_exception/tests/test_jikimo_workorder_exception.py new file mode 100644 index 00000000..69220947 --- /dev/null +++ b/jikimo_workorder_exception/tests/test_jikimo_workorder_exception.py @@ -0,0 +1,53 @@ +import json +from datetime import datetime +from odoo.addons.jikimo_workorder_exception.tests.common import TestJikimoWorkorderExceptionCommon + +class TestJikimoWorkorderException(TestJikimoWorkorderExceptionCommon): + + def test_create_exception_record(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0001', + 'exception_content': '无CNC编程' + }) + + self.assertTrue(exception_record) + self.assertEqual(exception_record.exception_content, '无CNC编程') + self.assertEqual(exception_record.workorder_id.id, self.workorder.id) + self.assertEqual(exception_record.exception_code, 'YC0001') + + def test_handle_exception(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0001', + 'exception_content': '无CNC编程' + }) + self.workorder.handle_exception('YC0001') + self.assertEqual(exception_record.state, 'done') + # 判断完成时间是否为当前分钟 + self.assertEqual(exception_record.completion_time.minute, datetime.now().minute) + + def test_handle_exception_with_invalid_code(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0001', + 'exception_content': '无CNC编程' + }) + self.workorder.handle_exception(['YC0002', 'YC0004']) + self.assertEqual(exception_record.state, 'pending') + self.assertEqual(exception_record.completion_time, False) + + + def test_handle_exception_with_test_results(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0005', + 'exception_content': '工单加工失败' + }) + self.workorder.write({ + 'test_results': '返工', + 'reason': 'cutter', + 'detailed_reason': '刀坏了', + }) + self.assertEqual(exception_record.state, 'done') + self.assertEqual(exception_record.completion_time.minute, datetime.now().minute) \ No newline at end of file diff --git a/jikimo_workorder_exception/views/mrp_workorder_views.xml b/jikimo_workorder_exception/views/mrp_workorder_views.xml new file mode 100644 index 00000000..e589adb4 --- /dev/null +++ b/jikimo_workorder_exception/views/mrp_workorder_views.xml @@ -0,0 +1,23 @@ + + + + + mrp.workorder.form + mrp.workorder + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jikimo_workorder_exception_notify/__init__.py b/jikimo_workorder_exception_notify/__init__.py new file mode 100644 index 00000000..77bbdbd3 --- /dev/null +++ b/jikimo_workorder_exception_notify/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import models + diff --git a/jikimo_workorder_exception_notify/__manifest__.py b/jikimo_workorder_exception_notify/__manifest__.py new file mode 100644 index 00000000..0b8c1013 --- /dev/null +++ b/jikimo_workorder_exception_notify/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': '机企猫 工单异常消息通知', + 'version': '1.0', + 'summary': '当产生工单异常时,发送消息通知', + 'sequence': 1, + 'category': 'sf', + 'website': 'https://www.sf.jikimo.com', + 'depends': ['jikimo_workorder_exception', 'jikimo_message_notify'], + 'data': [ + 'data/bussiness_node.xml', + 'data/template_data.xml', + # 'security/ir.model.access.csv', + ], + 'demo': [ + ], + 'license': 'LGPL-3', + 'installable': True, + 'application': False, + 'auto_install': False, +} diff --git a/jikimo_workorder_exception_notify/data/bussiness_node.xml b/jikimo_workorder_exception_notify/data/bussiness_node.xml new file mode 100644 index 00000000..b772158b --- /dev/null +++ b/jikimo_workorder_exception_notify/data/bussiness_node.xml @@ -0,0 +1,17 @@ + + + + + 无功能刀具 + jikimo.workorder.exception + + + 无定位数据 + jikimo.workorder.exception + + + 加工失败 + jikimo.workorder.exception + + + \ No newline at end of file diff --git a/jikimo_workorder_exception_notify/data/template_data.xml b/jikimo_workorder_exception_notify/data/template_data.xml new file mode 100644 index 00000000..554ef2c2 --- /dev/null +++ b/jikimo_workorder_exception_notify/data/template_data.xml @@ -0,0 +1,38 @@ + + + + + 生产线无功能刀具提醒 + + jikimo.workorder.exception + + markdown + urgent + ### 生产线无功能刀具提醒 +单号:工单[{{workorder_id.production_id.name}}]({{url}}) +原因:生产线无加工程序用的{{function_tool_name}}名称功能刀具 + + + 工单无定位数据提醒 + + jikimo.workorder.exception + + markdown + urgent + ### 生产线无功能刀具提醒 +单号:工单[{{workorder_id.production_id.name}}]({{url}}) +原因:无装夹定位测量数据 + + + 工单加工失败提醒 + + jikimo.workorder.exception + + markdown + urgent + ### 工单加工失败提醒 +单号:工单[{{workorder_id.production_id.name}}]({{url}}) +原因:加工失败,工件下产线处理 + + + \ No newline at end of file diff --git a/jikimo_workorder_exception_notify/models/__init__.py b/jikimo_workorder_exception_notify/models/__init__.py new file mode 100644 index 00000000..76a90c74 --- /dev/null +++ b/jikimo_workorder_exception_notify/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import jikimo_message_template +from . import jikimo_workorder_exception diff --git a/jikimo_workorder_exception_notify/models/jikimo_message_template.py b/jikimo_workorder_exception_notify/models/jikimo_message_template.py new file mode 100644 index 00000000..530cbb99 --- /dev/null +++ b/jikimo_workorder_exception_notify/models/jikimo_message_template.py @@ -0,0 +1,10 @@ +from odoo import models + + +class JikimoMessageTemplate(models.Model): + _inherit = "jikimo.message.template" + + def _get_message_model(self): + res = super(JikimoMessageTemplate, self)._get_message_model() + res.append('jikimo.workorder.exception') + return res \ No newline at end of file diff --git a/jikimo_workorder_exception_notify/models/jikimo_workorder_exception.py b/jikimo_workorder_exception_notify/models/jikimo_workorder_exception.py new file mode 100644 index 00000000..bbe69ab5 --- /dev/null +++ b/jikimo_workorder_exception_notify/models/jikimo_workorder_exception.py @@ -0,0 +1,61 @@ +from odoo import models, api +from odoo.addons.sf_base.commons.common import Common +import requests, logging + +_logger = logging.getLogger(__name__) + + +class JikimoWorkorderException(models.Model): + _name = 'jikimo.workorder.exception' + _inherit = ['jikimo.workorder.exception', 'jikimo.message.dispatch'] + + @api.model_create_multi + def create(self, vals_list): + res = super(JikimoWorkorderException, self).create(vals_list) + # 根据异常编码发送消息提醒 + try: + for rec in res: + if rec.exception_code == 'YC0001': + # 无CNC程序,调用cloud接口 + data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0001'} + configsettings = self.env['res.config.settings'].sudo().get_values() + config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) + url = '/api/message/workorder_exception' + config_url = configsettings['sf_url'] + url + data['token'] = configsettings['token'] + ret = requests.post(config_url, json=data, headers=config_header) + ret = ret.json() + _logger.info('无CNC程序异常消息推送接口:%s' % ret) + elif rec.exception_code == 'YC0002': + # 无功能刀具 + rec.add_queue('无功能刀具') + elif rec.exception_code == 'YC0003': + # 无定位数据 + rec.add_queue('无定位数据') + elif rec.exception_code == 'YC0004': + # 无FTP文件,调用cloud接口 + data = {'name': rec.workorder_id.programming_no, 'exception_code': 'YC0004'} + configsettings = self.env['res.config.settings'].sudo().get_values() + config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) + url = '/api/message/workorder_exception' + config_url = configsettings['sf_url'] + url + data['token'] = configsettings['token'] + ret = requests.post(config_url, json=data, headers=config_header) + ret = ret.json() + _logger.info('无FTP文件异常消息推送接口:%s' % ret) + elif rec.exception_code == 'YC0005': + # 加工失败 + rec.add_queue('加工失败') + except Exception as e: + _logger.error('异常编码发送消息提醒失败:%s' % e) + return res + + def _get_message(self, message_queue_ids): + contents = super(JikimoWorkorderException, self)._get_message(message_queue_ids) + url = self.env['ir.config_parameter'].get_param('web.base.url') + action_id = self.env.ref('mrp.mrp_production_action').id + for index, content in enumerate(contents): + exception_id = self.env['jikimo.workorder.exception'].browse(message_queue_ids[index].res_id) + url = url + '/web#id=%s&view_type=form&action=%s' % (exception_id.workorder_id.production_id.id, action_id) + contents[index] = content.replace('{{url}}', url) + return contents diff --git a/jikimo_workorder_exception_notify/tests/__init__.py b/jikimo_workorder_exception_notify/tests/__init__.py new file mode 100644 index 00000000..318a4c8a --- /dev/null +++ b/jikimo_workorder_exception_notify/tests/__init__.py @@ -0,0 +1,2 @@ +from . import common +from . import test_jikimo_workorder_exception_notify diff --git a/jikimo_workorder_exception_notify/tests/common.py b/jikimo_workorder_exception_notify/tests/common.py new file mode 100644 index 00000000..5fefe6bf --- /dev/null +++ b/jikimo_workorder_exception_notify/tests/common.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import fields, Command +from odoo.tests.common import TransactionCase, HttpCase, tagged, Form + +import json +import time +import base64 +from lxml import etree + +@tagged('post_install', '-at_install') +class TestJikimoWorkorderExceptionNotifyCommonNotify(TransactionCase): + + def setUp(self): + super(TestJikimoWorkorderExceptionNotifyCommonNotify, self).setUp() + # 获取最后一个工单 + self.workorder = self.env['mrp.workorder'].search([], order='id desc', limit=1) + \ No newline at end of file diff --git a/jikimo_workorder_exception_notify/tests/test_jikimo_workorder_exception_notify.py b/jikimo_workorder_exception_notify/tests/test_jikimo_workorder_exception_notify.py new file mode 100644 index 00000000..85d304be --- /dev/null +++ b/jikimo_workorder_exception_notify/tests/test_jikimo_workorder_exception_notify.py @@ -0,0 +1,62 @@ +import json +from datetime import datetime +from odoo.addons.jikimo_workorder_exception_notify.tests.common import TestJikimoWorkorderExceptionNotifyCommonNotify + +class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommonNotify): + + def test_create_message_template(self): + self.assertTrue(self.env['jikimo.message.template'].search([ + ('name', '=', '生产线无功能刀具提醒'), + ('model', '=', 'jikimo.workorder.exception') + ])) + self.assertTrue(self.env['jikimo.message.template'].search([ + ('name', '=', '工单无定位数据提醒'), + ('model', '=', 'jikimo.workorder.exception') + ])) + self.assertTrue(self.env['jikimo.message.template'].search([ + ('name', '=', '加工失败'), + ('model', '=', 'jikimo.workorder.exception') + ])) + + + def test_create_message_queue(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0002', + 'exception_content': '无功能刀具' + }) + + bussiness_node = self.env['jikimo.message.bussiness.node'].search([ + ('name', '=', '无功能刀具'), + ('model', '=', 'jikimo.workorder.exception') + ]) + + message_template = self.env['jikimo.message.template'].search([ + ('bussiness_node_id', '=', bussiness_node.id), + ('model', '=', 'jikimo.workorder.exception') + ]) + + message_record = self.env['jikimo.message.queue'].search([ + ('res_id', '=', exception_record.id), + ('model', '=', 'jikimo.workorder.exception'), + ('message_status', '=', 'pending'), + ('message_template_id', '=', message_template.id) + ]) + self.assertTrue(message_record) + + + def test_get_message(self): + exception_record = self.env['jikimo.workorder.exception'].create({ + 'workorder_id': self.workorder.id, + 'exception_code': 'YC0002', + 'exception_content': '无功能刀具' + }) + message_queue_ids = self.env['jikimo.message.queue'].search([ + ('res_id', '=', exception_record.id), + ('model', '=', 'jikimo.workorder.exception'), + ('message_status', '=', 'pending') + ]) + message = self.env['jikimo.workorder.exception']._get_message(message_queue_ids) + self.assertTrue(message) + + diff --git a/sf_base/controllers/controllers.py b/sf_base/controllers/controllers.py index 71ed8f94..47c67322 100644 --- a/sf_base/controllers/controllers.py +++ b/sf_base/controllers/controllers.py @@ -38,3 +38,17 @@ class Manufacturing_Connect(http.Controller): res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} logging.info('get_maintenance_tool_groups_Info error:%s' % e) return json.JSONEncoder().encode(res) + + +class MultiInheritController(): + _sub_classes = [] + + def __init_subclass__(cls): + """ + 多继承,解决多个字类时方法调用super的问题 + """ + super().__init_subclass__() + if len(cls._sub_classes) > 0 and cls not in cls._sub_classes: + cls.__bases__ = (cls._sub_classes[-1],) + if cls not in cls._sub_classes: + cls._sub_classes.append(cls) diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index f44915f1..2a5e4d3e 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -189,6 +189,7 @@ class Manufacturing_Connect(http.Controller): request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write( {'actual_start_time': workorder.date_start, 'state': 'processing'}) + res.update({'workorder_id': workorder.id}) except Exception as e: res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index 0c380ebd..a584379f 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -40,7 +40,7 @@ class ResMrpRoutingWorkcenter(models.Model): def get_company_id(self): self.company_id = self.env.user.company_id.id - company_id = fields.Many2one('res.company', compute="get_company_id", related=False) + company_id = fields.Many2one('res.company', compute="get_company_id", related=False, store=True) # 排产的时候, 根据坯料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床). # 工单对应的工作中心,根据工序中的工作中心去匹配, diff --git a/sf_message/controllers/main.py b/sf_message/controllers/main.py index ab97816b..11e776dc 100644 --- a/sf_message/controllers/main.py +++ b/sf_message/controllers/main.py @@ -15,12 +15,13 @@ class MessageSfMrsConnect(Sf_Mrs_Connect): def get_cnc_processing_create(self, **kw): res = super(MessageSfMrsConnect, self).get_cnc_processing_create(**kw) res = json.loads(res) + _logger.info('已进入消息推送:%s' % res) if res.get('production_ids'): try: _logger.info('已编程的制造订单:%s' % res.get('production_ids')) productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))]) # 过滤programming_state为已编程,tool_state为2的制造订单 - tool_state_valid_productions = productions.filtered(lambda x: x.programming_state == '已编程' and x.tool_state == '2') + tool_state_valid_productions = productions.filtered(lambda x: x.tool_state == '2') if tool_state_valid_productions: data = { 'name': tool_state_valid_productions[0].programming_no @@ -38,3 +39,22 @@ class MessageSfMrsConnect(Sf_Mrs_Connect): _logger.info('无效用刀异常消息推送接口:%s' % e) return json.JSONEncoder().encode(res) + @http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + def maintenance_logs_notify(self, **kw): + res = {'code': 200, 'message': '设备故障日志信息推送成功'} + datas = request.httprequest.data + ret = json.loads(datas) + log_id = ret.get('log_id') + if not log_id: + res = {'code': 400, 'message': '设备故障日志id不能为空'} + return json.JSONEncoder().encode(res) + try: + if not isinstance(log_id, list): + log_id = [log_id] + maintenance_logs = request.env['sf.maintenance.logs'].sudo().search([('id', 'in', [int(id) for id in log_id])]) + if maintenance_logs: + maintenance_logs.add_queue('设备故障') + except Exception as e: + res = {'code': 400, 'message': '设备故障信息推送失败', 'error': str(e)} + return json.JSONEncoder().encode(res) + diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index d9ac9ae1..a7123d44 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -111,5 +111,9 @@ quality.cnc.test + + 设备故障 + sf.maintenance.logs + \ No newline at end of file diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index f511d338..057dc009 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -264,5 +264,16 @@ ### 待质量判定提醒 事项:共有[{{judge_num}}]({{url}})个工单需判定质量结果 + + 设备故障 + + sf.maintenance.logs + + markdown + urgent + ### 设备故障及异常提醒: +机台号:[{{maintenance_equipment_id.name}}]({{url}}) +事项:{{create_date}}故障报警 + \ No newline at end of file diff --git a/sf_message/models/__init__.py b/sf_message/models/__init__.py index 25702b1e..0b9c9ad6 100644 --- a/sf_message/models/__init__.py +++ b/sf_message/models/__init__.py @@ -9,3 +9,4 @@ from . import sf_message_workorder from . import sf_message_functional_tool_dismantle from . import sf_message_mrp_production from . import sf_message_quality_cnc_test +from . import sf_message_maintenance_logs diff --git a/sf_message/models/sf_message_maintenance_logs.py b/sf_message/models/sf_message_maintenance_logs.py new file mode 100644 index 00000000..288043ff --- /dev/null +++ b/sf_message/models/sf_message_maintenance_logs.py @@ -0,0 +1,22 @@ +from odoo import models, fields, api + +class SFMessageMaintenanceLogs(models.Model): + _name = 'sf.maintenance.logs' + _inherit = ['sf.maintenance.logs', 'jikimo.message.dispatch'] + + @api._model_create_multi + def create(self, vals_list): + res = super(SFMessageMaintenanceLogs, self).create(vals_list) + for rec in res: + rec.add_queue() + return res + + def _get_message(self, message_queue_ids): + contents = super(SFMessageMaintenanceLogs, self)._get_message(message_queue_ids) + url = self.env['ir.config_parameter'].get_param('web.base.url') + action_id = self.env.ref('sf_maintenance.action_maintenance_logs').id + for index, content in enumerate(contents): + maintenance_logs_id = self.env['sf.maintenance.logs'].browse(message_queue_ids[index].res_id) + url = url + '/web#id=%s&view_type=form&action=%s' % (maintenance_logs_id.id, action_id) + contents[index] = content.replace('{{url}}', url) + return contents \ No newline at end of file diff --git a/sf_message/models/sf_message_template.py b/sf_message/models/sf_message_template.py index 56346c27..5e4d66b0 100644 --- a/sf_message/models/sf_message_template.py +++ b/sf_message/models/sf_message_template.py @@ -14,4 +14,5 @@ class SfMessageTemplate(models.Model): res.append('sf.functional.tool.dismantle') res.append('purchase.order') res.append('mrp.workorder') + res.append('sf.maintenance.logs') return res diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index cb56287a..c66b03bc 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -3,11 +3,12 @@ import logging import os import json import base64 -from odoo import http +from odoo import http, fields, models from odoo.http import request +from odoo.addons.sf_base.controllers.controllers import MultiInheritController -class Sf_Mrs_Connect(http.Controller): +class Sf_Mrs_Connect(http.Controller, MultiInheritController): @http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, cors="*")