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.

237 lines
8.5 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2017 Simone Orsi <simone.orsi@camptocamp.com>
  3. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
  4. from odoo import models, fields, api, _
  5. class ResPartner(models.Model):
  6. _inherit = 'res.partner'
  7. notify_email = fields.Selection(selection_add=[('digest', _('Digest'))])
  8. notify_frequency = fields.Selection(
  9. string='Frequency',
  10. selection=[
  11. ('daily', 'Daily'),
  12. ('weekly', 'Weekly')
  13. ],
  14. default='weekly',
  15. required=True,
  16. )
  17. notify_conf_ids = fields.One2many(
  18. string='Notifications',
  19. inverse_name='partner_id',
  20. comodel_name='partner.notification.conf',
  21. )
  22. enabled_notify_subtype_ids = fields.Many2many(
  23. string='Partner enabled subtypes',
  24. comodel_name='mail.message.subtype',
  25. compute='_compute_enabled_notify_subtype_ids',
  26. search='_search_enabled_notify_subtype_ids',
  27. )
  28. disabled_notify_subtype_ids = fields.Many2many(
  29. string='Partner disabled subtypes',
  30. comodel_name='mail.message.subtype',
  31. compute='_compute_disabled_notify_subtype_ids',
  32. search='_search_disabled_notify_subtype_ids',
  33. )
  34. @api.multi
  35. def _compute_notify_subtypes(self, enabled):
  36. self.ensure_one()
  37. query = (
  38. 'SELECT subtype_id FROM partner_notification_conf '
  39. 'WHERE partner_id=%s AND enabled = %s'
  40. )
  41. self.env.cr.execute(
  42. query, (self.id, enabled))
  43. return [x[0] for x in self.env.cr.fetchall()]
  44. @api.multi
  45. @api.depends('notify_conf_ids.subtype_id')
  46. def _compute_enabled_notify_subtype_ids(self):
  47. for partner in self:
  48. partner.enabled_notify_subtype_ids = \
  49. partner._compute_notify_subtypes(True)
  50. @api.multi
  51. @api.depends('notify_conf_ids.subtype_id')
  52. def _compute_disabled_notify_subtype_ids(self):
  53. for partner in self:
  54. partner.disabled_notify_subtype_ids = \
  55. partner._compute_notify_subtypes(False)
  56. def _search_notify_subtype_ids_domain(self, operator, value, enabled):
  57. """Build domain to search notification subtypes by partner settings."""
  58. if operator in ('in', 'not in') and \
  59. not isinstance(value, (tuple, list)):
  60. value = [value, ]
  61. conf_value = value
  62. if isinstance(conf_value, int):
  63. # we search conf records always w/ 'in'
  64. conf_value = [conf_value]
  65. _value = self.env['partner.notification.conf'].search([
  66. ('subtype_id', 'in', conf_value),
  67. ('enabled', '=', enabled),
  68. ]).mapped('partner_id').ids
  69. return [('id', operator, _value)]
  70. def _search_enabled_notify_subtype_ids(self, operator, value):
  71. return self._search_notify_subtype_ids_domain(
  72. operator, value, True)
  73. def _search_disabled_notify_subtype_ids(self, operator, value):
  74. return self._search_notify_subtype_ids_domain(
  75. operator, value, False)
  76. @api.multi
  77. def _notify(self, message,
  78. force_send=False, send_after_commit=True, user_signature=True):
  79. """Override to delegate domain generation."""
  80. # notify_by_email
  81. email_domain = self._get_notify_by_email_domain(
  82. message, force_send=force_send)
  83. # `sudo` from original odoo method
  84. # the reason should be that anybody can write messages to a partner
  85. # and you really want to find all ppl to be notified
  86. partners = self.sudo().search(email_domain)
  87. partners._notify_by_email(
  88. message, force_send=force_send,
  89. send_after_commit=send_after_commit, user_signature=user_signature)
  90. if not force_send:
  91. # notify_by_digest
  92. digest_domain = self._get_notify_by_email_domain(
  93. message, force_send=force_send, digest=True)
  94. partners = self.sudo().search(digest_domain)
  95. partners._notify_by_digest(message)
  96. # notify_by_chat
  97. self._notify_by_chat(message)
  98. return True
  99. def _digest_enabled_message_types(self):
  100. """Return a list of enabled message types for digest.
  101. In `_notify_by_digest` we check if digest mode is enabled
  102. for given message's type. Here we retrieve global settings
  103. from a config param that you can customize to second your needs.
  104. """
  105. param = self.env['ir.config_parameter'].sudo().get_param(
  106. 'mail_digest.enabled_message_types', default='')
  107. return [x.strip() for x in param.split(',') if x.strip()]
  108. @api.multi
  109. def _notify_by_digest(self, message):
  110. message_sudo = message.sudo()
  111. if message_sudo.message_type \
  112. not in self._digest_enabled_message_types():
  113. return
  114. self.env['mail.digest'].sudo().create_or_update(self, message)
  115. @api.model
  116. def _get_notify_by_email_domain(self, message,
  117. force_send=False, digest=False):
  118. """Return domain to collect partners to be notified by email.
  119. :param message: instance of mail.message
  120. :param force_send: whether the message should be sent immediately
  121. :param digest: include/exclude digest enabled partners
  122. NOTE: since mail.mail inherits from mail.message
  123. this method is called even when
  124. we create the final email for mail.digest object.
  125. Here we introduce a new context flag `notify_only_recipients`
  126. to explicitely retrieve only partners among message's recipients.
  127. """
  128. message_sudo = message.sudo()
  129. channels = message.channel_ids.filtered(
  130. lambda channel: channel.email_send)
  131. email = message_sudo.author_id \
  132. and message_sudo.author_id.email or message.email_from
  133. ids = self.ids
  134. if self.env.context.get('notify_only_recipients'):
  135. ids = [x for x in ids if x in message.partner_ids.ids]
  136. domain = [
  137. '|',
  138. ('id', 'in', ids),
  139. ('channel_ids', 'in', channels.ids),
  140. ('email', '!=', email)
  141. ]
  142. if force_send:
  143. return domain
  144. if not digest:
  145. domain.append(('notify_email', 'not in', ('none', 'digest')))
  146. else:
  147. domain.append(('notify_email', '=', 'digest'))
  148. if message.subtype_id:
  149. domain.extend(self._get_domain_subtype_leaf(message.subtype_id))
  150. return domain
  151. @api.model
  152. def _get_domain_subtype_leaf(self, subtype):
  153. return [
  154. '|',
  155. ('disabled_notify_subtype_ids', 'not in', (subtype.id, )),
  156. ('enabled_notify_subtype_ids', 'in', (subtype.id, )),
  157. ]
  158. @api.multi
  159. def _notify_update_subtype(self, subtype, enable):
  160. """Update notification settings by subtype.
  161. :param subtype: `mail.message.subtype` to enable or disable
  162. :param enable: boolean to enable or disable given subtype
  163. """
  164. self.ensure_one()
  165. exists = self.env['partner.notification.conf'].search([
  166. ('subtype_id', '=', subtype.id),
  167. ('partner_id', '=', self.id)
  168. ], limit=1)
  169. if exists:
  170. exists.enabled = enable
  171. else:
  172. self.write({
  173. 'notify_conf_ids': [
  174. (0, 0, {'enabled': enable, 'subtype_id': subtype.id})]
  175. })
  176. @api.multi
  177. def _notify_enable_subtype(self, subtype):
  178. """Enable given subtype."""
  179. self._notify_update_subtype(subtype, True)
  180. @api.multi
  181. def _notify_disable_subtype(self, subtype):
  182. """Disable given subtype."""
  183. self._notify_update_subtype(subtype, False)
  184. class PartnerNotificationConf(models.Model):
  185. """Hold partner's single notification configuration."""
  186. _name = 'partner.notification.conf'
  187. _description = 'Partner notification configuration'
  188. # TODO: add friendly onchange to not yield errors when editin via UI
  189. _sql_constraints = [
  190. ('unique_partner_subtype_conf',
  191. 'unique (partner_id,subtype_id)',
  192. 'You can have only one configuration per subtype!')
  193. ]
  194. partner_id = fields.Many2one(
  195. string='Partner',
  196. comodel_name='res.partner',
  197. readonly=True,
  198. required=True,
  199. ondelete='cascade',
  200. index=True,
  201. )
  202. subtype_id = fields.Many2one(
  203. 'mail.message.subtype',
  204. 'Notification type',
  205. ondelete='cascade',
  206. required=True,
  207. index=True,
  208. )
  209. enabled = fields.Boolean(default=True, index=True)