diff --git a/addons/sale/controllers/portal.py b/addons/sale/controllers/portal.py index c33e7b79860..a72c647844b 100644 --- a/addons/sale/controllers/portal.py +++ b/addons/sale/controllers/portal.py @@ -200,16 +200,11 @@ class CustomerPortal(CustomerPortal): ] return request.make_response(pdf, headers=pdfhttpheaders) - def _portal_quote_user_can_accept(self, order_id): - return request.env['ir.config_parameter'].sudo().get_param('sale.sale_portal_confirmation_options', default='none') in ('pay', 'sign') + def _portal_quote_user_can_accept(self, order): + return order.company_id.portal_confirmation_sign or order.company_id.portal_confirmation_pay @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 not self._portal_quote_user_can_accept(res_id): - return {'error': _('Operation not allowed')} - if not signature: - return {'error': _('Signature is missing.')} - try: order_sudo = self._order_check_access(res_id, access_token=access_token) except AccessError: @@ -217,15 +212,29 @@ class CustomerPortal(CustomerPortal): if order_sudo.state != 'sent': return {'error': _('Order is not in a state requiring customer validation.')} - order_sudo.action_confirm() + if not self._portal_quote_user_can_accept(order_sudo): + return {'error': _('Operation not allowed')} + if not signature: + return {'error': _('Signature is missing.')} + success_message = _('Your order has been signed but still needs to be paid to be confirmed.') + + if not order_sudo.has_to_be_paid(): + order_sudo.action_confirm() + success_message = _('Your order has been confirmed.') + + order_sudo.signature = signature + order_sudo.signed_by = partner_name + + pdf = request.env.ref('sale.action_report_saleorder').sudo().render_qweb_pdf([order_sudo.id])[0] _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 [], + attachments=[('%s.pdf' % order_sudo.name, pdf)], **({'token': access_token} if access_token else {})) + return { - 'success': _('Your Order has been confirmed.'), + 'success': success_message, 'redirect_url': '/my/orders/%s?%s' % (order_sudo.id, access_token and 'access_token=%s' % order_sudo.access_token or ''), } diff --git a/addons/sale/data/mail_data.xml b/addons/sale/data/mail_data.xml index ce8dcc651a1..cc3a3291a2d 100644 --- a/addons/sale/data/mail_data.xml +++ b/addons/sale/data/mail_data.xml @@ -69,8 +69,16 @@ % set is_online = access_action and access_action['type'] == 'ir.actions.act_url' % set doc_name = 'quotation' if object.state in ('draft', 'sent') else 'order confirmation' % set pay_sign_name = object.get_portal_confirmation_action() -% set access_name = is_online and object.state in ('draft', 'sent') and pay_sign_name in ('pay', 'sign') and 'Accept and %s online' % pay_sign_name or 'View %s' % doc_name % set access_url = is_online and object.get_mail_url() or '' +% set access_name = 'View %s' % doc_name + +% if is_online and object.state in ('draft', 'sent') and pay_sign_name in ('pay', 'sign'): + % if pay_sign_name == 'sign' and object.has_to_be_paid(): + % set access_name = 'Sign and pay online' + % else: + % set access_name = 'Accept and %s online' % pay_sign_name + % endif +% endif % if object.partner_id.parent_id: (${object.partner_id.parent_id.name}) diff --git a/addons/sale/models/res_company.py b/addons/sale/models/res_company.py index 54a389d315e..d868ca91638 100644 --- a/addons/sale/models/res_company.py +++ b/addons/sale/models/res_company.py @@ -8,3 +8,5 @@ class ResCompany(models.Model): _inherit = "res.company" sale_note = fields.Text(string='Default Terms and Conditions', translate=True) + portal_confirmation_sign = fields.Boolean(string='Digital Signature', default=True) + portal_confirmation_pay = fields.Boolean(string='Electronic Payment') diff --git a/addons/sale/models/res_config_settings.py b/addons/sale/models/res_config_settings.py index d8fe8daeba5..c42b10d9b52 100644 --- a/addons/sale/models/res_config_settings.py +++ b/addons/sale/models/res_config_settings.py @@ -18,12 +18,9 @@ class ResConfigSettings(models.TransientModel): module_sale_margin = fields.Boolean("Margins") group_sale_layout = fields.Boolean("Sections on Sales Orders", implied_group='sale.group_sale_layout') group_warning_sale = fields.Boolean("Sale Order Warnings", implied_group='sale.group_warning_sale') - portal_confirmation = fields.Boolean('Online Signature & Payment') - portal_confirmation_options = fields.Selection([ - ('sign', 'Signature'), - ('pay', 'Payment')], string="Online Signature & Payment options", - config_parameter='sale.sale_portal_confirmation_options') - module_sale_payment = fields.Boolean("Sale Payment", help='Technical field implied by user choice of online_confirmation') + portal_confirmation_sign = fields.Boolean(related='company_id.portal_confirmation_sign', string='Digital Signature') + portal_confirmation_pay = fields.Boolean(related='company_id.portal_confirmation_pay', string='Electronic Payment') + module_sale_payment = fields.Boolean("Sale Payment", help='Technical field implied by user choice of portal_confirmation_pay.') module_website_quote = fields.Boolean("Quotations Templates") group_sale_delivery_address = fields.Boolean("Customer Addresses", implied_group='sale.group_delivery_invoice_address') multi_sales_price = fields.Boolean("Multiple Sales Prices per Product") @@ -131,16 +128,9 @@ class ResConfigSettings(models.TransientModel): 'group_pricelist_item': False, }) - @api.onchange('portal_confirmation') - def _onchange_portal_confirmation(self): - if not self.portal_confirmation: - self.portal_confirmation_options = False - elif not self.portal_confirmation_options: - self.portal_confirmation_options = 'sign' - - @api.onchange('portal_confirmation_options') - def _onchange_portal_confirmation_options(self): - if self.portal_confirmation_options == 'pay': + @api.onchange('portal_confirmation_pay') + def _onchange_portal_confirmation_pay(self): + if self.portal_confirmation_pay: self.module_sale_payment = True @api.model @@ -152,6 +142,5 @@ class ResConfigSettings(models.TransientModel): multi_sales_price=sale_pricelist_setting in ['percentage', 'formula'], multi_sales_price_method=sale_pricelist_setting in ['percentage', 'formula'] and sale_pricelist_setting or False, sale_pricelist_setting=sale_pricelist_setting, - portal_confirmation=ICPSudo.get_param('sale.sale_portal_confirmation_options', default=False) in ('pay', 'sign'), ) return res diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 1f0eeb79071..676f10c30be 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -163,6 +163,9 @@ class SaleOrder(models.Model): company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env['res.company']._company_default_get('sale.order')) team_id = fields.Many2one('crm.team', 'Sales Channel', change_default=True, default=_get_default_team, oldname='section_id') + signature = fields.Binary('Signature', help='Signature received through the portal.', copy=False, attachment=True) + signed_by = fields.Char('Signed by', help='Name of the person that signed the SO.', copy=False) + product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') def _compute_portal_url(self): @@ -488,6 +491,8 @@ class SaleOrder(models.Model): orders = self.filtered(lambda s: s.state in ['cancel', 'sent']) return orders.write({ 'state': 'draft', + 'signature': False, + 'signed_by': False, }) @api.multi @@ -673,7 +678,18 @@ class SaleOrder(models.Model): return self.get_share_url() def get_portal_confirmation_action(self): - return self.env['ir.config_parameter'].sudo().get_param('sale.sale_portal_confirmation_options', default='none') + if self.company_id.portal_confirmation_sign and not self.signature: + return 'sign' + if self.company_id.portal_confirmation_pay: + return 'pay' + + return 'none' + + def has_to_be_signed(self): + return self.company_id.portal_confirmation_sign + + def has_to_be_paid(self): + return self.company_id.portal_confirmation_pay @api.multi def _notify_get_groups(self, message, groups): diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml index 3b948aef951..a5da58ea770 100644 --- a/addons/sale/report/sale_report_templates.xml +++ b/addons/sale/report/sale_report_templates.xml @@ -202,6 +202,19 @@ Fiscal Position Remark:
+ +