中国本土应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
8.5KB

  1. # -*- coding: utf-8 -*-
  2. import logging
  3. from odoo import api, models, _
  4. from odoo.addons.oec_im_wecom_api.api.wecom_abstract_api import ApiException
  5. from datetime import datetime, timedelta
  6. import pytz
  7. import json
  8. _logger = logging.getLogger(__name__)
  9. class WeComMessageApi(models.AbstractModel):
  10. _name = "wecom.message.api"
  11. _description = "WeCom Message API"
  12. def get_message_api(self, company):
  13. """"""
  14. wxapi = self.env["wecom.service_api"].InitServiceApi(
  15. company, "message_secret", "message"
  16. )
  17. return wxapi
  18. def send_by_api(self, message, api):
  19. params = self.env["ir.config_parameter"].sudo()
  20. debug = params.get_param("wecom.debug_enabled")
  21. try:
  22. del message["company"] # 删除message中的 company
  23. response = api.httpCall(
  24. self.env["wecom.service_api_list"].get_server_api_call("MESSAGE_SEND"),
  25. message,
  26. )
  27. return response
  28. except ApiException as ex:
  29. if debug:
  30. _logger.warning(_("Error sending message: %s") % (ex))
  31. def build_message(
  32. self,
  33. msgtype,
  34. toall=None,
  35. touser=None,
  36. toparty=None,
  37. totag=None,
  38. subject=None,
  39. media_id=None,
  40. description=None,
  41. author_id=None,
  42. body_html=None,
  43. body_json=None,
  44. body_markdown=None,
  45. safe=None,
  46. enable_id_trans=None,
  47. enable_duplicate_check=None,
  48. duplicate_check_interval=None,
  49. company=None,
  50. ):
  51. """
  52. 构建消息
  53. :msgtype: 消息类型,根据消息类型来构建消息内容
  54. :toall: 发送给全体人员
  55. :touser: 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
  56. 特殊情况:指定为”@all”,则向该企业应用的全部成员发送
  57. :toparty: 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。
  58. 当touser为”@all”时忽略本参数
  59. :totag: 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。
  60. 当touser为”@all”时忽略本参数
  61. :subject: 标题 ,不同消息类型,长度限制不一样
  62. :media_id: media_id, 可以通过素材管理接口获得
  63. :body_html: 图文消息的内容,支持html标签,不超过666 K个字节,仅用于图文消息(mpnews)
  64. :body_json: 非图文消息的内容,不同消息类型,长度限制不一样
  65. :safe: 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
  66. :enable_id_trans: 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
  67. :enable_duplicate_check: Indicates whether to enable duplicate message checking. 0 indicates no, 1 indicates yes. The default is 0
  68. :duplicate_check_interval: Indicates whether the message check is repeated. The default is 1800s and the maximum is no more than 4 hours
  69. """
  70. if not company:
  71. company = self.env.company
  72. messages_content = self.get_messages_content(
  73. msgtype,
  74. description,
  75. author_id,
  76. body_html,
  77. body_json,
  78. body_markdown,
  79. subject,
  80. media_id,
  81. )
  82. messages_options = self.get_messages_options(
  83. msgtype,
  84. safe,
  85. enable_id_trans,
  86. enable_duplicate_check,
  87. duplicate_check_interval,
  88. )
  89. messages = {
  90. "touser": "@all" if toall else touser,
  91. "toparty": "" if toall else toparty,
  92. "totag": "" if toall else totag,
  93. "msgtype": msgtype,
  94. "agentid": company.message_agentid,
  95. "company": company,
  96. }
  97. messages.update(messages_content)
  98. messages.update(messages_options)
  99. return messages
  100. @api.model
  101. def send_message(self, message):
  102. """
  103. 发送一条企业微信消息 到多个人员
  104. """
  105. return self.send_by_api(message)
  106. @api.model
  107. def _send_message_batch(self, messages):
  108. """
  109. 批量模式发送企业微信消息
  110. """
  111. params = {
  112. "messages": messages,
  113. }
  114. return self._wecom_message_send_api(params)
  115. def get_messages_content(
  116. self,
  117. msgtype,
  118. description=None,
  119. author_id=None,
  120. body_html=None,
  121. body_json=None,
  122. body_markdown=None,
  123. subject=None,
  124. media_id=None,
  125. ):
  126. # material_info = (
  127. # self.env["wecom.material"].sudo().browse(int(media_id)).read(["name"])
  128. # )
  129. messages_content = {}
  130. if msgtype == "text":
  131. # 文本消息
  132. messages_content = {
  133. "text": body_json,
  134. }
  135. elif msgtype == "mpnews":
  136. # 图文消息(mpnews)
  137. material = (
  138. self.sudo()
  139. .env["wecom.material"]
  140. .search(
  141. [
  142. ("id", "=", media_id),
  143. ],
  144. limit=1,
  145. )
  146. )
  147. # material_media_id = self.check_material_file_expiration(material)
  148. messages_content = {
  149. "mpnews": {
  150. "articles": [
  151. {
  152. "title": subject,
  153. "thumb_media_id": material._check_material_file_expiration(),
  154. "author": author_id.display_name,
  155. "content": body_html,
  156. "digest": description,
  157. }
  158. ]
  159. },
  160. }
  161. elif msgtype == "markdown":
  162. # markdown消息
  163. messages_content = {
  164. "markdown": {
  165. "content": body_markdown,
  166. }
  167. }
  168. elif msgtype == "template_card":
  169. # 模板卡片消息
  170. messages_content = {
  171. "template_card": json.loads(body_json, strict=False),
  172. }
  173. return messages_content
  174. def get_messages_options(
  175. self,
  176. msgtype,
  177. safe=None,
  178. enable_id_trans=None,
  179. enable_duplicate_check=None,
  180. duplicate_check_interval=None,
  181. ):
  182. """[summary]
  183. 获取企业微信消息的选项
  184. Args:
  185. msgtype ([type]): [description]
  186. safe ([type], optional): [description]. Defaults to None.
  187. enable_id_trans ([type], optional): [description]. Defaults to None.
  188. enable_duplicate_check ([type], optional): [description]. Defaults to None.
  189. duplicate_check_interval ([type], optional): [description]. Defaults to None.
  190. Returns:
  191. [type]: [description]
  192. """
  193. messages_options = {
  194. "safe": int(safe),
  195. "enable_id_trans": int(enable_id_trans),
  196. "enable_duplicate_check": int(enable_duplicate_check),
  197. "duplicate_check_interval": duplicate_check_interval,
  198. }
  199. if msgtype == "markdown":
  200. # markdown消息
  201. del messages_options["safe"]
  202. del messages_options["enable_id_trans"]
  203. if msgtype == "template_card":
  204. # 模板卡片消息
  205. del messages_options["safe"]
  206. return messages_options
  207. # def check_material_file_expiration(self, material):
  208. # """[summary]
  209. # 检查素材文件是否过期
  210. # Args:
  211. # material ([type]): [description]
  212. # Returns:
  213. # [type]: [description]
  214. # """
  215. # media_id = ""
  216. # if material.created_at:
  217. # # 有创建日期
  218. # created_time = material.created_at
  219. # MAX_FAIL_TIME = 3
  220. # # 检查是否超过3天
  221. # overdue = self.env["wecom.tools"].cheeck_days_overdue(
  222. # created_time, MAX_FAIL_TIME
  223. # )
  224. # if overdue:
  225. # # 临时素材超期,重新上传
  226. # material.upload_media()
  227. # media_id = material.media_id
  228. # else:
  229. # # 无创建日期,执行第一次上传临时素材
  230. # material.upload_media()
  231. # media_id = material.media_id
  232. # return media_id
上海开阖软件有限公司 沪ICP备12045867号-1