From 06e13555d51aace43ea6b2b36d717e58f6c2ba7f Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 30 Aug 2012 14:21:12 +0200 Subject: [PATCH 1/5] [FIX] mail: simplify test and cleanup some code + fix plaintext signature append bzr revid: odo@openerp.com-20120830122112-y2lbgcazy0opvbs8 --- addons/mail/mail_followers.py | 24 ++--- addons/mail/mail_message.py | 20 ++-- addons/mail/mail_thread.py | 15 ++- addons/mail/tests/test_mail.py | 174 ++++++++++++--------------------- 4 files changed, 94 insertions(+), 139 deletions(-) diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index b18832fa9cd..10d33536136 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -79,19 +79,19 @@ class mail_notification(osv.Model): if context.get('mail_noemail') or not partner_ids: return True - mail_mail_obj = self.pool.get('mail.mail') - msg_obj = self.pool.get('mail.message') - msg = msg_obj.browse(cr, uid, msg_id, context=context) + mail_mail = self.pool.get('mail.mail') + msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context) # add signature body_html = msg.body signature = msg.author_id and msg.author_id.user_ids[0].signature or '' - insertion_point = body_html.find('') - if insertion_point > -1: + if signature: + signature_block = u'\n
%s
\n' % signature insertion_point = body_html.find('') - body_html = body_html[:insertion_point] + '
%s
' % tools.ustr(signature) + body_html[insertion_point:] - else: - body_html = body_html + '
%s
' % tools.ustr(signature) + if insertion_point > -1: + body_html = body_html[:insertion_point] + signature_block + body_html[insertion_point:] + else: + body_html += signature_block towrite = { 'mail_message_id': msg.id, @@ -118,8 +118,8 @@ class mail_notification(osv.Model): continue if partner.email not in towrite['email_to']: towrite['email_to'].append(partner.email) - towrite['email_to'] = ', '.join(towrite['email_to']) - - email_notif_id = mail_mail_obj.create(cr, uid, towrite, context=context) - mail_mail_obj.send(cr, uid, [email_notif_id], context=context) + if towrite['email_to']: + towrite['email_to'] = ', '.join(towrite['email_to']) + email_notif_id = mail_mail.create(cr, uid, towrite, context=context) + mail_mail.send(cr, uid, [email_notif_id], context=context) return True diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 97473886e1a..413606b9ed2 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -330,19 +330,19 @@ class mail_message(osv.Model): Call mail_notification.notify to manage the email sending """ message = self.browse(cr, uid, newid, context=context) - partners_to_notify = [] + partners_to_notify = set([]) # add all partner_ids of the message if message.partner_ids: - for partner in message.partner_ids: - if partner.id not in partners_to_notify: - partners_to_notify.append(partner.id) - # add all followers and set them as partner_ids + partners_to_notify |= set(partner.id for partner in message.partner_ids) + # add all followers and set add them in partner_ids if message.model and message.res_id: - modobj = self.pool.get(message.model) - for follower in modobj.browse(cr, uid, message.res_id, context=context).message_follower_ids: - partners_to_notify.append(follower.id) - self.write(cr, uid, [newid], {'partner_ids': [(4, follower.id)]}, context=context) - self.pool.get('mail.notification').notify(cr, uid, partners_to_notify, newid, context=context) + record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context) + extra_notified = set(partner.id for partner in record.message_follower_ids) + missing_notified = extra_notified - partners_to_notify + if missing_notified: + message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]}) + partners_to_notify |= extra_notified + self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context) def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'): self.check(cr, uid, ids, 'read', context=context) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index eb9b48bbc5f..5c4ecbd48f6 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -475,16 +475,25 @@ class mail_thread(osv.Model): # plain text is wrapped in
 to preserve formatting
                     text = u'
