[IMP] sale: support quote confirmation and sign in customer portal
Purpose is to allow customers to accept and confirm orders on the customer portal without having to rely on advanced website_quote (online quotation) features. Including : * add quote confirmation route; * add support in customer portal using the newly-introduced signature widget; * add action button on the order page view;
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
|
||||
from odoo import http, _
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.http import request
|
||||
from odoo.tools import consteq
|
||||
|
||||
from odoo.addons.portal.controllers.mail import _message_post_helper
|
||||
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager, get_records_pager
|
||||
|
||||
|
||||
@@ -54,6 +56,8 @@ class CustomerPortal(CustomerPortal):
|
||||
}
|
||||
if access_token:
|
||||
values['no_breadcrumbs'] = True
|
||||
values['access_token'] = access_token
|
||||
values['portal_confirmation'] = request.env['ir.config_parameter'].sudo().get_param('sale.sale_portal_confirmation_options', default='none')
|
||||
|
||||
if kwargs.get('error'):
|
||||
values['error'] = kwargs['error']
|
||||
@@ -64,6 +68,7 @@ class CustomerPortal(CustomerPortal):
|
||||
|
||||
history = request.session.get('my_orders_history', [])
|
||||
values.update(get_records_pager(history, order))
|
||||
|
||||
return values
|
||||
|
||||
@http.route(['/my/quotes', '/my/quotes/page/<int:page>'], type='http', auth="user", website=True)
|
||||
@@ -192,3 +197,32 @@ class CustomerPortal(CustomerPortal):
|
||||
('Content-Length', len(pdf)),
|
||||
]
|
||||
return request.make_response(pdf, headers=pdfhttpheaders)
|
||||
|
||||
@http.route(['/my/quotes/accept'], type='json', auth="public", website=True)
|
||||
def portal_quote_accept(self, res_id, access_token=None, partner_name=None, signature=None):
|
||||
if request.env['ir.config_parameter'].sudo().get_param(
|
||||
'sale.sale_portal_confirmation_options', default='none') not in ('pay', 'sign'):
|
||||
return False
|
||||
try:
|
||||
order_sudo = self._order_check_access(res_id, access_token=access_token)
|
||||
except AccessError:
|
||||
return {
|
||||
'error': _('Invalid order')
|
||||
}
|
||||
|
||||
if order_sudo.state != 'sent':
|
||||
return {
|
||||
'error': _('Order is not in a state requiring customer validation.')
|
||||
}
|
||||
order_sudo.action_confirm()
|
||||
|
||||
_message_post_helper(
|
||||
res_model='sale.order',
|
||||
res_id=order_sudo.id,
|
||||
message=_('Order signed by %s') % (partner_name,),
|
||||
attachments=[('signature.png', base64.b64decode(signature))] if signature else [],
|
||||
**({'token': access_token, 'token_field': 'access_token'} if access_token else {}))
|
||||
return {
|
||||
'success': _('Your Order has been confirmed.'),
|
||||
'redirect_url': '/my/orders/%s?%s' % (order_sudo.id, access_token and 'access_token=%s' % order_sudo.access_token or ''),
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
</template>
|
||||
|
||||
<template id="assets_frontend" inherit_id="web.assets_frontend" name="Sale frontend assets">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel='stylesheet' href='/sale/static/src/less/sale_portal.less'/>
|
||||
</xpath>
|
||||
<xpath expr="." position="inside">
|
||||
<link rel='stylesheet' href='/sale/static/src/less/sale_portal.less'/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -131,6 +131,8 @@
|
||||
<template id="portal_order_page" name="Sales Order">
|
||||
<t t-call="portal.portal_layout">
|
||||
<t t-set="sales_order" t-value="order"/> <!-- rename to ensure breadcrumb compatibility (differentiate with purchase orders) -->
|
||||
<t t-set="invoices" t-value="[i for i in order.invoice_ids if i.state not in ['draft', 'cancel']]"/>
|
||||
<t t-set="invoices_amount" t-value="sum(i.amount_total for i in invoices)"/>
|
||||
<div id="optional_placeholder"></div>
|
||||
<div class="container">
|
||||
<div class="panel panel-default">
|
||||
@@ -145,7 +147,17 @@
|
||||
</h4>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-6 col-xs-12 hidden-print" id="o_portal_order_actions">
|
||||
<a target="_blank" t-att-href="'/my/orders/pdf/%s?%s' % (order.id, keep_query())" class="pull-right" title="Download">
|
||||
<t t-if="order.state == 'sent' and portal_confirmation == 'sign'" name="portal_confirmation_sign">
|
||||
<a class="btn btn-primary ml8 pull-right" href="#portal_sign">
|
||||
<i class="fa fa-arrow-circle-right"/> Accept & Sign
|
||||
</a>
|
||||
</t>
|
||||
<t t-if="order.state == 'sale' and portal_confirmation == 'sign'">
|
||||
<a class="btn btn-success ml8 pull-right" disabled="disabled">
|
||||
<i class="fa fa-check-circle"/> Signed
|
||||
</a>
|
||||
</t>
|
||||
<a target="_blank" t-att-href="'/my/orders/pdf/%s?%s' % (order.id, keep_query())" class="ml8 pull-right" title="Download">
|
||||
<i class="fa fa-download fa-2x" aria-hidden="true"/>
|
||||
</a>
|
||||
</div>
|
||||
@@ -165,7 +177,6 @@
|
||||
<div>
|
||||
<address t-field="order.partner_invoice_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
|
||||
</div>
|
||||
<t t-set="invoices" t-value="[i for i in order.invoice_ids if i.state not in ['draft', 'cancel']]"/>
|
||||
<t t-if="invoices">
|
||||
<div>
|
||||
<strong>Invoices</strong>
|
||||
@@ -277,6 +288,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row" t-if="order.state == 'sent' and portal_confirmation == 'sign'" id="portal_sign">
|
||||
<div class="col-md-offset-3 col-md-6">
|
||||
<h4>Accept order</h4>
|
||||
<t t-call="portal.portal_signature">
|
||||
<t t-set="object" t-value="order"/>
|
||||
<t t-set="partner_name" t-value="order.partner_id.name"/>
|
||||
<t t-set="callUrl" t-value="'/my/quotes/accept'"/>
|
||||
<t t-set="accessToken" t-value="order.access_token"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_structure mb32"/>
|
||||
|
||||
Reference in New Issue
Block a user