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.

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