%s
' % tools.ustr(part.get_payload(decode=True), encoding, errors='replace') - body = body[:insertion_point] + text + body[:insertion_point] + if insertion_point != -1: + body = body[:insertion_point] + text + body[insertion_point:] + else: + body += text # 3) text/html -> raw elif part.get_content_type() == 'text/html': html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace') if alternative: body = html + # force tag to lowercase, for easier matching + body = re.sub(r'(?i)', r'', body) else: - html = re.sub('(?i)', '', html) + # strip enclosing html/body tags and append to existing body + html = re.sub(r'(?i)(|)', '', html) insertion_point = body.find('') - body = body[:insertion_point] + text + body[:insertion_point] + if insertion_point != -1: + body = body[:insertion_point] + html + body[insertion_point:] + else: + body += html # 4) Anything else -> attachment else: attachments.append((filename or 'attachment', part.get_payload(decode=True))) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 858e5e868ad..86f3997c6b7 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -150,69 +150,47 @@ class test_mail(common.TransactionCase): {'res_model': 'mail.group', 'res_id': group_dummy_id, 'partner_id': partner_bert_id}) # Pigs just created: should be only Admin as follower - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 1, - 'Newly created group should have only 1 follower') - self.assertTrue(user_admin.partner_id.id in follower_ids, - 'Admin should be the only Pigs group follower') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan') # Subscribe Bert through a '4' command group_pigs.write({'message_follower_ids': [(4, partner_bert_id)]}) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 2, - 'Pigs group should have 2 followers after linking Bert') - self.assertTrue(all(id in follower_ids for id in [partner_bert_id, user_admin.partner_id.id]), - 'Bert and Admin should be the 2 Pigs group followers') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the only Pigs fans') # Unsubscribe Bert through a '3' command group_pigs.write({'message_follower_ids': [(3, partner_bert_id)]}) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 1, - 'Pigs group should have 1 follower after unlinking Bert') - self.assertTrue(all(id in follower_ids for id in [user_admin.partner_id.id]), - 'Admin should be the only Pigs group follower') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan') # Set followers through a '6' command group_pigs.write({'message_follower_ids': [(6, 0, [partner_bert_id])]}) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 1, - 'Pigs group should have 1 follower after replacing followers') - self.assertTrue(follower_ids == [partner_bert_id], - 'Bert should be the only Pigs group follower') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the only Pigs fan') # Add a follower created on the fly through a '0' command group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]}) partner_patrick_id = self.res_partner.search(cr, uid, [('name', '=', 'Patrick Fiori')])[0] group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 2, - 'Pigs group should have 2 followers after linking to new partner') - self.assertTrue(all(id in follower_ids for id in [partner_bert_id, partner_patrick_id]), - 'Bert and Patrick should be Pigs group followers') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([partner_bert_id, partner_patrick_id]), 'Bert and Patrick should be the only Pigs fans') # Finally, unlink through a '5' command group_pigs.write({'message_follower_ids': [(5, 0)]}) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 0, - 'Pigs group should not have followers anymore') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertFalse(follower_ids, 'Pigs group should not have fans anymore') # Test dummy data has not been altered fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.thread'), ('res_id', '=', self.group_pigs_id)]) - follower_ids = [follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)] - self.assertTrue(len(follower_ids) == 1, - 'mail.thread dummy data should have 1 follower') - self.assertTrue(follower_ids[0] == partner_bert_id, - 'Bert should be the follower of dummy mail.thread data') + follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]) + self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the follower of dummy mail.thread data') fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', group_dummy_id)]) - follower_ids = [follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)] - self.assertTrue(len(follower_ids) == 2, - 'mail.group dummy data should have 2 followers') - self.assertTrue(all(id in follower_ids for id in [partner_bert_id, user_admin.partner_id.id]), - 'Bert and Admin should be the followers of dummy mail.group data') + follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]) + self.assertEqual(follower_ids,set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data') def test_11_message_followers(self): """ Tests designed for the subscriber API. """ @@ -227,21 +205,14 @@ class test_mail(common.TransactionCase): # Subscribe Raoul twice (niak niak) through message_subscribe_users group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id]) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 2, - 'Pigs group should have 2 followers after having subscribed Raoul. Subscribing twice '\ - 'the same user should create only one follower.') - self.assertTrue(all(id in follower_ids for id in [user_raoul.partner_id.id, user_admin.partner_id.id]), - 'Admin and Raoul should be the 2 Pigs group followers') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([user_raoul.partner_id.id, user_admin.partner_id.id]), 'Admin and Raoul should be the only 2 Pigs group followers') # Unsubscribe Raoul twice through message_unsubscribe_users group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id]) group_pigs.refresh() - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertTrue(len(follower_ids) == 1, - 'Pigs group should have 1 follower after unsubscribing Raoul') - self.assertTrue(all(id in follower_ids for id in [user_admin.partner_id.id]), - 'Admin the only Pigs group followers') + follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) + self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin must be the only Pigs fan') def test_20_message_post(self): """ Tests designed for message_post. """ @@ -266,97 +237,72 @@ class test_mail(common.TransactionCase): _subject = 'Pigs' _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name) _body1 = 'Pigs rules' - _mail_body1 = 'Pigs rules
Admin
' + _mail_body1 = 'Pigs rules\n
Admin
\n' _mail_bodyalt1 = 'Pigs rules\nAdmin' _body2 = 'Pigs rules' - _mail_body2 = 'Pigs rules
Admin
' - _mail_bodyalt2 = 'Pigs rules\nAdmin' + _mail_body2 = 'Pigs rules\n
Admin
\n' + _mail_bodyalt2 = 'Pigs rules\nAdmin\n' # Post comment with body and subject, comment preference msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, msg_type='comment') - # Fetch: created mail_message, mail_mail, send_email + # Fetch: created mail_message, mail_mail, sent_email message = self.mail_message.browse(cr, uid, msg_id) mail_ids = self.mail_mail.search(cr, uid, [], limit=1) mail = self.mail_mail.browse(cr, uid, mail_ids[0]) - send_email = self._build_email_kwargs + sent_email = self._build_email_kwargs # Test: mail_message: subject is _subject, body is _body1 (no formatting done) - self.assertEqual(message.subject, _subject, - 'mail.message subject is %s; should be %s' % (message.subject, _subject)) - self.assertEqual(message.body, _body1, - 'mail.message body is %s; should be %s' % (message.body, _body1)) + self.assertEqual(message.subject, _subject, 'mail.message subject incorrect') + self.assertEqual(message.body, _body1, 'mail.message body incorrect') # Test: mail_mail: subject is _subject, body_html is _mail_body1 (signature appended) - self.assertEqual(mail.subject, _subject, - 'mail.mail subject is %s; should be %s' % (mail.subject, _subject)) - self.assertEqual(mail.body_html, _mail_body1, - 'mail.mail body_html is %s; should be %s' % (mail.body_html, _mail_body1)) - self.assertTrue(mail.mail_message_id and mail.mail_message_id.id == msg_id, - 'mail_mail.mail_message_id is not the id of its related mail_message; got %s, should be %s' % (mail.mail_message_id.id, msg_id)) - # Test: send_email: email send by server: correct subject and body - self.assertEqual(send_email['subject'], _subject, - 'send_email subject is %s; should be %s' % (send_email['subject'], _subject)) - self.assertEqual(send_email['body'], _mail_body1, - 'send_email body is %s; should be %s' % (send_email['body'], _mail_body1)) - self.assertEqual(send_email['body_alternative'], _mail_bodyalt1, - 'send_email body_alternative is %s; should be %s' % (send_email['body_alternative'], _mail_bodyalt1)) + self.assertEqual(mail.subject, _subject, 'mail.mail subject incorrect') + self.assertEqual(mail.body_html, _mail_body1, 'mail.mail body_html incorrect') + self.assertEqual(mail.mail_message_id.id, msg_id, 'mail_mail.mail_message_id is not the id of its related mail_message)') + # Test: sent_email: email send by server: correct subject and body + self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect') + self.assertEqual(sent_email['body'], _mail_body1, 'sent_email body incorrect') + self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1, 'sent_email body_alternative is incorrect') # Test: mail_message: partner_ids = group followers - message_pids = [partner.id for partner in message.partner_ids] - test_pids = [p_a_id, p_b_id, p_c_id] - self.assertTrue(all(pid in message_pids for pid in test_pids) and len(message_pids) == len(test_pids), - 'mail.message partners are %s; should be %s' % (message_pids, test_pids)) + message_pids = set([partner.id for partner in message.partner_ids]) + test_pids = set([p_a_id, p_b_id, p_c_id]) + self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect') # Test: notification linked to this message = group followers = partner_ids notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)]) - notif_pids = [notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)] - self.assertTrue(all(pid in notif_pids for pid in test_pids) and len(notif_pids) == len(test_pids), - 'mail.message notification partners are %s; should be %s' % (notif_pids, test_pids)) - # Test: send_email: email_to should contain b@b, not c@c (pref email), not a@a (writer) - test_emails = ['b@b'] - self.assertTrue(all(email in send_email['email_to'] for email in test_emails) and len(send_email['email_to']) == len(test_emails), - 'send_email email_to is %s; should be %s' % (send_email['email_to'], test_emails)) + notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) + self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') + # Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer) + self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect') # New post: test automatic subject, signature in html, add a partner, email preference, parent_id previous message msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, msg_type='email', partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id) - # Fetch: created mail_message, mail_mail, send_email + # Fetch: created mail_message, mail_mail, sent_email message = self.mail_message.browse(cr, uid, msg_id2) mail_ids = self.mail_mail.search(cr, uid, [], limit=1) mail = self.mail_mail.browse(cr, uid, mail_ids[0]) - send_email = self._build_email_kwargs + sent_email = self._build_email_kwargs # Test: mail_message: subject is False, body is _body1 (no formatting done), parent_id is msg_id - self.assertEqual(message.subject, False, - 'mail.message subject is %s; should be %s' % (message.subject, False)) - self.assertEqual(message.body, _body2, - 'mail.message body is %s; should be %s' % (message.body, _body2)) - self.assertEqual(message.parent_id.id, msg_id, - 'mail.message parent_id is %s; should be %s' % (message.parent_id.id, msg_id)) + self.assertEqual(message.subject, False, 'mail.message subject incorrect') + self.assertEqual(message.body, _body2, 'mail.message body incorrect') + self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect') # Test: mail_mail: subject is False, body_html is _mail_body1 (signature appended) - self.assertEqual(mail.subject, False, - 'mail.mail subject is %s; should be %s' % (mail.subject, False)) - self.assertEqual(mail.body_html, _mail_body2, - 'mail.mail body_html is %s; should be %s' % (mail.body_html, _mail_body2)) - self.assertTrue(mail.mail_message_id and mail.mail_message_id.id == msg_id2, - 'mail_mail.mail_message_id is not the id of its related mail_message; got %s, should be %s' % (mail.mail_message_id.id, msg_id2)) - # Test: send_email: email send by server: correct subject and body - self.assertEqual(send_email['subject'], _mail_subject, - 'send_email subject is %s; should be %s' % (send_email['subject'], _mail_subject)) - self.assertEqual(send_email['body'], _mail_body2, - 'send_email body is %s; should be %s' % (send_email['body'], _mail_body2)) - self.assertEqual(send_email['body_alternative'], _mail_bodyalt2, - 'send_email body_alternative is %s; should be %s' % (send_email['body_alternative'], _mail_bodyalt2)) + self.assertEqual(mail.subject, False, 'mail.mail subject is incorrect') + self.assertEqual(mail.body_html, _mail_body2, 'mail.mail body_html incorrect') + self.assertEqual(mail.mail_message_id.id, msg_id2, 'mail_mail.mail_message_id incorrect') + # Test: sent_email: email send by server: correct subject and body + self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect') + self.assertEqual(sent_email['body'], _mail_body2, 'sent_email body incorrect') + self.assertEqual(sent_email['body_alternative'], _mail_bodyalt2, 'sent_email body_alternative incorrect') # Test: mail_message: partner_ids = group followers - message_pids = [partner.id for partner in message.partner_ids] - test_pids = [p_a_id, p_b_id, p_c_id, p_d_id] - self.assertTrue(all(pid in message_pids for pid in test_pids) and len(message_pids) == len(test_pids), - 'mail.message partners are %s; should be %s' % (message_pids, test_pids)) + message_pids = set([partner.id for partner in message.partner_ids]) + test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id]) + self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect') # Test: notification linked to this message = group followers = partner_ids notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)]) - notif_pids = [notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)] - self.assertTrue(all(pid in notif_pids for pid in test_pids) and len(notif_pids) == len(test_pids), - 'mail.message notification partners are %s; should be %s' % (notif_pids, test_pids)) - # Test: send_email: email_to should contain b@b, c@c, not a@a (writer) - test_emails = ['b@b', 'c@c'] - self.assertTrue(all(email in send_email['email_to'] for email in test_emails) and len(send_email['email_to']) == len(test_emails), - 'send_email email_to is %s; should be %s' % (send_email['email_to'], test_emails)) + notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) + self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') + # Test: sent_email: email_to should contain b@b, c@c, not a@a (writer) + self.assertEqual(set(sent_email['email_to']), set(['b@b', 'c@c']), 'sent_email email_to incorrect') def test_21_message_post_attachments(self): """ Tests designed for attachments. """ From 1dce0b1dc4a8c206b4c91de3cb85900fa1634645 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 30 Aug 2012 16:18:52 +0200 Subject: [PATCH 2/5] [FIX] all mail dependencies: replace message_post call by normal record + review misc wording bzr revid: odo@openerp.com-20120830141852-ku8nql1sfkko8669 --- .../account_accountant_data.xml | 15 +++++----- .../account_voucher/account_voucher_data.xml | 17 +++++------ addons/crm/crm_data.xml | 17 ++++++----- addons/event/event_data.xml | 14 ++++++---- addons/hr/hr_data.xml | 16 ++++++----- addons/hr_evaluation/hr_evaluation_data.xml | 14 ++++++---- addons/hr_expense/__openerp__.py | 6 ++-- addons/hr_expense/hr_expense_data.xml | 16 +++++------ addons/hr_holidays/__openerp__.py | 6 ++-- addons/hr_holidays/hr_holidays_data.xml | 15 ++++++---- addons/hr_recruitment/hr_recruitment_data.xml | 15 +++++----- addons/hr_timesheet_sheet/__openerp__.py | 4 +-- .../hr_timesheet_sheet_data.xml | 28 +++++++++---------- addons/mail/data/mail_demo.xml | 23 ++++++++------- addons/mail/data/mail_group_data.xml | 16 +++++------ addons/mrp/mrp_data.xml | 16 ++++++----- addons/point_of_sale/point_of_sale_data.xml | 15 +++++----- addons/project/project_data.xml | 16 ++++++----- addons/project_gtd/project_gtd_data.xml | 15 ++++++---- addons/project_issue/__openerp__.py | 4 +-- addons/project_issue/project_issue_data.xml | 16 ++++++----- addons/purchase/purchase_data.xml | 15 +++++----- addons/sale/sale_data.xml | 15 +++++----- addons/stock/stock_data.xml | 14 ++++++---- 24 files changed, 188 insertions(+), 160 deletions(-) diff --git a/addons/account_accountant/account_accountant_data.xml b/addons/account_accountant/account_accountant_data.xml index 7a666c8d344..5b563017c62 100644 --- a/addons/account_accountant/account_accountant_data.xml +++ b/addons/account_accountant/account_accountant_data.xml @@ -21,13 +21,14 @@ - - - - With OpenERP's accounting, you can get an instant access to all your financial data, setup your analytic accounting, forecast your taxes, control your budgets, easily create and send invoices, record bank statements, etc. + + mail.group + + notification + Accounting and Finance application installed! + With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc. -The accounting features are fully integrated with others OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc. - Module Accounting and Finance has been installed. - +The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc. + diff --git a/addons/account_voucher/account_voucher_data.xml b/addons/account_voucher/account_voucher_data.xml index b497f4ee20e..656d2c2cd91 100644 --- a/addons/account_voucher/account_voucher_data.xml +++ b/addons/account_voucher/account_voucher_data.xml @@ -2,15 +2,16 @@ - - - - OpenERP's electronic invoicing allows to ease and fasten the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system. + + mail.group + + notification + eInvoicing & Payments application installed! + OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system. -You can track customer payments easily and automate the reminders. You get an overview of the discussion with your customers on each invoice to ensure a full traceability. +You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. -If you want to use advanced accounting features, you should install the "Accounting and Finance" module. - Module eInvoicing & Payments has been installed. - +For advanced accounting features, you should install the "Accounting and Finance" module. + diff --git a/addons/crm/crm_data.xml b/addons/crm/crm_data.xml index 52d779f4584..5bf4b5ffbf9 100644 --- a/addons/crm/crm_data.xml +++ b/addons/crm/crm_data.xml @@ -55,21 +55,20 @@ - - - - From the top menu Sales, you can: trace leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects. + + mail.group + + notification + CRM application installed! + From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects. +To manage quotations and sale orders, install the "Sales Management" application. + -To manage quotations and sale orders, install the module "Sales Management". - Module CRM has been installed - - sales {'type':'lead'} - diff --git a/addons/event/event_data.xml b/addons/event/event_data.xml index 83af2f35cfb..2c19fdc574f 100644 --- a/addons/event/event_data.xml +++ b/addons/event/event_data.xml @@ -14,11 +14,13 @@ - - - - From the top menu Events, you can organize events, manage registrations, automate communication around your event and sell events through your quotations. - Module Events Organisation has been installed - + + mail.group + + notification + Events Organisation application installed! + From the top Events menu, you can organize events, manage registrations, automate communication around your event and sell events through your quotations. + + diff --git a/addons/hr/hr_data.xml b/addons/hr/hr_data.xml index 0f5bbdf2d26..514cf1f80f6 100644 --- a/addons/hr/hr_data.xml +++ b/addons/hr/hr_data.xml @@ -2,14 +2,16 @@ - - - - Manage your human resources in OpenERP: employees and hierarchy, HR departments and jobs. + + mail.group + + notification + Employee Directory application installed! + Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions. -More HR features are available from the following modules: Recruitment Process (manage job positions and recruitment), Timesheets Validation (record timesheets and attendance), Leaves Management (keep track of employee leaves), Expenses Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager.) - Module Employee Directory has been installed - +More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance), +Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager). + Administrator diff --git a/addons/hr_evaluation/hr_evaluation_data.xml b/addons/hr_evaluation/hr_evaluation_data.xml index 6f122e44e9b..2cf656a72bb 100644 --- a/addons/hr_evaluation/hr_evaluation_data.xml +++ b/addons/hr_evaluation/hr_evaluation_data.xml @@ -14,12 +14,14 @@ 100 - - - - Create evaluations for your subordinates or manager. You can define a plan with several surveys, where you organize evaluation surveys related to the hierarchy levels. Evaluations filled by employees can exported as pdf files. - Module Employee Appraisals has been installed - + + mail.group + + notification + Employee Appraisals application installed! + Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels. +Evaluations filled by employees may be exported as pdf files. + Self Appraisal diff --git a/addons/hr_expense/__openerp__.py b/addons/hr_expense/__openerp__.py index 9c148ad9019..63fca88b148 100644 --- a/addons/hr_expense/__openerp__.py +++ b/addons/hr_expense/__openerp__.py @@ -21,14 +21,14 @@ { - 'name': 'Expenses Management', + 'name': 'Expense Management', 'version': '1.0', 'category': 'Human Resources', 'sequence': 30, 'summary': 'Expenses Validation, Invoicing', 'description': """ -This module aims to manage employee's expenses. -=============================================== +This module aims to manage employee expenses. +============================================= The whole workflow is implemented: ---------------------------------- diff --git a/addons/hr_expense/hr_expense_data.xml b/addons/hr_expense/hr_expense_data.xml index d5123df7ee8..2a9f3ae0a56 100644 --- a/addons/hr_expense/hr_expense_data.xml +++ b/addons/hr_expense/hr_expense_data.xml @@ -2,20 +2,20 @@ - - - - Manage your employee's expenses, with validations by employee manager and accountant, creation and payment of invoices. + + mail.group + + notification + Expense Management application installed! + Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices. -This module also uses the analytic accounting and is compatible with the invoice on timesheet module so that you will be able to automatically re-invoice your customer's expenses if your work by project. - Module Expenses Management has been installed - +This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers. + Expenses - diff --git a/addons/hr_holidays/__openerp__.py b/addons/hr_holidays/__openerp__.py index d5a2728c763..070ae0344b0 100644 --- a/addons/hr_holidays/__openerp__.py +++ b/addons/hr_holidays/__openerp__.py @@ -21,7 +21,7 @@ { - 'name': 'Leaves Management', + 'name': 'Leave Management', 'version': '1.5', 'author': 'OpenERP SA', 'category': 'Human Resources', @@ -29,8 +29,8 @@ 'summary': 'Holidays, Allocation and Leave Requests', 'website': 'http://www.openerp.com', 'description': """ -This module allows you to manage leaves and leave's requests. -============================================================= +This module allows you to manage leaves and leave requests. +=========================================================== Implements a dashboard for human resource management that includes: ------------------------------------------------------------------- diff --git a/addons/hr_holidays/hr_holidays_data.xml b/addons/hr_holidays/hr_holidays_data.xml index 5c8e4922259..1e534093eb3 100644 --- a/addons/hr_holidays/hr_holidays_data.xml +++ b/addons/hr_holidays/hr_holidays_data.xml @@ -13,12 +13,15 @@ 100 - - - - Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR people. Once validated, they are visible in the employee's calendar. HR people can define leave types and allocate off-days for employees. - Module Leaves Management has been installed - + + mail.group + + notification + Leave Management application installed! + Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers. +Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories. + + diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml index 58a0595c857..84289da7bae 100644 --- a/addons/hr_recruitment/hr_recruitment_data.xml +++ b/addons/hr_recruitment/hr_recruitment_data.xml @@ -2,14 +2,15 @@ - - - - Manage job positions and the recruitment process in your company. This module is integrated with the module Survey to help you to define interviews for different jobs. + + mail.group + + notification + Recruitment Process application installed! + Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs. -You can automatically create application records from an email gateway, that you can configure in the Human Resources Settings. - Module Recruitment Process has been installed - +You can automatically receive job application though an email gateway, see the Human Resources settings. + diff --git a/addons/hr_timesheet_sheet/__openerp__.py b/addons/hr_timesheet_sheet/__openerp__.py index 34fbb602c9a..b1f03e7d6e0 100644 --- a/addons/hr_timesheet_sheet/__openerp__.py +++ b/addons/hr_timesheet_sheet/__openerp__.py @@ -27,8 +27,8 @@ 'sequence': 16, 'summary': 'Timesheets, Attendances, Activities', 'description': """ -This module helps you to easily encode and validate timesheet and attendances within the same view. -=================================================================================================== +This module helps you to easily record and validate timesheets and attendances within the same view. +==================================================================================================== * It will maintain attendances and track (sign in/sign out) events. * Track the timesheet lines. diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml index 046fd7fe3d0..87edf949972 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml @@ -1,23 +1,23 @@ - - - - - From the top menu "Human Resources", encode and validate timesheets and attendances. - Module Timesheets Validation has been installed - + + + mail.group + + notification + Timesheet Validation application installed! + From the top menu "Human Resources", enter and validate timesheets and attendances. + - - - + + code + ir.actions.server - - - - + action = pool.get('hr.timesheet.current.open').open_timesheet(cr, uid, None, context) + True + My Timesheet diff --git a/addons/mail/data/mail_demo.xml b/addons/mail/data/mail_demo.xml index ed30d38b8d3..1350fd33547 100644 --- a/addons/mail/data/mail_demo.xml +++ b/addons/mail/data/mail_demo.xml @@ -4,9 +4,9 @@ mail.group - - + + Your monthly meal vouchers arrived. You can get them at Christine's office. +This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year. comment @@ -21,7 +21,7 @@ This month you also have 250 EUR of eco-checks for all employees that worked wit mail.group - + Thanks, but where is Christine's office, if I may ask? (I'm new here) comment @@ -29,16 +29,19 @@ This month you also have 250 EUR of eco-checks for all employees that worked wit mail.group - + Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers! comment + + mail.group + + Building B3, second floor on the right :-) + + comment + + mail.catchall.domain demo.openerp.com diff --git a/addons/mail/data/mail_group_data.xml b/addons/mail/data/mail_group_data.xml index c9ac97e6836..53720926a5c 100644 --- a/addons/mail/data/mail_group_data.xml +++ b/addons/mail/data/mail_group_data.xml @@ -13,16 +13,16 @@ - - - - Your homepage is a summary of messages you received and key information about documents you follow. + + mail.group + + notification + Welcome to OpenERP! + Your homepage is a summary of messages you received and key information about documents you follow. The top menu bar contains all applications you installed. You can use this <i>Settings</i> menu to install more applications, activate others features or give access to new users. -To setup your preferences (name, email signature, avatar), click on the top right corner. - Welcome to OpenERP! - - +To setup your preferences (name, email signature, avatar), click on the top right corner. + diff --git a/addons/mrp/mrp_data.xml b/addons/mrp/mrp_data.xml index d8d7d2063dc..0bbf2d3b64c 100644 --- a/addons/mrp/mrp_data.xml +++ b/addons/mrp/mrp_data.xml @@ -2,14 +2,16 @@ - - - - Manage your manufacturing process in OpenERP by defining bill of materials (BoM), routings and work centers. This module supports complete integration and planification of stockable goods, consumable, and services. + + mail.group + + notification + MRP application installed! + Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers. +This application supports complete integration and production scheduling for stockable goods, consumables, and services. -From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time. - Module MRP has been installed - +From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time. + Production order diff --git a/addons/point_of_sale/point_of_sale_data.xml b/addons/point_of_sale/point_of_sale_data.xml index 33ea01a6f5e..35a2516da02 100644 --- a/addons/point_of_sale/point_of_sale_data.xml +++ b/addons/point_of_sale/point_of_sale_data.xml @@ -24,14 +24,15 @@ - - - - Encode sale orders, register payments, compute money to return, create invoices, and manage refunds of former sales through a specific, web-based, touch-screen user interface. + + mail.group + + notification + Point of Sale application installed! + Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface. -If you install the PoS proxy, you will be able to interface OpenERP with retail materials; barcode scanners, printers, cash registers, weighing machine, credit card payments. - Module Point of Sale has been installed - +If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals. + 1.00 diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml index d661ad2b68c..5cc4c99df1b 100644 --- a/addons/project/project_data.xml +++ b/addons/project/project_data.xml @@ -85,13 +85,15 @@ - - - - Manage multi-level projects and tasks. You can delegate tasks, track the work done on tasks, and review your planning based on the entered data. + + mail.group + + notification + Project Management application installed! + Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning. -You can manage todo lists on tasks by installing the module "Todo Lists", which supports the methodology Getting Things Done (GTD). You can also manage issues/bugs in projects by installing the module "Issues Tracker." - Module Project Management has been installed - +You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology. +You can also manage issues/bugs in projects by installing the "Issue Tracker" application. + diff --git a/addons/project_gtd/project_gtd_data.xml b/addons/project_gtd/project_gtd_data.xml index d46bc0fda14..61b2468329c 100644 --- a/addons/project_gtd/project_gtd_data.xml +++ b/addons/project_gtd/project_gtd_data.xml @@ -26,11 +26,14 @@ - - - - Add todo items on project tasks, to help you organize your work. This module supports the methodology Getting Things Done (GTD), created by David Allen, and described in the book of the same name. - Module Todo Lists has been installed - + + mail.group + + notification + Todo Lists application installed! + Add todo items on project tasks, to help you organize your work. +This application supports the Getting Things Done (GTD) methodology, based on David Allen's book. + + diff --git a/addons/project_issue/__openerp__.py b/addons/project_issue/__openerp__.py index 07e453af885..3d005f3fad6 100644 --- a/addons/project_issue/__openerp__.py +++ b/addons/project_issue/__openerp__.py @@ -21,11 +21,11 @@ ############################################################################## { - 'name': 'Issues Tracker', + 'name': 'Issue Tracker', 'version': '1.0', 'category': 'Project Management', 'sequence': 22, - 'summary': 'Support, Bug Traker, Helpdesk', + 'summary': 'Support, Bug Tracker, Helpdesk', 'description': """ This module provides Issues/Bugs Management in Project. ======================================================= diff --git a/addons/project_issue/project_issue_data.xml b/addons/project_issue/project_issue_data.xml index 5df09b683ca..ddb0d575e63 100644 --- a/addons/project_issue/project_issue_data.xml +++ b/addons/project_issue/project_issue_data.xml @@ -32,13 +32,15 @@ - - - - Manage the issues you might face in a project, like bugs in a system, client complaints or material breakdowns. You can record issues, assign them to some responsible person, and keep track of their status as they evolve over time. + + mail.group + + notification + Issue Tracker application installed! + Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns. +You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time. +Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view. + -You can access issues from the top menu Project, and access the issues of a specific project from the projects gallery view. - Module Issues Tracker has been installed. - diff --git a/addons/purchase/purchase_data.xml b/addons/purchase/purchase_data.xml index 802f415d01f..693d18eb1ba 100644 --- a/addons/purchase/purchase_data.xml +++ b/addons/purchase/purchase_data.xml @@ -3,14 +3,15 @@ - - - - From the top menu Purchases, create purchase orders to buy products from your suppliers, encode supplier invoices and manage your payments. + + mail.group + + notification + Purchase Management application installed! + From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments. -You can also manage purchase requisitions, see the Purchase Settings. - Module Purchase Management has been installed. - +You can also manage purchase requisitions, see also the Purchase Settings. + Purchase Order diff --git a/addons/sale/sale_data.xml b/addons/sale/sale_data.xml index 95d7b6d21e2..a2ef6ddd802 100644 --- a/addons/sale/sale_data.xml +++ b/addons/sale/sale_data.xml @@ -41,13 +41,14 @@ - - - - This modules allows you to create and send easily quotations and process your sales orders; from the delivery to the invoicing. + + mail.group + + notification + Sales Management application installed! + This application lets you create and send quotations and process your sales orders; from delivery to invoicing. -If you need to manage your sales pipeline (leads, opportunities, phonecalls), you can install the module <i>CRM</i> from the top menu Settings. - The Sales Management application has been installed. - +If you need to manage your sales pipeline (leads, opportunities, phonecalls), the <i>CRM</i> application may be useful. Use the Settings menu to install it. + diff --git a/addons/stock/stock_data.xml b/addons/stock/stock_data.xml index 282929ea6fb..77c82989a21 100644 --- a/addons/stock/stock_data.xml +++ b/addons/stock/stock_data.xml @@ -2,12 +2,14 @@ - - - - Manage your product inventoy and stock locations. You can control your stock moves history and planning, perform stock valuation, and trace product lots upstream and downstream (based on serial numbers.) - Module Warehouse Management has been installed - + + mail.group + + notification + Warehouse Management application installed! + Manage your product inventoy and stock locations: you can control stock moves history and planning, +watch your stock valuation, and track production lots upstream and downstream (based on serial numbers). + Stock Journal Sequence From 00fc7d1e88ddba7633ebc850f23c34a2ea858fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 30 Aug 2012 16:35:49 +0200 Subject: [PATCH 3/5] [IMP] mail.compose.message: added basic mass_mail support back. Moved generation into a dedicated method, to be inherited in email_template. Added somes tests in mail to test mass_mailing without email_template. bzr revid: tde@openerp.com-20120830143549-33sgtd30asvztg2c --- addons/mail/tests/test_mail.py | 23 ++- addons/mail/wizard/mail_compose_message.py | 134 ++++++++++-------- .../mail/wizard/mail_compose_message_view.xml | 10 +- 3 files changed, 104 insertions(+), 63 deletions(-) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 86f3997c6b7..12ae25e1815 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -97,7 +97,8 @@ class test_mail(common.TransactionCase): 'alias_model_id': self.mail_group_model_id}) # create a 'pigs' group that will be used through the various tests - self.group_pigs_id = self.mail_group.create(self.cr, self.uid, {'name': 'pigs'}) + self.group_pigs_id = self.mail_group.create(self.cr, self.uid, + {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) def test_00_message_process(self): cr, uid = self.cr, self.uid @@ -375,6 +376,26 @@ class test_mail(common.TransactionCase): self.assertEqual(compose.parent_id.id, msg.id, 'Wizard parent_id is %d; should be %d' % (compose.parent_id.id, msg.id)) + # 3 - Create in mass_mail composition mode that should work with or without email_template installed + compose_id = mail_compose.create(cr, uid, + {'subject': _subject, 'body': '${object.description}'}, + {'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1, + 'active_ids': [self.group_pigs_id]}) + compose = mail_compose.browse(cr, uid, compose_id) + + # Post the comment, get created message + mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id]}) + group_pigs.refresh() + msg = group_pigs.message_ids[0] + + # Test: last message on Pigs = last created message + test_msg = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [], limit=1))[0] + self.assertEqual(msg.id, test_msg.id, 'Pigs did not receive its mass mailing message') + # Test: mail.message: subject, body + self.assertEqual(msg.subject, _subject, 'mail.message subject is incorrect') + self.assertEqual(msg.body, group_pigs.description, 'mail.message body is incorrect') + + def test_30_message_read(self): """ Tests designed for message_read. """ def _simplify_struct(read_dict): diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index b4d992c5d1b..ae597b509ee 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -68,7 +68,7 @@ class mail_compose_message(osv.TransientModel): result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context) # get some important values from context - composition_mode = context.get('mail.compose.message.mode') + composition_mode = context.get('default_composition_mode', context.get('mail.compose.message.mode')) model = context.get('default_model', context.get('active_model')) res_id = context.get('default_res_id', context.get('active_id')) active_id = context.get('active_id') @@ -77,8 +77,10 @@ class mail_compose_message(osv.TransientModel): # get default values according to the composition mode if composition_mode in ['reply']: vals = self.get_message_data(cr, uid, active_id, context=context) - elif composition_mode in ['comment', 'mass_mail'] and model and res_id: + elif composition_mode in ['comment'] and model and res_id: vals = self.get_record_data(cr, uid, model, res_id, context=context) + elif composition_mode in ['mass_mail'] and model and active_ids: + vals = {'model': model, 'res_id': res_id, 'content_subtype': 'html'} else: vals = {'model': model, 'res_id': res_id} if composition_mode: @@ -189,91 +191,107 @@ class mail_compose_message(osv.TransientModel): """ onchange_content_subtype (values: 'plain' or 'html'). This onchange on the subtype allows to have some specific behavior when switching between text or html mode. - Basically, subject is reset when going out of html mode. This method can be overridden for models that want to have their - specific behavior. - """ + specific behavior. """ return {'value': {'content_subtype': value}} + def _verify_partner_email(self, cr, uid, partner_ids, context=None): + """ Verify that selected partner_ids have an email_address defined. + Otherwise throw a warning. """ + partner_wo_email_lst = [] + for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): + if not partner.email: + partner_wo_email_lst.append(partner) + if not partner_wo_email_lst: + return {} + warning_msg = _('The following partners chosen as recipients for the email have no email address linked :') + for partner in partner_wo_email_lst: + warning_msg += '\n- %s' % (partner.name) + return {'warning': { + 'title': _('Partners email addresses not found'), + 'message': warning_msg } + } + def onchange_partner_ids(self, cr, uid, ids, value, context=None): """ onchange_partner_ids (value format: [[6, False, [3, 4]]]). The basic purpose of this method is to check that destination partners effectively have email addresses. Otherwise a warning is thrown. """ - partner_ids = value[0][2] - partner_wo_email_lst = [] - for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): - if not partner.email: - partner_wo_email_lst.append(partner) - if not partner_wo_email_lst: - return {'value': {}} - warning_msg = _('The following partners chosen as recipients for the email have no email address linked :') - for partner in partner_wo_email_lst: - warning_msg += '\n- %s' % (partner.name) - warning = { - 'title': _('Partners email addresses not found'), - 'message': warning_msg, - } - return {'warning': warning, 'value': {}} + res = {'value': {}} + if not value or not value[0] or not value[0][0] == 6: + return + res.update(self._verify_partner_email(cr, uid, value[0][2], context=context)) + return res def send_mail(self, cr, uid, ids, context=None): """ Process the wizard content and proceed with sending the related email(s), rendering any template patterns on the fly if needed. """ if context is None: context = {} + active_ids = context.get('active_ids') for wizard in self.browse(cr, uid, ids, context=context): mass_mail_mode = wizard.composition_mode == 'mass_mail' - - attachment = {} - for attach in wizard.attachment_ids: - attachment[attach.datas_fname] = attach.datas and attach.datas or False - - # default values, according to the wizard options - subject = wizard.subject if wizard.content_subtype == 'html' else False - partner_ids = [(4, partner.id) for partner in wizard.partner_ids] - body = wizard.body if wizard.content_subtype == 'html' else '
%s
' % tools.ustr(wizard.body_text) - active_model_pool = self.pool.get(wizard.model if wizard.model else 'mail.thread') - - #TODO: TDE: WIP: have to check for mass mail and templates - no time anymore today - if context.get('mail.compose.message.mode') == 'mass_mail' and context.get('default_model', False) and context.get('default_res_id', False): - active_model = context.get('default_model', False) - active_model_pool = self.pool.get(active_model) - subject = self.render_template(cr, uid, subject, active_model, active_id) - body = self.render_template(cr, uid, wizard.body, active_model, active_id) - # TODO TDE: find partner_ids - # if email_to: find or create a partner - if values['email_to']: - partner_id = self.pool.get('mail.thread').message_partner_by_email(cr, uid, values['email_to'], context=context)['partner_id'] - if not partner_id: - partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context) - values['partner_ids'] = [partner_id] - - # determine the ids we are commenting - if mass_mail_mode: - res_ids = context.get('active_ids', []) - else: - res_ids = [wizard.res_id] - active_model_pool.message_post(cr, uid, res_ids, body=body, subject=subject, msg_type='comment', - attachments=attachment, context=context, partner_ids=partner_ids) + # wizard works in batch mode: [res_id] or active_ids + res_ids = active_ids if mass_mail_mode and wizard.model and active_ids else [wizard.res_id] + for res_id in res_ids: + # default values, according to the wizard options + post_values = { + 'subject': wizard.subject if wizard.content_subtype == 'html' else False, + 'body': wizard.body if wizard.content_subtype == 'html' else '
%s
' % tools.ustr(wizard.body_text), + 'partner_ids': [(4, partner.id) for partner in wizard.partner_ids], + 'attachments': [(attach.datas_fname, attach.datas) for attach in wizard.attachment_ids], + } + # mass mailing: render and override default values + if mass_mail_mode and wizard.model: + email_dict = self.render_message(cr, uid, wizard, wizard.model, res_id, context=context) + post_values['subject'] = email_dict.get('subject', False) + post_values['body'] = email_dict.get('body', '') + if email_dict.get('partner_ids'): + post_values['partner_ids'] += [(4, id) for id in email_dict.get('partner_ids')] + if email_dict.get('attachments'): + post_values['attachments'] += [(attach.datas_fname, attach.datas) for attach in email_dict.get('attachments')] + # post the message + active_model_pool.message_post(cr, uid, res_ids, msg_type='comment', context=context, **post_values) return {'type': 'ir.actions.act_window_close'} + def render_message(self, cr, uid, wizard, model, res_id, context=None): + """ Generate an email from the template for given (model, res_id) pair. + This method is meant to be inherited by email_template that will + produce a more complete dictionary, with email_to, ... + """ + # TDE: TODO: to move into mail.compose.message in email template + # mails = tools.email_split(email_dict.get('email_to', '')) + tools.email_split(email_dict.get('email_cc', '')) + # for mail in mails: + # partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', email)], context=context) + # if partner_search_ids: + # partner_ids.append((4, 0, partner_search_ids[0])) + # else: + # partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context) + # partner_ids.append((4, 0, partner_id)) + return { + 'subject': self.render_template(cr, uid, wizard.subject, model, res_id, context), + 'body': self.render_template(cr, uid, wizard.body, model, res_id, context), + 'partner_ids': [], + 'attachment_ids': [], + } + def render_template(self, cr, uid, template, model, res_id, context=None): - """Render the given template text, replace mako-like expressions ``${expr}`` - with the result of evaluating these expressions with an evaluation context - containing: + """ Render the given template text, replace mako-like expressions ``${expr}`` + with the result of evaluating these expressions with an evaluation context + containing: * ``user``: browse_record of the current user * ``object``: browse_record of the document record this mail is related to * ``context``: the context passed to the mail composition wizard - :param str template: the template text to render - :param str model: model name of the document record this mail is related to. - :param int res_id: id of the document record this mail is related to. + :param str template: the template text to render + :param str model: model name of the document record this mail is related to. + :param int res_id: id of the document record this mail is related to. """ if context is None: context = {} diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml index 8bf8df24f59..4ce5db3f4e3 100644 --- a/addons/mail/wizard/mail_compose_message_view.xml +++ b/addons/mail/wizard/mail_compose_message_view.xml @@ -7,6 +7,7 @@
+ @@ -38,11 +39,11 @@ + -
- +
-