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.

438 lines
18 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
9 years ago
9 years ago
9 years ago
  1. # -*- coding: utf-8 -*-
  2. from openerp import api
  3. from openerp import fields
  4. from openerp import models
  5. from openerp.tools import email_split
  6. from openerp.tools.translate import _
  7. class Wizard(models.TransientModel):
  8. _name = 'mail_move_message.wizard'
  9. def _model_selection(self):
  10. selection = []
  11. config_parameters = self.env['ir.config_parameter']
  12. model_names = config_parameters.get_param('mail_relocation_models')
  13. model_names = model_names.split(',') if model_names else []
  14. if 'default_message_id' in self.env.context:
  15. message = self.env['mail.message'].browse(self.env.context['default_message_id'])
  16. if message.model and message.model not in model_names:
  17. model_names.append(message.model)
  18. if message.moved_from_model and message.moved_from_model not in model_names:
  19. model_names.append(message.moved_from_model)
  20. if model_names:
  21. selection = [(m.model, m.display_name) for m in self.env['ir.model'].search([('model', 'in', model_names)])]
  22. return selection
  23. @api.model
  24. def default_get(self, fields_list):
  25. res = super(Wizard, self).default_get(fields_list)
  26. model_fields = self.fields_get()
  27. if model_fields['model']['selection']:
  28. res['model'] = model_fields['model']['selection'] and model_fields['model']['selection'][0][0]
  29. if 'message_id' in res:
  30. message = self.env['mail.message'].browse(res['message_id'])
  31. email_from = message.email_from
  32. parts = email_split(email_from.replace(' ', ','))
  33. if parts:
  34. email = parts[0]
  35. name = email_from.find(email) != -1 and email_from[:email_from.index(email)].replace('"', '').replace('<', '').strip() or email_from
  36. else:
  37. name, email = email_from
  38. res['message_name_from'] = name
  39. res['message_email_from'] = email
  40. res['partner_id'] = message.author_id.id
  41. if message.author_id and self.env.uid not in [u.id for u in message.author_id.user_ids]:
  42. res['filter_by_partner'] = True
  43. if message.author_id and res.get('model'):
  44. res_id = self.env[res['model']].search([], order='id desc', limit=1)
  45. if res_id:
  46. res['res_id'] = res_id[0].id
  47. config_parameters = self.env['ir.config_parameter']
  48. res['move_followers'] = config_parameters.get_param('mail_relocation_move_followers')
  49. res['uid'] = self.env.uid
  50. return res
  51. message_id = fields.Many2one('mail.message', string='Message')
  52. message_body = fields.Html(related='message_id.body', string='Message to move', readonly=True)
  53. message_from = fields.Char(related='message_id.email_from', string='From', readonly=True)
  54. message_subject = fields.Char(related='message_id.subject', string='Subject', readonly=True)
  55. message_moved_by_message_id = fields.Many2one('mail.message', related='message_id.moved_by_message_id', string='Moved with', readonly=True)
  56. message_moved_by_user_id = fields.Many2one('res.users', related='message_id.moved_by_user_id', string='Moved by', readonly=True)
  57. message_is_moved = fields.Boolean(string='Is Moved', related='message_id.is_moved', readonly=True)
  58. parent_id = fields.Many2one('mail.message', string='Search by name', )
  59. model = fields.Selection(_model_selection, string='Model')
  60. res_id = fields.Integer(string='Record')
  61. can_move = fields.Boolean('Can move', compute='_compute_can_move')
  62. move_back = fields.Boolean('MOVE TO ORIGIN', help='Move message and submessages to original place')
  63. partner_id = fields.Many2one('res.partner', string='Author')
  64. filter_by_partner = fields.Boolean('Filter Records by partner')
  65. message_email_from = fields.Char()
  66. message_name_from = fields.Char()
  67. # FIXME message_to_read should be True even if current message or any his childs are unread
  68. message_to_read = fields.Boolean(related='message_id.needaction')
  69. uid = fields.Integer()
  70. move_followers = fields.Boolean(
  71. 'Move Followers',
  72. help="Add followers of current record to a new record.\n"
  73. "You must use this option, if new record has restricted access.\n"
  74. "You can change default value for this option at Settings/System Parameters")
  75. @api.depends('message_id')
  76. @api.multi
  77. def _compute_can_move(self):
  78. for r in self:
  79. # message was not moved before OR message is a top message of previous move
  80. r.can_move = not r.message_id.moved_by_message_id or r.message_id.moved_by_message_id.id == r.message_id.id
  81. @api.onchange('move_back')
  82. def on_change_move_back(self):
  83. if not self.move_back:
  84. return
  85. self.parent_id = self.message_id.moved_from_parent_id
  86. model = self.message_id.moved_from_model
  87. if self.message_id.is_moved:
  88. self.model = model
  89. self.res_id = self.message_id.moved_from_res_id
  90. @api.onchange('parent_id', 'res_id', 'model')
  91. def update_move_back(self):
  92. model = self.message_id.moved_from_model
  93. self.move_back = self.parent_id == self.message_id.moved_from_parent_id \
  94. and self.res_id == self.message_id.moved_from_res_id \
  95. and (self.model == model or (not self.model and not model))
  96. @api.onchange('parent_id')
  97. def on_change_parent_id(self):
  98. if self.parent_id and self.parent_id.model:
  99. self.model = self.parent_id.model
  100. self.res_id = self.parent_id.res_id
  101. else:
  102. self.model = None
  103. self.res_id = None
  104. @api.onchange('model', 'filter_by_partner', 'partner_id')
  105. def on_change_partner(self):
  106. domain = {'res_id': [('id', '!=', self.message_id.res_id)]}
  107. if self.model and self.filter_by_partner and self.partner_id:
  108. fields = self.env[self.model].fields_get(False)
  109. contact_field = False
  110. for n, f in fields.iteritems():
  111. if f['type'] == 'many2one' and f['relation'] == 'res.partner':
  112. contact_field = n
  113. break
  114. if contact_field:
  115. domain['res_id'].append((contact_field, '=', self.partner_id.id))
  116. if self.model:
  117. res_id = self.env[self.model].search(domain['res_id'], order='id desc', limit=1)
  118. self.res_id = res_id and res_id[0].id
  119. else:
  120. self.res_id = None
  121. return {'domain': domain}
  122. @api.multi
  123. def check_access(self):
  124. for r in self:
  125. r.check_access_one()
  126. @api.multi
  127. def check_access_one(self):
  128. self.ensure_one()
  129. operation = 'write'
  130. if not (self.model and self.res_id):
  131. return True
  132. model_obj = self.env[self.model]
  133. mids = model_obj.browse(self.res_id).exists()
  134. if hasattr(model_obj, 'check_mail_message_access'):
  135. model_obj.check_mail_message_access(mids.ids, operation)
  136. else:
  137. self.env['mail.thread'].check_mail_message_access(mids.ids, operation, model_name=self.model)
  138. @api.multi
  139. def open_moved_by_message_id(self):
  140. message_id = None
  141. for r in self:
  142. message_id = r.message_moved_by_message_id.id
  143. return {
  144. 'type': 'ir.actions.act_window',
  145. 'res_model': 'mail_move_message.wizard',
  146. 'view_mode': 'form',
  147. 'view_type': 'form',
  148. 'views': [[False, 'form']],
  149. 'target': 'new',
  150. 'context': {'default_message_id': message_id},
  151. }
  152. @api.multi
  153. def move(self):
  154. for r in self:
  155. r.check_access()
  156. if not r.parent_id or not (r.parent_id.model == r.model and
  157. r.parent_id.res_id == r.res_id):
  158. # link with the first message of record
  159. parent = self.env['mail.message'].search([('model', '=', r.model), ('res_id', '=', r.res_id)], order='id', limit=1)
  160. r.parent_id = parent.id or None
  161. r.message_id.move(r.parent_id.id, r.res_id, r.model, r.move_back, r.move_followers)
  162. if not (r.model and r.res_id):
  163. r.message_id.needaction = False
  164. return {
  165. 'type': 'ir.actions.client',
  166. 'name': 'All messages',
  167. 'tag': 'reload',
  168. }
  169. return {
  170. 'name': _('Record'),
  171. 'view_type': 'form',
  172. 'view_mode': 'form',
  173. 'res_model': r.model,
  174. 'res_id': r.res_id,
  175. 'views': [(False, 'form')],
  176. 'type': 'ir.actions.act_window',
  177. }
  178. @api.multi
  179. def delete(self):
  180. for r in self:
  181. r.delete_one()
  182. @api.multi
  183. def delete_one(self):
  184. self.ensure_one()
  185. msg_id = self.message_id.id
  186. # Send notification
  187. notification = {'id': msg_id}
  188. self.env['bus.bus'].sendone((self._cr.dbname, 'mail_move_message.delete_message'), notification)
  189. self.message_id.unlink()
  190. return {}
  191. @api.model
  192. def create_partner(self, message_id, relation, partner_id, message_name_from, message_email_from):
  193. model = self.env[relation]
  194. message = self.env['mail.message'].browse(message_id)
  195. if not partner_id and message_name_from:
  196. partner_id = self.env['res.partner'].with_context({'update_message_author': True}).create({
  197. 'name': message_name_from,
  198. 'email': message_email_from
  199. }).id
  200. context = {'partner_id': partner_id}
  201. if model._rec_name:
  202. context.update({'default_%s' % model._rec_name: message.subject})
  203. fields = model.fields_get()
  204. contact_field = False
  205. for n, f in fields.iteritems():
  206. if f['type'] == 'many2one' and f['relation'] == 'res.partner':
  207. contact_field = n
  208. break
  209. if contact_field:
  210. context.update({'default_%s' % contact_field: partner_id})
  211. return context
  212. @api.multi
  213. def read_close(self):
  214. for r in self:
  215. r.read_close_one()
  216. @api.multi
  217. def read_close_one(self):
  218. self.ensure_one()
  219. self.message_id.set_message_done()
  220. self.message_id.child_ids.set_message_done()
  221. return {'type': 'ir.actions.act_window_close'}
  222. class MailMessage(models.Model):
  223. _inherit = 'mail.message'
  224. is_moved = fields.Boolean('Is moved')
  225. moved_from_res_id = fields.Integer('Related Document ID (Original)')
  226. moved_from_model = fields.Char('Related Document Model (Original)')
  227. moved_from_parent_id = fields.Many2one('mail.message', 'Parent Message (Original)', ondelete='set null')
  228. moved_by_message_id = fields.Many2one('mail.message', 'Moved by message', ondelete='set null', help='Top message, that initate moving this message')
  229. moved_by_user_id = fields.Many2one('res.users', 'Moved by user', ondelete='set null')
  230. all_child_ids = fields.One2many('mail.message', string='All childs', compute='_compute_all_childs', help='all childs, including subchilds')
  231. @api.multi
  232. def _compute_all_childs(self, include_myself=True):
  233. for r in self:
  234. r._compute_all_childs_one(include_myself=include_myself)
  235. @api.multi
  236. def _compute_all_childs_one(self, include_myself=True):
  237. self.ensure_one()
  238. ids = []
  239. if include_myself:
  240. ids.append(self.id)
  241. while True:
  242. new_ids = self.search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids
  243. if new_ids:
  244. ids = ids + new_ids
  245. continue
  246. break
  247. moved_childs = self.search([('moved_by_message_id', '=', self.id)]).ids
  248. self.all_child_ids = ids + moved_childs
  249. @api.multi
  250. def move_followers(self, model, ids):
  251. fol_obj = self.env['mail.followers']
  252. for message in self:
  253. followers = fol_obj.sudo().search([('res_model', '=', message.model),
  254. ('res_id', '=', message.res_id)])
  255. for f in followers:
  256. self.env[model].browse(ids).message_subscribe([f.partner_id.id], [s.id for s in f.subtype_ids])
  257. @api.multi
  258. def move(self, parent_id, res_id, model, move_back, move_followers=False):
  259. for r in self:
  260. r.move_one(parent_id, res_id, model, move_back, move_followers=move_followers)
  261. @api.multi
  262. def move_one(self, parent_id, res_id, model, move_back, move_followers=False):
  263. self.ensure_one()
  264. if parent_id == self.id:
  265. # if for any reason method is called to move message with parent
  266. # equal to oneself, we need stop to prevent infinitive loop in
  267. # building message tree
  268. return
  269. vals = {}
  270. if move_back:
  271. # clear variables if we move everything back
  272. vals['is_moved'] = False
  273. vals['moved_by_user_id'] = None
  274. vals['moved_by_message_id'] = None
  275. vals['moved_from_res_id'] = None
  276. vals['moved_from_model'] = None
  277. vals['moved_from_parent_id'] = None
  278. else:
  279. vals['parent_id'] = parent_id
  280. vals['res_id'] = res_id
  281. vals['model'] = model
  282. vals['is_moved'] = True
  283. vals['moved_by_user_id'] = self.env.user.id
  284. vals['moved_by_message_id'] = self.id
  285. # Update record_name in message
  286. vals['record_name'] = self._get_record_name(vals)
  287. for r in self.all_child_ids:
  288. r_vals = vals.copy()
  289. if not r.is_moved:
  290. # moved_from_* variables contain not last, but original
  291. # reference
  292. r_vals['moved_from_parent_id'] = r.parent_id.id
  293. r_vals['moved_from_res_id'] = r.res_id
  294. r_vals['moved_from_model'] = r.model
  295. elif move_back:
  296. r_vals['parent_id'] = r.moved_from_parent_id.id
  297. r_vals['res_id'] = r.moved_from_res_id
  298. r_vals['model'] = r.moved_from_model
  299. if move_followers:
  300. r.sudo().move_followers(r_vals.get('model'), r_vals.get('res_id'))
  301. r.sudo().write(r_vals)
  302. r.attachment_ids.sudo().write({
  303. 'res_id': r_vals.get('res_id'),
  304. 'res_model': r_vals.get('model')
  305. })
  306. # Send notification
  307. notification = {
  308. 'id': self.id,
  309. 'res_id': vals.get('res_id'),
  310. 'model': vals.get('model'),
  311. 'is_moved': vals['is_moved'],
  312. 'record_name': vals['record_name']
  313. }
  314. self.env['bus.bus'].sendone((self._cr.dbname, 'mail_move_message'), notification)
  315. @api.multi
  316. def name_get(self):
  317. context = self.env.context
  318. if not (context or {}).get('extended_name'):
  319. return super(MailMessage, self).name_get()
  320. reads = self.read(['record_name', 'model', 'res_id'])
  321. res = []
  322. for record in reads:
  323. name = record['record_name'] or ''
  324. extended_name = ' [%s] ID %s' % (record.get('model', 'UNDEF'), record.get('res_id', 'UNDEF'))
  325. res.append((record['id'], name + extended_name))
  326. return res
  327. @api.multi
  328. def message_format(self):
  329. message_values = super(MailMessage, self).message_format()
  330. message_index = {message['id']: message for message in message_values}
  331. for item in self:
  332. msg = message_index.get(item.id)
  333. if msg:
  334. msg['is_moved'] = item.is_moved
  335. return message_values
  336. class MailMoveMessageConfiguration(models.TransientModel):
  337. _name = 'mail_move_message.config.settings'
  338. _inherit = 'res.config.settings'
  339. model_ids = fields.Many2many(comodel_name='ir.model', string='Models')
  340. move_followers = fields.Boolean('Move Followers')
  341. @api.model
  342. def get_default_move_message_configs(self, fields):
  343. config_parameters = self.env['ir.config_parameter']
  344. model_obj = self.env['ir.model']
  345. model_names = config_parameters.get_param('mail_relocation_models')
  346. if not model_names:
  347. return {}
  348. model_names = model_names.split(',')
  349. model_ids = model_obj.search([('model', 'in', model_names)])
  350. return {
  351. 'model_ids': [m.id for m in model_ids],
  352. 'move_followers': config_parameters.get_param('mail_relocation_move_followers')
  353. }
  354. @api.multi
  355. def set_move_message_configs(self):
  356. config_parameters = self.env['ir.config_parameter']
  357. model_names = ''
  358. for record in self:
  359. model_names = ','.join([m.model for m in record.model_ids])
  360. config_parameters.set_param('mail_relocation_models', model_names)
  361. config_parameters.set_param('mail_relocation_move_followers', record.move_followers or '')
  362. class ResPartner(models.Model):
  363. _inherit = 'res.partner'
  364. @api.model
  365. def create(self, vals):
  366. res = super(ResPartner, self).create(vals)
  367. if 'update_message_author' in self.env.context and 'email' in vals:
  368. mail_message_obj = self.env['mail.message']
  369. # Escape special SQL characters in email_address to avoid invalid matches
  370. email_address = (vals['email'].replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_'))
  371. email_brackets = "<%s>" % email_address
  372. messages = mail_message_obj.search([
  373. '|',
  374. ('email_from', '=ilike', email_address),
  375. ('email_from', 'ilike', email_brackets),
  376. ('author_id', '=', False)
  377. ])
  378. if messages:
  379. messages.sudo().write({'author_id': res.id})
  380. return res