[IMP] website_quote: use generic portal signature widget

Online quote can now use the generic signature widget already used on
the standard sale customer portal. We therefore remove the custom
widget build in website_quote.

A route already exists to sign quotes; the old route is removed. The
existing route is overridden so that quotations with template requiring
payment cannot be signed. This is the expected behavior.
This commit is contained in:
Thibault Delavallée
2017-09-06 10:40:32 +02:00
parent 22734f47d8
commit faea658382
3 changed files with 26 additions and 117 deletions
+13 -14
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import werkzeug
@@ -23,6 +22,19 @@ class CustomerPortal(CustomerPortal):
return request.redirect('/quote/%s/%s' % (order, access_token or ''))
return super(CustomerPortal, self).portal_order_page(order=order, access_token=access_token, **kw)
@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):
try:
order_sudo = self._order_check_access(res_id, access_token=access_token)
except exceptions.AccessError:
pass
else:
if order_sudo.require_payment:
return {
'error': _('Order is not in a state requiring customer validation.')
}
return super(CustomerPortal, self).portal_quote_accept(res_id, access_token=access_token, partner_name=partner_name, signature=signature)
class sale_quote(http.Controller):
@@ -102,19 +114,6 @@ class sale_quote(http.Controller):
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)
def accept(self, order_id, token=None, signer=None, sign=None, **post):
Order = request.env['sale.order'].sudo().browse(order_id)
if token != Order.access_token or Order.require_payment:
return request.render('website.404')
if Order.state != 'sent':
return False
attachments = [('signature.png', base64.b64decode(sign))] if sign else []
Order.action_confirm()
message = _('Order signed by %s') % (signer,)
_message_post_helper(message=message, res_id=order_id, res_model='sale.order', attachments=attachments, **({'token': token, 'token_field': 'access_token'} if token else {}))
return True
@http.route(['/quote/<int:order_id>/<token>/decline'], type='http', auth="public", methods=['POST'], website=True)
def decline(self, order_id, token, **post):
Order = request.env['sale.order'].sudo().browse(order_id)
@@ -46,77 +46,6 @@ if(!$('.o_website_quote').length) {
update_button_list.push(button);
});
// Accept Modal, with jSignature
var AcceptModal = Widget.extend({
events: {
'shown.bs.modal': 'initSignature',
'click #sign_clean': 'clearSignature',
'submit #accept': 'submitForm',
},
initSignature: function(ev){
this.$("#signature").empty().jSignature({'decor-color' : '#D1D0CE', 'color': '#000', 'background-color': '#fff'});
this.empty_sign = this.$("#signature").jSignature("getData",'image');
},
clearSignature: function(ev){
this.$("#signature").jSignature('reset');
},
submitForm: function(ev){
// extract data
var self = this;
var $confirm_btn = self.$el.find('button[type="submit"]');
// Support 2 routes:
// - <form id="accept" method="POST" t-attf-action="/quote/accept/#{quotation.id}/?token=#{quotation.access_token}" ...>
// - <form id="accept" method="POST" t-att-data-order-id="quotation.id" t-att-data-token="quotation.access_token" ...>
// The first route is deprecated but might still be used if the template is not updated
var href = self.$el.find('form').attr("action");
var action, order_id, token;
if (href) {
action = href.match(/quote\/([a-z]+)/)[1];
order_id = parseInt(href.match(/quote\/[a-z]+\/([0-9]+)/)[1]);
token = href.match(/token=(.*)/) && href.match(/token=(.*)/)[1];
}
else {
action = 'accept';
order_id = self.$el.find('form').data("order-id");
token = self.$el.find('form').data("token");
}
if (action === 'accept') {
ev.preventDefault();
// process : display errors, or submit
var signer_name = self.$("#name").val();
var signature = self.$("#signature").jSignature("getData",'image');
var is_empty = signature ? this.empty_sign[1] === signature[1] : false;
self.$('#signer').toggleClass('has-error', !signer_name);
self.$('#drawsign').toggleClass('panel-danger', is_empty).toggleClass('panel-default', !is_empty);
if (is_empty || ! signer_name){
setTimeout(function () {
self.$('button[type="submit"], a.a-submit').removeAttr('data-loading-text').button('reset');
});
return false;
}
$confirm_btn.prepend('<i class="fa fa-spinner fa-spin"></i> ');
$confirm_btn.attr('disabled', true);
ajax.jsonRpc("/quote/"+action, 'call', {
'order_id': order_id,
'token': token,
'signer': signer_name,
'sign': signature?JSON.stringify(signature[1]):false,
}).then(function (data) {
var message_id = (data) ? 3 : 4;
self.$el.modal('hide');
window.location.href = '/quote/'+order_id.toString()+'/'+token+'?message='+message_id;
});
return false;
}
},
});
var accept_modal = new AcceptModal();
accept_modal.setElement($('#modalaccept'));
accept_modal.start();
// Nav Menu ScrollSpy
var NavigationSpyMenu = Widget.extend({
start: function(watched_selector){
@@ -292,23 +292,19 @@
<h4 class="modal-title">Validate Order</h4>
</div>
<div class="modal-body" id="sign-dialog">
<p>
<span>I agree that by signing this proposal, I
accept it on the behalf of </span><b t-field="quotation.partner_id.commercial_partner_id"/><span>, for an amount of </span>
<b data-id="total_amount" t-field="quotation.amount_total"
t-options='{"widget": "monetary", "display_currency": quotation.pricelist_id.currency_id}'/>
<span>with payment terms: </span><b t-field="quotation.payment_term_id"/>.
</p>
<div id="signer" class="form-group">
<label class="control-label" for="name">Your Name:</label>
<input type="text" name="signer" id="name" class="form-control"/>
</div>
</div>
<div class="modal-footer">
<div t-if="not (pms or s2s_acquirers or form_acquirers)">
<button type="submit" t-attf-class="btn btn-primary">Sign &amp; Confirm</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
<p>
<span>I agree that by signing this proposal, I
accept it on the behalf of </span><b t-field="quotation.partner_id.commercial_partner_id"/><span>, for an amount of </span>
<b data-id="total_amount" t-field="quotation.amount_total"
t-options='{"widget": "monetary", "display_currency": quotation.pricelist_id.currency_id}'/>
<span>with payment terms: </span><b t-field="quotation.payment_term_id"/>.
</p>
<t t-call="portal.portal_signature">
<t t-set="object" t-value="quotation"/>
<t t-set="partner_name" t-value="quotation.partner_id.name"/>
<t t-set="callUrl" t-value="'/my/quotes/accept'"/>
<t t-set="accessToken" t-value="quotation.access_token"/>
</t>
</div>
</form>
</div>
@@ -534,21 +530,6 @@
</div>
</template>
<!-- Options:Quotation Signature -->
<template id="opt_quotation_signature" name="Ask Signature" customize_show="True" inherit_id="website_quote.so_quotation">
<xpath expr="//div[@id='sign-dialog']" position="inside">
<div class="panel panel-default mt16 mb0" id="drawsign">
<div class="panel-heading">
<div class="pull-right">
<a id="sign_clean" class="btn btn-xs">Clear</a>
</div>
<strong>Draw your signature</strong>
</div>
<div id="signature" class="panel-body" style="padding: 0"/>
</div>
</xpath>
</template>
<template id="optional_products">
<t t-if="any([(not option.line_id) for option in quotation.options])">
<section>