[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, ...
This commit is contained in:
Jérome Maes
2017-03-23 14:51:00 +01:00
parent ea6d6accc3
commit ef75f0245f
5 changed files with 41 additions and 39 deletions
+19 -2
View File
@@ -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/<int:invoice_id>'], 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
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_order sale.order sale.model_sale_order base.group_portal 1 0 0 0
3 access_sale_order_line sale.order.line sale.model_sale_order_line base.group_portal 1 0 0 0
4 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
5 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
@@ -36,13 +36,5 @@
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record id="portal_personal_contact" model="ir.rule">
<field name="name">Portal Personal Contacts</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="domain_force">[('message_partner_ids','in',[user.commercial_partner_id.id])]</field>
<field eval="0" name="perm_read"/>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
</data>
</odoo>
@@ -185,7 +185,7 @@
<t t-foreach="invoices" t-as="invoice">
<tr>
<td class= "cell_overflow">
<a t-att-href="'/report/pdf/account.report_invoice/'+str(invoice.id)" t-att-title="invoice.number"><t t-esc="invoice.number"/></a>
<a t-att-href="'/my/invoices/'+str(invoice.id)" t-att-title="invoice.number"><t t-esc="invoice.number"/></a>
</td>
<td><span t-field="invoice.date_invoice"/></td>
<td class='hidden-xs'><span t-field="invoice.date_due"/></td>
@@ -286,7 +286,7 @@
</div>
<div>
<t t-foreach="invoices" t-as="i">
<t t-set="report_url" t-value="'/report/pdf/account.report_invoice/%s' % i.id"/>
<t t-set="report_url" t-value="'/my/invoices/%s' % i.id"/>
<div>
<a t-att-href="report_url"><span class="fa fa-download"/></a>
<a t-att-href="report_url"><span t-esc="i.number"/></a>
+20 -16
View File
@@ -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)