diff --git a/jikimo_message_notify/__init__.py b/jikimo_message_notify/__init__.py new file mode 100644 index 00000000..9a7e03ed --- /dev/null +++ b/jikimo_message_notify/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/jikimo_message_notify/__manifest__.py b/jikimo_message_notify/__manifest__.py new file mode 100644 index 00000000..9af32625 --- /dev/null +++ b/jikimo_message_notify/__manifest__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': '机企猫智能工厂 消息提醒', + 'version': '1.0', + 'summary': '智能工厂消息提醒模块', + 'sequence': 1, + 'description': """ + + """, + 'category': 'sf', + 'website': 'https://www.sf.jikimo.com', + 'depends': ['base', 'sf_plan', 'sf_sale', 'wechat_enterprise_business_processing'], + 'data': [ + 'security/ir.model.access.csv', + 'views/sf_message_template_view.xml', + ], + 'test': [ + ], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/jikimo_message_notify/models/__init__.py b/jikimo_message_notify/models/__init__.py new file mode 100644 index 00000000..04b9e069 --- /dev/null +++ b/jikimo_message_notify/models/__init__.py @@ -0,0 +1,5 @@ +from . import jikimo_message_template +from . import jikimo_message_queue +from . import jikimo_message_dispatch +from . import jikimo_message_bussiness_node + diff --git a/jikimo_message_notify/models/jikimo_message_bussiness_node.py b/jikimo_message_notify/models/jikimo_message_bussiness_node.py new file mode 100644 index 00000000..b24d4863 --- /dev/null +++ b/jikimo_message_notify/models/jikimo_message_bussiness_node.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +import logging +from odoo import models, fields, api +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + + +class JikimoMessageBussinessNode(models.Model): + _name = "jikimo.message.bussiness.node" + _description = '发送消息业务节点' + + name = fields.Char(string="节点名称") + model = fields.Char(string="模型") + + \ No newline at end of file diff --git a/jikimo_message_notify/models/jikimo_message_dispatch.py b/jikimo_message_notify/models/jikimo_message_dispatch.py new file mode 100644 index 00000000..ef6ac53c --- /dev/null +++ b/jikimo_message_notify/models/jikimo_message_dispatch.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +import logging +from odoo import models +from odoo import exceptions +from wechatpy.enterprise import WeChatClient +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + + +class JikimoMessageDispatch(models.AbstractModel): + _name = "jikimo.message.dispatch" + _description = '消息发送' + + def add_queue(self, bussiness_node, urgency="normal", **kwargs): + """ + 添加消息队列 + """ + bussiness_node_id = self.env["jikimo.message.bussiness.node"].search([ + ("model", "=", self._name), + ("name", "=", bussiness_node) + ]) + # 根据模型与紧急程度获取消息模板 + message_template_id = self.env["jikimo.message.template"].search([ + ("model", "=", self._name), + ("urgency", "=", urgency), + ("bussiness_node_id", "=", bussiness_node_id.id) + ]) + if not message_template_id: + _logger.warning(f"{self._name}消息推送模板未配置") + return False + + data_list = [] + for record in self: + data_list.append({ + 'res_id': record.id, + 'model': record._name, + 'message_template_id': message_template_id.id, + }) + return self.env["jikimo.message.queue"].create(data_list) + + def _merge_message_queue(self): + """ + 合并相同业务节点与相同模型的消息 + """ + pass + + def _get_message(self, message_queue_ids): + """ + 根据消息队列获取消息内容 + :param message_queue_ids: 消息队列ID列表 + :return: 消息内容 + """ + contents = [] + for message_queue_id in message_queue_ids: + content = message_queue_id.message_template_id.content + # 获取模板中带有{{}}的变量 + import re + variables = re.findall(r"{{[^{}]+}}", content) + if variables: + model_data = self.env[message_queue_id.model].browse(int(message_queue_id.res_id)) + for variable in variables: + # 获取变量对应的值 + variable_value = model_data[variable.strip("{{}}")] + # 将变量替换为值 + content = content.replace(variable, variable_value) + contents.append(content) + return contents + + def _send_message(self, message_content, we_user_list): + """ + 发送消息 + """ + enterprise = self.env['we.config'].search([('company_id', '=', 1)], limit=1) + if enterprise.odoo_app_id: + enterprise_app = self.env['we.app'].search([('agentid', '=', enterprise.odoo_app_id.agentid)]) + wechat = WeChatClient(corp_id=enterprise.corp_id, secret=enterprise_app.secret) + data = { + 'agentid': enterprise.odoo_app_id.agentid, + 'touser': we_user_list, + 'content': message_content + } + wechat.message.send_markdown(agent_id=data['agentid'], user_ids=data['touser'], content=data['content']) + else: + raise UserError('Odoo应用未配置. ') + + def _cron_dispatch(self): + """ + 定时发送消息 + """ + # 从消息队列中获取所有待发送消息的message_template_id + message_template_ids = self.env["jikimo.message.queue"].read_group([ + ("message_status", "=", "pending") + ], ['message_template_id'], ['message_template_id']) + # 根据模板类型来发送消息 + for message_template_id in message_template_ids[0]['message_template_id']: + message_queue_ids = self.env["jikimo.message.queue"].search([ + ("message_template_id", "=", message_template_id), + ("message_status", "=", "pending") + ]) + message_contents = self.env[message_queue_ids[0].message_template_id.model]._get_message(message_queue_ids) + # 发送消息 + for message_content in message_contents: + self._send_message(message_content, "HuYao") + return True \ No newline at end of file diff --git a/jikimo_message_notify/models/jikimo_message_queue.py b/jikimo_message_notify/models/jikimo_message_queue.py new file mode 100644 index 00000000..fe9defe4 --- /dev/null +++ b/jikimo_message_notify/models/jikimo_message_queue.py @@ -0,0 +1,19 @@ +from odoo import models, fields, api + +class JikimoMessageQueue(models.Model): + _name = "jikimo.message.queue" + _description = "消息队列" + + message_template_id = fields.Many2one("jikimo.message.template", string="消息模板") + res_id = fields.Text(string="单据ID") + model = fields.Char(String="模型") + message_status = fields.Selection([ + ("pending", "待发送"), + ("sent", "已发送"), + ("failed", "发送失败") + ], string="消息状态", default="pending") + message_error = fields.Text(string="错误信息") + send_date = fields.Datetime(string="创建时间") + message_updated_at = fields.Datetime(string="更新时间") + + diff --git a/jikimo_message_notify/models/jikimo_message_template.py b/jikimo_message_notify/models/jikimo_message_template.py new file mode 100644 index 00000000..d03c66b3 --- /dev/null +++ b/jikimo_message_notify/models/jikimo_message_template.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, api + + +class JikimoMessageTemplate(models.Model): + _name = "jikimo.message.template" + _description = '消息模板' + + name = fields.Char(string="名称", required=True) + + description = fields.Char(string="描述") + content = fields.Html(string="内容", render_engine='qweb', translate=True, prefetch=True, sanitize=False) + msgtype = fields.Selection( + [('text', '文字'), ('markdown', 'Markdown')], '消息类型', + required=True, default='markdown') + notification_department_id = fields.Many2one('hr.department', '通知部门', required=True) + notification_employee_ids = fields.Many2many('hr.employee', string='员工', + domain="[('department_id', '=',notification_department_id)]", + required=True) + + urgency = fields.Selection([ + ("normal", "普通"), + ("urgent", "紧急"), + ("very_urgent", "非常紧急") + ], string="紧急程度") + active = fields.Boolean(string="是否有效", default=True) + + def _get_message_model(self): + """ + 获取通知的模型 + """ + return [] + + def _get_model(self): + return self.model + + model_id = fields.Many2one( + "ir.model", + string="关联模型", + domain=lambda self: [("model", "in", self._get_message_model())] + ) + model = fields.Char(related="model_id.model", index=True, store=True) + bussiness_node_id = fields.Many2one( + "jikimo.message.bussiness.node", + string="业务节点", + domain=lambda self: [("model", "=", self.model)], + required=True + ) + + @api.onchange('notification_department_id') + def _clear_employee_ids(self): + if self.notification_department_id: + self.notification_employee_ids = False + + def test_send_message(self): + self.env["jikimo.message.dispatch"]._cron_dispatch() + + \ No newline at end of file diff --git a/jikimo_message_notify/security/group_security.xml b/jikimo_message_notify/security/group_security.xml new file mode 100644 index 00000000..fdbc3ae5 --- /dev/null +++ b/jikimo_message_notify/security/group_security.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/jikimo_message_notify/security/ir.model.access.csv b/jikimo_message_notify/security/ir.model.access.csv new file mode 100644 index 00000000..4011baed --- /dev/null +++ b/jikimo_message_notify/security/ir.model.access.csv @@ -0,0 +1,23 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_jikimo_message_template_group_sale_salemanager,jikimo_message_template,model_jikimo_message_template,sf_base.group_sale_salemanager,1,1,1,0 +access_jikimo_message_template_group_purchase,jikimo_message_template,model_jikimo_message_template,sf_base.group_purchase,1,1,1,0 +access_jikimo_message_template_group_sf_stock_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_stock_user,1,1,1,0 +access_jikimo_message_template_group_sf_order_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_order_user,1,1,1,0 +access_jikimo_message_template_group_sf_tool_user,jikimo_message_template,model_jikimo_message_template,sf_base.group_sf_tool_user,1,1,1,0 + +access_jikimo_message_bussiness_node_group_sale_salemanager,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sale_salemanager,1,1,1,0 +access_jikimo_message_bussiness_node_group_purchase,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_purchase,1,1,1,0 +access_jikimo_message_bussiness_node_group_sf_stock_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_stock_user,1,1,1,0 +access_jikimo_message_bussiness_node_group_sf_order_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_order_user,1,1,1,0 +access_jikimo_message_bussiness_node_group_sf_tool_user,jikimo_message_bussiness_node,model_jikimo_message_bussiness_node,sf_base.group_sf_tool_user,1,1,1,0 + +access_jikimo_message_queue_group_sale_salemanager,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sale_salemanager,1,1,1,0 +access_jikimo_message_queue_group_purchase,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_purchase,1,1,1,0 +access_jikimo_message_queue_group_sf_stock_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_stock_user,1,1,1,0 +access_jikimo_message_queue_group_sf_order_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_order_user,1,1,1,0 +access_jikimo_message_queue_group_sf_tool_user,jikimo_message_queue,model_jikimo_message_queue,sf_base.group_sf_tool_user,1,1,1,0 + + + + + diff --git a/jikimo_message_notify/views/sf_message_template_view.xml b/jikimo_message_notify/views/sf_message_template_view.xml new file mode 100644 index 00000000..ec8243ce --- /dev/null +++ b/jikimo_message_notify/views/sf_message_template_view.xml @@ -0,0 +1,80 @@ + + + + + + + + sf.message.template.view.form + jikimo.message.template + +
+ +
+
+ + + + + + + + + + + +