[MERGE] 'Invite & Quick Create User' update. Addons branch; see server branch for more details.

Quick Create:
- [ADD] in context of 'user_id' fields the xml_ids of necessary groups,
Invite:
- [ADD] added send_mail boolean field on invite wizard, allowing to avoid sending emails when inviting someone as a follower on the document,
- [IMP] notification and invite signature: improved signature (now including: sender name, company name as a link to the company website); invite message and subject improved, small code re-organization
Misc:
- [IMP] sheet tags added in various form views in HR

bzr revid: tde@openerp.com-20130318121439-xyl34r9tdut6t19c
This commit is contained in:
Thibault Delavallée 2013-03-18 13:14:39 +01:00
commit 00bb2273d9
22 changed files with 189 additions and 114 deletions

View File

@ -19,11 +19,9 @@
</header>
</xpath>
<!-- add Reset Password button -->
<xpath expr="//div[@class='oe_right oe_button_box']" position="replace">
<div class="oe_right oe_button_box">
<xpath expr="//div[@class='oe_right oe_button_box']//button" position="replace">
<button string="Send Reset Password Instructions"
type="object" name="action_reset_password" />
</div>
</xpath>
</field>
</record>

View File

@ -151,7 +151,8 @@
-->
</group>
<group>
<field name="user_id"/>
<field name="user_id"
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
<label for="section_id"/>
<div>
<field name="section_id"/>
@ -426,7 +427,7 @@
</group>
<group>
<field name="user_id"/>
<field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
<label for="section_id"/>
<div>
<field name="section_id" widget="selection"/>
@ -436,7 +437,7 @@
<group>
<field name="categ_ids"
string="Categories" widget="many2many_tags"
context = "{'object_name': 'crm.lead'}"
context="{'object_name': 'crm.lead'}"
domain="[('object_id.model', '=', 'crm.lead')]"/>
</group>

View File

@ -49,7 +49,8 @@
</group>
<group>
<field name="company_id" groups="base.group_multi_company" on_change="onchange_company(company_id)"/>
<field name="user_id" on_change="onchange_user(user_id)" string="Related User"/>
<field name="user_id" on_change="onchange_user(user_id)" string="Related User"
context="{'default_groups_ref': ['base.group_user']}"/>
</group>
</group>
<field name="notes" placeholder="Other Information ..." colspan="4"/>

View File

@ -374,6 +374,7 @@
<field name="model">hr.holidays.status</field>
<field name="arch" type="xml">
<form string="Leave Type" version="7.0">
<sheet string="Leave Type">
<group col="4">
<field name="name"/>
<field name="categ_id"/>
@ -392,6 +393,7 @@
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

View File

@ -107,7 +107,8 @@
<field name="type_id" placeholder="Degree"/>
</group>
<group>
<field name="user_id"/>
<field name="user_id"
context="{'default_groups_ref': ['base.group_user', 'base.group_hr_manager']}"/>
<label for="title_action"/>
<div>
<field name="date_action"/>
@ -341,6 +342,7 @@
<field name="model">hr.recruitment.stage</field>
<field name="arch" type="xml">
<form string="Stage" version="7.0">
<sheet>
<group string="Stage Definition">
<group>
<field name="name"/>
@ -354,6 +356,7 @@
</group>
<separator string="Requirements"/>
<field name="requirements"/>
</sheet>
</form>
</field>
</record>
@ -399,10 +402,12 @@
<field name="model">hr.recruitment.degree</field>
<field name="arch" type="xml">
<form string="Degree" version="7.0">
<sheet>
<group>
<field name="name"/>
<field name="sequence" groups="base.group_no_one"/>
</group>
</sheet>
</form>
</field>
</record>
@ -436,8 +441,12 @@
<field name="name">hr.recruitment.source.form</field>
<field name="model">hr.recruitment.source</field>
<field name="arch" type="xml">
<form string="Sources of Applicants">
<field name="name"/>
<form string="Sources of Applicants" version="7.0">
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>

View File

