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.

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