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.

413 lines
17 KiB

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