From ef75f0245f002cada1028cb6e1e7953858a019ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Maes?= Date: Thu, 8 Dec 2016 13:35:14 +0100 Subject: [PATCH] [IMP] website_portal_sale, website_quote: portal access right Portal has access (read only) to partner, pricelist, taxes, ... These access were given to display informations on portal pages. Since, these are not very secure, we remove the access right. Some modifications are required to make the portal work again : - 'sudo' business document before rendering templates. ir.rule are still apply to filter the documents do display. For instance, SO total amount is computed using account.tax. - a related field has been added on SO line to allow portal user to see the image of the ordered product (on SO frontend view) - a new controller is created to display invoice PDF (as 'sudo'), since the rendering of this document required read access to taxes, payment terms, ... --- .../website_portal_sale/controllers/main.py | 21 +++++++++-- .../security/ir.model.access.csv | 11 ------ .../security/sale_order_security.xml | 8 ----- .../views/website_portal_sale_templates.xml | 4 +-- addons/website_quote/controllers/main.py | 36 ++++++++++--------- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py index 53b40c2b450..9b42a203bd7 100644 --- a/addons/website_portal_sale/controllers/main.py +++ b/addons/website_portal_sale/controllers/main.py @@ -82,7 +82,7 @@ class website_account(website_account): values.update({ 'date': date_begin, - 'quotations': quotations, + 'quotations': quotations.sudo(), 'page_name': 'quote', 'pager': pager, 'archive_groups': archive_groups, @@ -132,7 +132,7 @@ class website_account(website_account): values.update({ 'date': date_begin, - 'orders': orders, + 'orders': orders.sudo(), 'page_name': 'order', 'pager': pager, 'archive_groups': archive_groups, @@ -215,6 +215,23 @@ class website_account(website_account): }) return request.render("website_portal_sale.portal_my_invoices", values) + @http.route(['/my/invoices/'], type='http', auth="user", website=True) + def portal_my_invoices_report(self, invoice_id, **kw): + invoice = request.env['account.invoice'].browse(invoice_id) + try: + invoice.check_access_rights('read') + invoice.check_access_rule('read') + except AccessError: + return request.render("website.403") + # print report as sudo, since it require access to taxes, payment term, ... and portal + # does not have those access rights. + pdf = request.env['report'].sudo().get_pdf([invoice_id], 'account.report_invoice') + pdfhttpheaders = [ + ('Content-Type', 'application/pdf'), + ('Content-Length', len(pdf)), + ] + return request.make_response(pdf, headers=pdfhttpheaders) + def details_form_validate(self, data): error, error_message = super(website_account, self).details_form_validate(data) # prevent VAT/name change if invoices exist diff --git a/addons/website_portal_sale/security/ir.model.access.csv b/addons/website_portal_sale/security/ir.model.access.csv index 4ca1fb4c2b9..2033898fc32 100644 --- a/addons/website_portal_sale/security/ir.model.access.csv +++ b/addons/website_portal_sale/security/ir.model.access.csv @@ -2,15 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_sale_order,sale.order,sale.model_sale_order,base.group_portal,1,0,0,0 access_sale_order_line,sale.order.line,sale.model_sale_order_line,base.group_portal,1,0,0,0 access_account_invoice,account.invoice,account.model_account_invoice,base.group_portal,1,0,0,0 -access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,base.group_portal,1,0,0,0 access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,base.group_portal,1,0,0,0 -access_account_journal,account.journal,account.model_account_journal,base.group_portal,1,0,0,0 -access_product_list,product.pricelist,product.model_product_pricelist,base.group_portal,1,0,0,0 -access_res_partner,res.partner,base.model_res_partner,base.group_portal,1,0,0,0 -access_account_tax,account.tax,account.model_account_tax,base.group_portal,1,0,0,0 -access_account_tax_group,account.tax.group,account.model_account_tax_group,base.group_portal,1,0,0,0 -access_res_partner_category,res.partner.category,base.model_res_partner_category,base.group_portal,1,0,0,0 -access_product_attribute_portal,product.attribute portal,product.model_product_attribute,base.group_portal,1,0,0,0 -access_product_attribute_value_portal,product.attribute value portal,product.model_product_attribute_value,base.group_portal,1,0,0,0 -access_product_attribute_price_portal,product.attribute price portal,product.model_product_attribute_price,base.group_portal,1,0,0,0 -access_product_attribute_line_portal,product.attribute line portal,product.model_product_attribute_line,base.group_portal,1,0,0,0 diff --git a/addons/website_portal_sale/security/sale_order_security.xml b/addons/website_portal_sale/security/sale_order_security.xml index dd662d4309e..aa97cba3ea0 100644 --- a/addons/website_portal_sale/security/sale_order_security.xml +++ b/addons/website_portal_sale/security/sale_order_security.xml @@ -36,13 +36,5 @@ - - Portal Personal Contacts - - [('message_partner_ids','in',[user.commercial_partner_id.id])] - - - - diff --git a/addons/website_portal_sale/views/website_portal_sale_templates.xml b/addons/website_portal_sale/views/website_portal_sale_templates.xml index d2c493bdecf..5e3eec666da 100644 --- a/addons/website_portal_sale/views/website_portal_sale_templates.xml +++ b/addons/website_portal_sale/views/website_portal_sale_templates.xml @@ -185,7 +185,7 @@ - + @@ -286,7 +286,7 @@
- +
diff --git a/addons/website_quote/controllers/main.py b/addons/website_quote/controllers/main.py index ae1adab0d4f..328f4ee0f55 100644 --- a/addons/website_quote/controllers/main.py +++ b/addons/website_quote/controllers/main.py @@ -31,35 +31,39 @@ class sale_quote(http.Controller): if not Order: return request.render('website.404') + # Token or not, sudo the order, since portal user has not access on + # taxes, required to compute the total_amout of SO. + order_sudo = Order.sudo() + days = 0 - if Order.validity_date: - days = (fields.Date.from_string(Order.validity_date) - fields.Date.from_string(fields.Date.today())).days + 1 + if order_sudo.validity_date: + days = (fields.Date.from_string(order_sudo.validity_date) - fields.Date.from_string(fields.Date.today())).days + 1 if pdf: - pdf = request.env['report'].sudo().with_context(set_viewport_size=True).get_pdf([Order.id], 'website_quote.report_quote') + pdf = request.env['report'].sudo().with_context(set_viewport_size=True).get_pdf([order_sudo.id], 'website_quote.report_quote') pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) - transaction_id = request.session.get('quote_%s_transaction_id' % Order.id) + transaction_id = request.session.get('quote_%s_transaction_id' % order_sudo.id) if not transaction_id: - Transaction = request.env['payment.transaction'].sudo().search([('reference', '=', Order.name)]) + Transaction = request.env['payment.transaction'].sudo().search([('reference', '=', order_sudo.name)]) else: Transaction = request.env['payment.transaction'].sudo().browse(transaction_id) values = { - 'quotation': Order, + 'quotation': order_sudo, 'message': message and int(message) or False, - 'option': bool(filter(lambda x: not x.line_id, Order.options)), - 'order_valid': (not Order.validity_date) or (now <= Order.validity_date), + 'option': bool(filter(lambda x: not x.line_id, order_sudo.options)), + 'order_valid': (not order_sudo.validity_date) or (now <= order_sudo.validity_date), 'days_valid': days, 'action': request.env.ref('sale.action_quotations').id, - 'breadcrumb': request.env.user.partner_id == Order.partner_id, + 'breadcrumb': request.env.user.partner_id == order_sudo.partner_id, 'tx_id': Transaction.id if Transaction else False, 'tx_state': Transaction.state if Transaction else False, 'tx_post_msg': Transaction.acquirer_id.post_msg if Transaction else False, - 'need_payment': Order.invoice_status == 'to invoice' and Transaction.state in ['draft', 'cancel', 'error'], + 'need_payment': order_sudo.invoice_status == 'to invoice' and Transaction.state in ['draft', 'cancel', 'error'], 'token': token, } - if Order.require_payment or values['need_payment']: - values['acquirers'] = list(request.env['payment.acquirer'].sudo().search([('website_published', '=', True), ('company_id', '=', Order.company_id.id)])) + if order_sudo.require_payment or values['need_payment']: + values['acquirers'] = list(request.env['payment.acquirer'].sudo().search([('website_published', '=', True), ('company_id', '=', order_sudo.company_id.id)])) extra_context = { 'submit_class': 'btn btn-primary', 'submit_txt': _('Pay & Confirm') @@ -68,16 +72,16 @@ class sale_quote(http.Controller): for acquirer in values['acquirers']: values['buttons'][acquirer.id] = acquirer.with_context(**extra_context).render( '/', - Order.amount_total, - Order.pricelist_id.currency_id.id, + order_sudo.amount_total, + order_sudo.pricelist_id.currency_id.id, values={ 'return_url': '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id, 'type': 'form', 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'), - 'partner_id': Order.partner_id.id, + 'partner_id': order_sudo.partner_id.id, }) history = request.session.get('my_quotes_history', []) - values.update(get_records_pager(history, Order)) + values.update(get_records_pager(history, order_sudo)) return request.render('website_quote.so_quotation', values) @http.route(['/quote/accept'], type='json', auth="public", website=True)