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.

401 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
10 years ago
10 years ago
10 years ago
  1. from lxml import etree
  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.needaction')
  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. r.message_id.needaction = False
  158. return {
  159. 'type': 'ir.actions.client',
  160. 'name': 'All messages',
  161. 'tag': 'reload',
  162. }
  163. return {
  164. 'name': _('Record'),
  165. 'view_type': 'form',
  166. 'view_mode': 'form',
  167. 'res_model': r.model,
  168. 'res_id': r.res_id,
  169. 'views': [(False, 'form')],
  170. 'type': 'ir.actions.act_window',
  171. }
  172. @api.one
  173. def delete(self):
  174. msg_id = self.message_id.id
  175. # Send notification
  176. notification = {'message_ids': [msg_id]}
  177. self.env['bus.bus'].sendone((self._cr.dbname, 'mail_move_message.delete_message'), notification)
  178. self.message_id.unlink()
  179. return {}
  180. @api.model
  181. def create_partner(self, message_id, relation, partner_id, message_name_from, message_email_from):
  182. model = self.env[relation]
  183. message = self.env['mail.message'].browse(message_id)
  184. if not partner_id and message_name_from:
  185. partner_id = self.env['res.partner'].with_context({'update_message_author': True}).create({
  186. 'name': message_name_from,
  187. 'email': message_email_from
  188. }).id
  189. context = {'partner_id': partner_id}
  190. if model._rec_name:
  191. context.update({'default_%s' % model._rec_name: message.subject})
  192. fields = model.fields_get()
  193. contact_field = False
  194. for n, f in fields.iteritems():
  195. if f['type'] == 'many2one' and f['relation'] == 'res.partner':
  196. contact_field = n
  197. break
  198. if contact_field:
  199. context.update({'default_%s' % contact_field: partner_id})
  200. return context
  201. @api.one
  202. def read_close(self):
  203. self.message_id.set_message_read(True)
  204. self.message_id.child_ids.set_message_read(True)
  205. return {'type': 'ir.actions.act_window_close'}
  206. class mail_message(models.Model):
  207. _inherit = 'mail.message'
  208. is_moved = fields.Boolean('Is moved')
  209. moved_from_res_id = fields.Integer('Related Document ID (Original)')
  210. moved_from_model = fields.Char('Related Document Model (Original)')
  211. moved_from_parent_id = fields.Many2one('mail.message', 'Parent Message (Original)', ondelete='set null')
  212. moved_by_message_id = fields.Many2one('mail.message', 'Moved by message', ondelete='set null', help='Top message, that initate moving this message')
  213. moved_by_user_id = fields.Many2one('res.users', 'Moved by user', ondelete='set null')
  214. all_child_ids = fields.One2many('mail.message', string='All childs', compute='_get_all_childs', help='all childs, including subchilds')
  215. @api.one
  216. def _get_all_childs(self, include_myself=True):
  217. ids = []
  218. if include_myself:
  219. ids.append(self.id)
  220. while True:
  221. new_ids = self.search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids
  222. if new_ids:
  223. ids = ids + new_ids
  224. continue
  225. break
  226. moved_childs = self.search([('moved_by_message_id', '=', self.id)]).ids
  227. self.all_child_ids = ids + moved_childs
  228. @api.multi
  229. def move_followers(self, model, ids):
  230. fol_obj = self.env['mail.followers']
  231. for message in self:
  232. followers = fol_obj.sudo().search([('res_model', '=', message.model),
  233. ('res_id', '=', message.res_id)])
  234. for f in followers:
  235. self.env[model].browse(ids).message_subscribe([f.partner_id.id], [s.id for s in f.subtype_ids])
  236. @api.one
  237. def move(self, parent_id, res_id, model, move_back, move_followers=False):
  238. if parent_id == res_id:
  239. return
  240. vals = {}
  241. if move_back:
  242. # clear variables if we move everything back
  243. vals['is_moved'] = False
  244. vals['moved_by_user_id'] = None
  245. vals['moved_by_message_id'] = None
  246. vals['moved_from_res_id'] = None
  247. vals['moved_from_model'] = None
  248. vals['moved_from_parent_id'] = None
  249. else:
  250. vals['parent_id'] = parent_id
  251. vals['res_id'] = res_id
  252. vals['model'] = model
  253. vals['is_moved'] = True
  254. vals['moved_by_user_id'] = self.env.user.id
  255. vals['moved_by_message_id'] = self.id
  256. for r in self.all_child_ids:
  257. r_vals = vals.copy()
  258. if not r.is_moved:
  259. # moved_from_* variables contain not last, but original
  260. # reference
  261. r_vals['moved_from_parent_id'] = r.parent_id.id
  262. r_vals['moved_from_res_id'] = r.res_id
  263. r_vals['moved_from_model'] = r.model
  264. elif move_back:
  265. r_vals['parent_id'] = r.moved_from_parent_id.id
  266. r_vals['res_id'] = r.moved_from_res_id
  267. r_vals['model'] = r.moved_from_model
  268. print 'update message', r, r_vals
  269. if move_followers:
  270. r.sudo().move_followers(r_vals.get('model'), r_vals.get('res_id'))
  271. r.sudo().write(r_vals)
  272. r.attachment_ids.sudo().write({
  273. 'res_id': r_vals.get('res_id'),
  274. 'res_model': r_vals.get('model')
  275. })
  276. # Send notification
  277. notification = {'message_ids': [self.id], 'values': vals}
  278. self.env['bus.bus'].sendone((self._cr.dbname, 'mail_move_message'), notification)
  279. def name_get(self, cr, uid, ids, context=None):
  280. if not (context or {}).get('extended_name'):
  281. return super(mail_message, self).name_get(cr, uid, ids, context=context)
  282. if isinstance(ids, (list, tuple)) and not len(ids):
  283. return []
  284. if isinstance(ids, (long, int)):
  285. ids = [ids]
  286. reads = self.read(cr, uid, ids, ['record_name','model', 'res_id'], context=context)
  287. res = []
  288. for record in reads:
  289. name = record['record_name'] or ''
  290. extended_name = ' [%s] ID %s' % (record.get('model', 'UNDEF'), record.get('res_id', 'UNDEF'))
  291. res.append((record['id'], name + extended_name))
  292. return res
  293. def _message_read_dict(self, cr, uid, message, parent_id=False, context=None):
  294. res = super(mail_message, self)._message_read_dict(cr, uid, message, parent_id, context)
  295. res['is_moved'] = message.is_moved
  296. return res
  297. @api.multi
  298. def message_format(self):
  299. message_values = super(mail_message, self).message_format()
  300. message_index = {message['id']: message for message in message_values}
  301. for item in self:
  302. msg = message_index.get(item.id)
  303. if msg:
  304. msg['is_moved'] = item.is_moved
  305. return message_values
  306. class mail_move_message_configuration(models.TransientModel):
  307. _name = 'mail_move_message.config.settings'
  308. _inherit = 'res.config.settings'
  309. model_ids = fields.Many2many(comodel_name='ir.model', string='Models')
  310. move_followers = fields.Boolean('Move Followers')
  311. @api.model
  312. def get_default_move_message_configs(self, fields):
  313. config_parameters = self.env['ir.config_parameter']
  314. model_obj = self.env['ir.model']
  315. model_names = config_parameters.get_param('mail_relocation_models')
  316. if not model_names:
  317. return {}
  318. model_names = model_names.split(',')
  319. model_ids = model_obj.search([('model', 'in', model_names)])
  320. return {
  321. 'model_ids': [m.id for m in model_ids],
  322. 'move_followers': config_parameters.get_param('mail_relocation_move_followers')
  323. }
  324. @api.multi
  325. def set_move_message_configs(self):
  326. config_parameters = self.env['ir.config_parameter']
  327. model_names = ''
  328. for record in self:
  329. model_names = ','.join([m.model for m in record.model_ids])
  330. config_parameters.set_param('mail_relocation_models', model_names)
  331. config_parameters.set_param('mail_relocation_move_followers', record.move_followers or '')
  332. class res_partner(models.Model):
  333. _inherit = 'res.partner'
  334. @api.model
  335. def create(self, vals):
  336. res = super(res_partner, self).create(vals)
  337. if 'update_message_author' in self.env.context and 'email' in vals:
  338. mail_message_obj = self.env['mail.message']
  339. # Escape special SQL characters in email_address to avoid invalid matches
  340. email_address = (vals['email'].replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_'))
  341. email_brackets = "<%s>" % email_address
  342. messages = mail_message_obj.search([
  343. '|',
  344. ('email_from', '=ilike', email_address),
  345. ('email_from', 'ilike', email_brackets),
  346. ('author_id', '=', False)
  347. ])
  348. if messages:
  349. messages.sudo().write({'author_id': res.id})
  350. return res