@ -8,7 +8,8 @@
<field name="arch" type="xml">
<tree editable="top" string="Timesheet Activities">
<field name="date" on_change="on_change_date(date)"/>
<field name="user_id" on_change="on_change_user_id(user_id)" required="1" options='{"no_open": True}'/>
<field name="user_id" on_change="on_change_user_id(user_id)" required="1" options='{"no_open": True}'
context="{'default_groups_ref': [base.group_user']}"/>
<field name="name"/>
<field domain="[('type','=','normal'),('use_timesheets','=',1)]" name="account_id" context="{'default_use_timesheets': 1, 'default_type': 'contract'}"/>
<field name="unit_amount" string="Duration" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" sum="Total time" widget="float_time"/>
@ -29,7 +30,8 @@
<group>
<group>
<field name="name"/>
<field name="user_id" on_change="on_change_user_id(user_id)" required="1"/>
<field name="user_id" on_change="on_change_user_id(user_id)" required="1"
context="{'default_groups_ref': [base.group_user']}"/>
</group>
<group>
<field name="date" on_change="on_change_date(date)"/>

View File

@ -324,7 +324,8 @@
<sheet>
<group>
<group>
<field name='user_id'/>
<field name='user_id'
context="{'default_groups_ref': ['base.group_user', 'lunch.group_lunch_user']}"/>
</group>
<group>
<field name='date'/>
@ -409,7 +410,8 @@
<form string="cashmove form" version="7.0">
<sheet>
<group>
<field name="user_id"/>
<field name="user_id"
context="{'default_groups_ref': ['base.group_user', 'lunch.group_lunch_user']}"/>
<field name="date"/>
<field name="amount"/>
</group>

View File

@ -20,6 +20,8 @@
##############################################################################
from openerp.osv import osv, fields
from openerp import tools, SUPERUSER_ID
from openerp.tools.translate import _
from openerp.tools.mail import plaintext2html
class mail_followers(osv.Model):
""" mail_followers holds the data related to the follow mechanism inside
@ -105,6 +107,43 @@ class mail_notification(osv.Model):
notify_pids.append(partner.id)
return notify_pids
def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None):
""" Format a standard footer for notification emails (such as pushed messages
notification or invite emails).
Format:
<p>--<br />
Administrator
</p>
<div>
<small>Send by <a ...>Your Company</a> using <a ...>OpenERP</a>.</small> OR
<small>Send by Administrator using <a ...>OpenERP</a>.</small>
</div>
"""
footer = ""
if not user_id:
return footer
# add user signature
user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0]
if user.signature:
signature = plaintext2html(user.signature)
else:
signature = "--<br />%s" % user.name
footer = tools.append_content_to_html(footer, signature, plaintext=False, container_tag='p')
# add company signature
if user.company_id:
company = user.company_id.website and "<a style='color:inherit' href='%s'>%s</a>" % (user.company_id.website, user.company_id.name) or user.company_id.name
else:
company = user.name
signature_company = _('<small>Send by %(company)s using %(openerp)s.</small>' % {
'company': company,
'openerp': "<a style='color:inherit' href='https://www.openerp.com/'>OpenERP</a>"
})
footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
return footer
def _notify(self, cr, uid, msg_id, partners_to_notify=None, context=None):
""" Send by email the notification depending on the user preferences
@ -141,14 +180,11 @@ class mail_notification(osv.Model):
# TDE FIXME: commented, to be improved in a future branch
# quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
mail_mail = self.pool.get('mail.mail')
# add signature
body_html = msg.body
# if quote_context:
# body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
if signature:
body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
user_id = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0] and msg.author_id.user_ids[0].id or None
signature_company = self.get_signature_footer(cr, uid, user_id, res_model=msg.model, res_id=msg.res_id, context=context)
body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div')
# email_from: partner-user alias or partner email or mail.message email_from
if msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].alias_domain and msg.author_id.user_ids[0].alias_name:
@ -164,6 +200,7 @@ class mail_notification(osv.Model):
'body_html': body_html,
'email_from': email_from,
}
mail_mail = self.pool.get('mail.mail')
email_notif_id = mail_mail.create(cr, uid, mail_values, context=context)
try:
return mail_mail.send(cr, uid, [email_notif_id], recipient_ids=notify_partner_ids, context=context)

View File

