From 2e5412fc1d63516c8b4aefcb0bacd79d85b2d498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 7 Aug 2014 14:43:21 +0200 Subject: [PATCH] [FIX] mail, BaseModel, portal_sale: fixes and improvements in the URL management to access documents in notification emails, as well as for the 'view quotation' link in portal_sale module. models: added a get_access_action method: basically, returns the action to access a document. It uses the get_formview_action by default (form view of the document). However for some documents we want to directly go to the website, leading to an act_url action for some documents. This method allows this behavior. portal_sale: get_signup_url now uses the mail.action_mail_redirect method instead of directly redirecting towards a portal menu. This allows to fall back on a standard behavior. portal_sale: get_formview_action updated, to match actions tailored for portal users. website_quote: get_access_action of sale order updated. If the sale order has a template defined, the returned action is an act_url (website view of the quotation), not the form action anymore. mail: fixed signature + company signature in notification emails. Even without user signature, the company signature + access link should be correct. portal: signup url in notification emali was not using the mail redirection as action. It is now the case. --- addons/mail/mail_followers.py | 20 ++++++++------- addons/mail/mail_thread.py | 4 +-- addons/portal/mail_mail.py | 1 + addons/portal/tests/test_portal.py | 13 +++++----- addons/portal_sale/portal_sale.py | 33 +++++++++++++++++++------ addons/portal_sale/portal_sale_data.xml | 1 + addons/website_quote/models/order.py | 14 ++++++++++- openerp/models.py | 25 +++++++++++++------ 8 files changed, 76 insertions(+), 35 deletions(-) diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index aeb0a2b10ec..e8dd37e0ad9 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -120,7 +120,7 @@ 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): + def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None, user_signature=True): """ Format a standard footer for notification emails (such as pushed messages notification or invite emails). Format: @@ -137,11 +137,13 @@ class mail_notification(osv.Model): # add user signature user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0] - if user.signature: - signature = user.signature - else: - signature = "--
%s" % user.name - footer = tools.append_content_to_html(footer, signature, plaintext=False) + if user_signature: + if user.signature: + signature = user.signature + else: + signature = "--
%s" % user.name + footer = tools.append_content_to_html(footer, signature, plaintext=False) + # add company signature if user.company_id.website: website_url = ('http://%s' % user.company_id.website) if not user.company_id.website.lower().startswith(('http:', 'https:')) \ @@ -187,9 +189,9 @@ class mail_notification(osv.Model): # compute email body (signature, company data) body_html = message.body # add user signature except for mail groups, where users are usually adding their own signatures already - if user_signature and message.model != 'mail.group': - user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None - signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context) + user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None + signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context, user_signature=(user_signature and message.model != 'mail.group')) + if signature_company: body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') # compute email references diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 9125b775e49..0eb4d35c22d 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -627,7 +627,7 @@ class mail_thread(osv.AbstractModel): if params: msg_id = params.get('message_id') model = params.get('model') - res_id = params.get('res_id') + res_id = params.get('res_id', params.get('id')) # signup automatically generated id instead of res_id if not msg_id and not (model and res_id): return action if msg_id and not (model and res_id): @@ -641,7 +641,7 @@ class mail_thread(osv.AbstractModel): if model_obj.check_access_rights(cr, uid, 'read', raise_exception=False): try: model_obj.check_access_rule(cr, uid, [res_id], 'read', context=context) - action = model_obj.get_formview_action(cr, uid, res_id, context=context) + action = model_obj.get_access_action(cr, uid, res_id, context=context) except (osv.except_osv, orm.except_orm): pass action.update({ diff --git a/addons/portal/mail_mail.py b/addons/portal/mail_mail.py index 79e5be49612..44af0468657 100644 --- a/addons/portal/mail_mail.py +++ b/addons/portal/mail_mail.py @@ -39,6 +39,7 @@ class mail_mail(osv.Model): if partner and not partner.user_ids: contex_signup = dict(context, signup_valid=True) signup_url = partner_obj._get_signup_url_for_action(cr, SUPERUSER_ID, [partner.id], + action='mail.action_mail_redirect', model=mail.model, res_id=mail.res_id, context=contex_signup)[partner.id] return _(""", access %s %s through our Customer Portal""") % (context.get('model_name', ''), mail.record_name, signup_url) diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index 04122289316..6a8242bf0cf 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -131,12 +131,11 @@ class test_portal(TestMail): 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 Discussion group: Pigs', - 'invite: subject of invitation email is incorrect') + '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') - invite_url = partner_carine._get_signup_url_for_action(model='mail.group', res_id=self.group_pigs_id)[partner_carine.id] - self.assertTrue(invite_url in sent_email.get('body'), - 'invite: body of invitation email does not contain signup url') + 'invite: body of invitation email is incorrect') + self.assertIn(partner_carine.signup_token, sent_email.get('body'), + 'invite: body of invitation email does not contain signup token') def test_20_notification_url(self): """ Tests designed to test the URL added in notification emails. """ @@ -157,8 +156,8 @@ class test_portal(TestMail): # Test: link for partner -> signup URL url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_bert) - self.assertIn(partner_bert.signup_url, url, - 'notification email: mails send to a not-user partner should contain the signup URL') + self.assertIn(partner_bert.signup_token, url, + 'notification email: mails send to a not-user partner should contain the signup token') # Test: link for user -> signin url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_raoul) diff --git a/addons/portal_sale/portal_sale.py b/addons/portal_sale/portal_sale.py index f45acf45523..b0997f78a7c 100644 --- a/addons/portal_sale/portal_sale.py +++ b/addons/portal_sale/portal_sale.py @@ -19,6 +19,7 @@ # ############################################################################## +from openerp import SUPERUSER_ID from openerp.osv import osv, fields @@ -67,10 +68,19 @@ class sale_order(osv.Model): def get_signup_url(self, cr, uid, ids, context=None): assert len(ids) == 1 document = self.browse(cr, uid, ids[0], context=context) - partner = document.partner_id - action = 'portal_sale.action_quotations_portal' if document.state in ('draft', 'sent') else 'portal_sale.action_orders_portal' - partner.signup_prepare() - return partner._get_signup_url_for_action(action=action, view_type='form', res_id=document.id)[partner.id] + contex_signup = dict(context, signup_valid=True) + return self.pool['res.partner']._get_signup_url_for_action( + cr, uid, [document.partner_id.id], action='mail.action_mail_redirect', + model=self._name, res_id=document.id, context=contex_signup, + )[document.partner_id.id] + + def get_formview_action(self, cr, uid, id, context=None): + user = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context) + if user.share: + document = self.browse(cr, uid, id, context=context) + action_xmlid = 'action_quotations_portal' if document.state in ('draft', 'sent') else 'action_orders_portal' + return self.pool['ir.actions.act_window'].for_xml_id(cr, uid, 'portal_sale', action_xmlid, context=context) + return super(sale_order, self).get_formview_action(cr, uid, id, context=context) class account_invoice(osv.Model): @@ -117,10 +127,17 @@ class account_invoice(osv.Model): def get_signup_url(self, cr, uid, ids, context=None): assert len(ids) == 1 document = self.browse(cr, uid, ids[0], context=context) - partner = document.partner_id - action = 'portal_sale.portal_action_invoices' - partner.signup_prepare() - return partner._get_signup_url_for_action(action=action, view_type='form', res_id=document.id)[partner.id] + contex_signup = dict(context, signup_valid=True) + return self.pool['res.partner']._get_signup_url_for_action( + cr, uid, [document.partner_id.id], action='mail.action_mail_redirect', + model=self._name, res_id=document.id, context=contex_signup, + )[document.partner_id.id] + + def get_formview_action(self, cr, uid, id, context=None): + user = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context) + if user.share: + return self.pool['ir.actions.act_window'].for_xml_id(cr, uid, 'portal_sale', 'portal_action_invoices', context=context) + return super(sale_order, self).get_formview_action(cr, uid, id, context=context) class mail_mail(osv.osv): diff --git a/addons/portal_sale/portal_sale_data.xml b/addons/portal_sale/portal_sale_data.xml index 2da55bcb081..6f8f3b3fd13 100644 --- a/addons/portal_sale/portal_sale_data.xml +++ b/addons/portal_sale/portal_sale_data.xml @@ -14,6 +14,7 @@ ${(object.name or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''} ${object.partner_id.lang} + diff --git a/addons/website_quote/models/order.py b/addons/website_quote/models/order.py index 8430ef07791..bb3f89a5c8d 100644 --- a/addons/website_quote/models/order.py +++ b/addons/website_quote/models/order.py @@ -183,7 +183,19 @@ class sale_order(osv.osv): for line in order_line: products += line.product_id.product_tmpl_id.recommended_products(context=context) return products - + + def get_access_action(self, cr, uid, id, context=None): + """ Override method that generated the link to access the document. Instead + of the classic form view, redirect to the online quote if exists. """ + quote = self.browse(cr, uid, id, context=context) + if not quote.template_id: + return super(sale_order, self).get_access_action(cr, uid, id, context=context) + return { + 'type': 'ir.actions.act_url', + 'url': '/quote/%s' % id, + 'target': 'self', + 'res_id': id, + } class sale_quote_option(osv.osv): diff --git a/openerp/models.py b/openerp/models.py index 8beb60d53b7..abe36b38b05 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -1593,14 +1593,23 @@ class BaseModel(object): """ view_id = self.get_formview_id(cr, uid, id, context=context) return { - 'type': 'ir.actions.act_window', - 'res_model': self._name, - 'view_type': 'form', - 'view_mode': 'form', - 'views': [(view_id, 'form')], - 'target': 'current', - 'res_id': id, - } + 'type': 'ir.actions.act_window', + 'res_model': self._name, + 'view_type': 'form', + 'view_mode': 'form', + 'views': [(view_id, 'form')], + 'target': 'current', + 'res_id': id, + } + + def get_access_action(self, cr, uid, id, context=None): + """ Return an action to open the document. This method is meant to be + overridden in addons that want to give specific access to the document. + By default it opens the formview of the document. + + :paramt int id: id of the document to open + """ + return self.get_formview_action(cr, uid, id, context=context) def _view_look_dom_arch(self, cr, uid, node, view_id, context=None): return self.pool['ir.ui.view'].postprocess_and_fields(