@ -160,15 +160,12 @@ class mail_mail(osv.Model):
return 'Re: %s' % (mail.record_name)
return mail.subject
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
""" Return a specific ir_email body. The main purpose of this method
is to be inherited by Portal, to add a link for signing in, in
def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
""" Return a specific footer for the ir_email body. The main purpose of this method
is to be inherited by Portal, to add modify the link for signing in, in
each notification email a partner receives.
:param browse_record mail: mail.mail browse_record
:param browse_record partner: specific recipient partner
"""
body = mail.body_html
body_footer = ""
# partner is a user, link to a related document (incentive to install portal)
if partner and partner.user_ids and mail.model and mail.res_id \
and self.check_access_rights(cr, partner.user_ids[0].id, 'read', raise_exception=False):
@ -184,10 +181,23 @@ class mail_mail(osv.Model):
'id': mail.res_id,
}
url = urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment)))
text = _("""<p>Access this document <a href="%s">directly in OpenERP</a></p>""") % url
body = tools.append_content_to_html(body, ("<div><p>%s</p></div>" % text), plaintext=False)
body_footer = _("""<small>Access this document <a style='color:inherit' href="%s">directly in OpenERP</a></small>""") % url
except except_orm, e:
pass
return body_footer
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
""" Return a specific ir_email body. The main purpose of this method
is to be inherited to add custom content depending on some module.
:param browse_record mail: mail.mail browse_record
:param browse_record partner: specific recipient partner
"""
body = mail.body_html
# add footer
body_footer = self.send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)
body = tools.append_content_to_html(body, body_footer, plaintext=False, container_tag='div')
return body
def send_get_mail_reply_to(self, cr, uid, mail, partner=None, context=None):

View File

@ -23,7 +23,7 @@
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<data>
<field name="email" position="before">
<field name="signature" position="before">
<field name="notification_email_send"/>
</field>
<field name="email" position="after">

View File

@ -561,6 +561,14 @@
text-align: center;
width:100%;
}
.openerp .oe_followers button.oe_invite{
margin: 5px 0;
padding: 2px 8px;
font-size: 12px;
text-shadow: none;
width: 100%;
}
.openerp .oe_followers button.oe_invite,
.openerp .oe_followers button.oe_follower.oe_following{
color: white;
background-color: #3465A4;
@ -614,9 +622,6 @@
margin-top: 12px;
margin-bottom: 4px;
}
.openerp .oe_followers .oe_invite{
float: right;
}
.openerp .oe_followers .oe_partner {
height: 32px;
overflow: hidden;

View File

@ -220,23 +220,16 @@ openerp_mail_followers = function(session, mail) {
/** Display subtypes: {'name': default, followed} */
display_subtypes:function (data, id) {
var self = this;
var subtype_list_ul = this.$('.oe_subtype_list');
var records = [];
var nb_subtype = 0;
subtype_list_ul.empty();
if (data[id]) {
records = data[id].message_subtype_data;
}
_(records).each(function (record) {nb_subtype++;});
if (nb_subtype > 1) {
this.$('hr').show();
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
$(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
});
} else {
this.$('hr').hide();
var $list = this.$('.oe_subtype_list');
$list.empty().hide();
var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
$(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
});
if (_.size(records) > 1) {
$list.show();
}
},

View File

@ -17,10 +17,9 @@
</t>
<div class="oe_subtype_list"></div>
</div>
<hr size="2"></hr>
<div class='oe_follower_title_box'>
<h4 class='oe_follower_title'>Followers</h4>
<a t-if="widget.view_is_editable" href='#' class="oe_invite">Add others</a>
<button t-if="widget.view_is_editable" href='#' class="oe_invite">Invite people</button>
</div>
<div class="oe_follower_list"></div>
</div>

View File

@ -31,18 +31,18 @@ class test_invite(TestMailBase):
# Do: create a mail_wizard_invite, validate it
self._init_mock_build_email()
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
mail_invite_id = mail_invite.create(cr, self.user_raoul_id, {'partner_ids': [(4, self.partner_bert_id)]}, context)
mail_invite_id = mail_invite.create(cr, self.user_raoul_id, {'partner_ids': [(4, self.partner_bert_id)], 'send_mail': True}, context)
mail_invite.add_followers(cr, self.user_raoul_id, [mail_invite_id], {'default_model': 'mail.group', 'default_res_id': 0})
# Test: Pigs followers should contain Admin, Bert
self.group_pigs.refresh()
follower_ids = [follower.id for follower in self.group_pigs.message_follower_ids]
self.assertEqual(set(follower_ids), set([self.partner_admin_id, self.partner_bert_id]), 'Pigs followers after invite is incorrect')
self.assertEqual(set(follower_ids), set([self.partner_admin_id, self.partner_bert_id]), 'invite: Pigs followers after invite is incorrect')
# Test: (pretend to) send email and check subject, body
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
for sent_email in self._build_email_kwargs_list:
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Pigs',
'subject of invitation email is incorrect')
self.assertTrue('You have been invited to follow Pigs' in sent_email.get('body'),
'body of invitation email is incorrect')
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
'invite: subject of invitation email is incorrect')
self.assertIn('Raoul Grosbedon invited you to follow Discussion group document: Pigs', sent_email.get('body'),
'invite: body of invitation email is incorrect')

View File

@ -84,23 +84,6 @@ Sylvie
class test_mail(TestMailBase):
def _mock_send_get_mail_body(self, *args, **kwargs):
# def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
body = append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner', plaintext=False)
return body
def setUp(self):
super(test_mail, self).setUp()
# Mock send_get_mail_body to test its functionality without other addons override
self._send_get_mail_body = self.registry('mail.mail').send_get_mail_body
self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body
def tearDown(self):
# Remove mocks
self.registry('mail.mail').send_get_mail_body = self._send_get_mail_body
super(test_mail, self).tearDown()
def test_00_message_process(self):
""" Testing incoming emails processing. """
cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
@ -341,11 +324,15 @@ class test_mail(TestMailBase):
_subject = 'Pigs'
_mail_subject = 'Re: %s' % (group_pigs.name)
_body1 = '<p>Pigs rules</p>'
_mail_body1 = '<p>Pigs rules</p>\n<div><p>Raoul</p></div>\n'
_mail_bodyalt1 = 'Pigs rules\nRaoul\n'
_mail_body1 = '<p>Pigs rules</p>'
_mail_signature1 = '<p>Raoul</p>'
_mail_bodyalt1 = 'Pigs rules\n'
_mail_signaturealt1 = '\nRaoul\n'
_body2 = '<html>Pigs rules</html>'
_mail_body2 = '<div><p>Pigs rules</p></div>\n<div><p>Raoul</p></div>'
_mail_bodyalt2 = 'Pigs rules\nRaoul'
_mail_body2 = '<div><p>Pigs rules</p></div>'
_mail_signature2 = '<p>Raoul</p>'
_mail_bodyalt2 = 'Pigs rules\n'
_mail_signaturealt2 = '\nRaoul\n'
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
# ----------------------------------------
@ -366,12 +353,14 @@ class test_mail(TestMailBase):
self.assertEqual(len(sent_emails), 2, 'sent_email number of sent emails incorrect')
for sent_email in sent_emails:
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
self.assertTrue(sent_email['body'] in [_mail_body1 + '\nBert Tartopoils\n', _mail_body1 + '\nAdministrator\n'],
'sent_email body incorrect')
self.assertIn(_mail_body1, sent_email['body'], 'sent_email body incorrect')
self.assertIn(_mail_signature1, sent_email['body'], 'sent_email body incorrect (no signature)')
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
# the html2plaintext uses etree or beautiful soup, so the result may be slighly different
# depending if you have installed beautiful soup.
self.assertTrue(sent_email['body_alternative'] in [_mail_bodyalt1 + '\nBert Tartopoils\n', _mail_bodyalt1 + '\nAdministrator\n'],
'sent_email body_alternative is incorrect')
self.assertIn(_mail_bodyalt1, sent_email['body_alternative'], 'sent_email body_alternative is incorrect')
self.assertIn(_mail_signaturealt1, sent_email['body_alternative'], 'sent_email body_alternative is incorrect (no signature)')
self.assertIn("OpenERP", sent_email['body_alternative'], 'sent_email body incorrect (no OpenERP company)')
# Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message1.notified_partner_ids])
test_pids = set([self.partner_admin_id, p_b_id, p_c_id])
@ -405,7 +394,12 @@ class test_mail(TestMailBase):
for sent_email in sent_emails:
self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect')
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
self.assertIn(_mail_signature2, sent_email['body'], 'sent_email body incorrect (no signature)')
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
# body_alternative
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative is incorrect')
self.assertIn(_mail_signaturealt2, sent_email['body_alternative'], 'sent_email body_alternative is incorrect (no signature)')
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
# Test: mail_message: notified_partner_ids = group followers
message_pids = set([partner.id for partner in message2.notified_partner_ids])
test_pids = set([self.partner_admin_id, p_b_id, p_c_id, p_d_id])

View File

@ -32,12 +32,19 @@ class invite_wizard(osv.osv_memory):
def default_get(self, cr, uid, fields, context=None):
result = super(invite_wizard, self).default_get(cr, uid, fields, context=context)
if 'message' in fields and result.get('res_model') and result.get('res_id'):
document_name = self.pool.get(result.get('res_model')).name_get(cr, uid, [result.get('res_id')], context=context)[0][1]
message = _('<div>You have been invited to follow %s.</div>' % document_name)
user_name = self.pool.get('res.users').name_get(cr, uid, [uid], context=context)[0][1]
model = result.get('res_model')
res_id = result.get('res_id')
if 'message' in fields and model and res_id:
ir_model = self.pool.get('ir.model')
model_ids = ir_model.search(cr, uid, [('model', '=', self.pool.get(model)._name)], context=context)
model_name = ir_model.name_get(cr, uid, model_ids, context=context)[0][1]
document_name = self.pool.get(model).name_get(cr, uid, [res_id], context=context)[0][1]
message = _('<div><p>Hello,</p><p>%s invited you to follow %s document: %s.<p></div>') % (user_name, model_name, document_name)
result['message'] = message
elif 'message' in fields:
result['message'] = _('<div>You have been invited to follow a new document.</div>')
result['message'] = _('<div><p>Hello,</p><p>%s invited you to follow a new document.</p></div>') % user_name
return result
_columns = {
@ -46,8 +53,12 @@ class invite_wizard(osv.osv_memory):
help='Model of the followed resource'),
'res_id': fields.integer('Related Document ID', select=1,
help='Id of the followed resource'),
'partner_ids': fields.many2many('res.partner', string='Partners'),
'partner_ids': fields.many2many('res.partner', string='Recipients',
help="List of partners that will be added as follower of the current document."),
'message': fields.html('Message'),
'send_mail': fields.boolean('Send Email',
help="If checked, the partners will receive an email warning they have been "
"added in the document's followers."),
}
def add_followers(self, cr, uid, ids, context=None):
@ -59,21 +70,25 @@ class invite_wizard(osv.osv_memory):
new_follower_ids = [p.id for p in wizard.partner_ids if p not in document.message_follower_ids]
model_obj.message_subscribe(cr, uid, [wizard.res_id], new_follower_ids, context=context)
# send an email
if wizard.message:
ir_model = self.pool.get('ir.model')
model_ids = ir_model.search(cr, uid, [('model', '=', model_obj._name)], context=context)
model_name = ir_model.name_get(cr, uid, model_ids, context=context)[0][1]
# send an email if option checked and if a message exists (do not send void emails)
if wizard.send_mail and wizard.message:
# add signature
user_id = self.pool.get("res.users").read(cr, uid, [uid], fields=["signature"], context=context)[0]
signature = user_id and user_id["signature"] or ''
if signature:
wizard.message = tools.append_content_to_html(wizard.message, signature, plaintext=True, container_tag='div')
# FIXME 8.0: use notification_email_send, send a wall message and let mail handle email notification + message box
signature_company = self.pool.get('mail.notification').get_signature_footer(cr, uid, user_id=uid, res_model=wizard.res_model, res_id=wizard.res_id, context=context)
wizard.message = tools.append_content_to_html(wizard.message, signature_company, plaintext=False, container_tag='div')
# send mail to new followers
for follower_id in new_follower_ids:
mail_mail = self.pool.get('mail.mail')
# the invite wizard should create a private message not related to any object -> no model, no res_id
mail_id = mail_mail.create(cr, uid, {
'model': wizard.res_model,
'res_id': wizard.res_id,
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
'subject': _('Invitation to follow %s: %s') % (model_name, document.name_get()[0][1]),
'body_html': '%s' % wizard.message,
'auto_delete': True,
}, context=context)

View File

@ -14,7 +14,8 @@
<field name="partner_ids" widget="many2many_tags_email"
placeholder="Add contacts to notify..."
context="{'force_email':True, 'show_email':True}"/>
<field name="message"/>
<field name="send_mail"/>
<field name="message" attrs="{'invisible': [('send_mail','!=',True)]}"/>
</group>
<footer>
<button string="Add Followers"

View File

@ -22,7 +22,6 @@
from openerp import SUPERUSER_ID
from openerp.osv import osv
from openerp.osv.orm import except_orm
from openerp.tools import append_content_to_html
from openerp.tools.translate import _
@ -30,18 +29,17 @@ class mail_mail(osv.Model):
""" Update of mail_mail class, to add the signin URL to notifications. """
_inherit = 'mail.mail'
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
""" add a signin link inside the body of a mail.mail
:param mail: mail.mail browse_record
:param partner: browse_record of the specific recipient partner
:return: the resulting body_html
"""
partner_obj = self.pool.get('res.partner')
body = mail.body_html
if partner:
contex_signup = dict(context or {}, signup_valid=True)
partner = partner_obj.browse(cr, SUPERUSER_ID, partner.id, context=contex_signup)
text = _("""<p>Access your messages and personal documents through <a href="%s">our Customer Portal</a></p>""") % partner.signup_url
body_footer = _("""<small>Access your messages and documents through <a style='color:inherit' href="%s">our Customer Portal</a></small>""") % partner.signup_url
# partner is an user: add a link to the document if read access
if partner.user_ids and mail.model and mail.res_id \
and self.check_access_rights(cr, partner.user_ids[0].id, 'read', raise_exception=False):
@ -49,8 +47,9 @@ class mail_mail(osv.Model):
try:
self.pool.get(mail.model).check_access_rule(cr, related_user.id, [mail.res_id], 'read', context=context)
url = partner_obj._get_signup_url_for_action(cr, related_user.id, [partner.id], action='', res_id=mail.res_id, model=mail.model, context=context)[partner.id]
text = _("""<p>Access this document <a href="%s">directly in OpenERP</a></p>""") % url
text = _("""<small>Access this document <a style='color:inherit' href="%s">directly in OpenERP</a></small>""") % url
except except_orm, e:
pass
body = append_content_to_html(body, ("<div><p>%s</p></div>" % text), plaintext=False)
return body
return body_footer
else:
return super(mail_mail, self).send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)

View File

@ -106,7 +106,7 @@ class test_portal(TestMailBase):
# Do: create a mail_wizard_invite, validate it
self._init_mock_build_email()
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)]}, context)
mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)], 'send_mail': True}, context)
mail_invite.add_followers(cr, uid, [mail_invite_id])
# Test: Pigs followers should contain Admin and Bert
@ -124,9 +124,9 @@ class test_portal(TestMailBase):
# Test: (pretend to) send email and check subject, body
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
for sent_email in self._build_email_kwargs_list:
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Pigs',
'subject of invitation email is incorrect')
self.assertTrue('You have been invited to follow Pigs' in sent_email.get('body'),
'body of invitation email is incorrect')
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
'invite: subject of invitation email is incorrect')
self.assertIn('Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'),
'invite: body of invitation email is incorrect')
self.assertTrue(partner_carine.signup_url in sent_email.get('body'),
'body of invitation email does not contain signup url')
'invite: body of invitation email does not contain signup url')

View File

@ -109,7 +109,8 @@
<group name="inventory">
<group name="status" string="Status">
<field name="state"/>
<field name="product_manager"/>
<field name="product_manager"
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_manager']}"/>
</group>
<group name="Weights" groups="product.group_stock_packaging" string="Weights">
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>

View File

@ -100,7 +100,9 @@
<group>
<group>
<field name="privacy_visibility"/>
<field name="user_id" string="Project Manager" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
<field name="user_id" string="Project Manager"
attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"
context="{'default_groups_ref': ['base.group_user', 'project.group_project_manager']}"/>
</group>
<group>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
@ -381,7 +383,10 @@
<group>
<group>
<field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
<field name="user_id" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}" options='{"no_open": True}'/>
<field name="user_id"
attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"
options='{"no_open": True}'
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
<field name="planned_hours" widget="float_time"
groups="project.group_time_work_estimation_tasks"
on_change="onchange_planned(planned_hours, effective_hours)"/>

View File

@ -69,7 +69,8 @@
<field name="categ_ids" widget="many2many_tags"/>
<group>
<group groups="base.group_user">
<field name="user_id"/>
<field name="user_id"
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id, email_from)"/>
<field name="email_from"/>
<label for="project_id" groups="base.group_user"/>