# -*- coding: utf-8 -*- # Copyright 2024-2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) import base64 import json import logging from odoo import http, fields, _ from odoo.http import request _logger = logging.getLogger(__name__) class Page11PublicSignController(http.Controller): def _get_sign_request(self, token): """Look up and validate a signing request by token.""" req = request.env['fusion.page11.sign.request'].sudo().search([ ('access_token', '=', token), ], limit=1) if not req: return None, 'not_found' if req.state == 'signed': return req, 'already_signed' if req.state == 'cancelled': return req, 'cancelled' if req.state == 'expired' or ( req.expiry_date and req.expiry_date < fields.Datetime.now() ): if req.state != 'expired': req.state = 'expired' return req, 'expired' return req, 'ok' @http.route('/page11/sign/', type='http', auth='public', website=True, sitemap=False) def page11_sign_form(self, token, **kw): """Display the Page 11 signing form.""" sign_req, status = self._get_sign_request(token) if status == 'not_found': return request.render( 'fusion_portal.portal_page11_sign_invalid', {} ) if status in ('expired', 'cancelled'): return request.render( 'fusion_portal.portal_page11_sign_expired', {'sign_request': sign_req}, ) if status == 'already_signed': return request.render( 'fusion_portal.portal_page11_sign_success', {'sign_request': sign_req, 'token': token}, ) order = sign_req.sale_order_id partner = order.partner_id assessment = request.env['fusion.assessment'].sudo().search([ ('sale_order_id', '=', order.id), ], limit=1, order='create_date desc') ICP = request.env['ir.config_parameter'].sudo() google_maps_api_key = ICP.get_param('fusion_claims.google_maps_api_key', '') client_first_name = '' client_last_name = '' client_middle_name = '' client_health_card = '' client_health_card_version = '' if assessment: client_first_name = assessment.client_first_name or '' client_last_name = assessment.client_last_name or '' client_middle_name = assessment.client_middle_name or '' client_health_card = assessment.client_health_card or '' client_health_card_version = assessment.client_health_card_version or '' else: first, last = order._get_client_name_parts() client_first_name = first client_last_name = last values = { 'sign_request': sign_req, 'order': order, 'partner': partner, 'assessment': assessment, 'company': order.company_id, 'token': token, 'signer_type': sign_req.signer_type, 'is_agent': sign_req.signer_type != 'client', 'google_maps_api_key': google_maps_api_key, 'client_first_name': client_first_name, 'client_last_name': client_last_name, 'client_middle_name': client_middle_name, 'client_health_card': client_health_card, 'client_health_card_version': client_health_card_version, } return request.render( 'fusion_portal.portal_page11_public_sign', values, ) @http.route('/page11/sign//submit', type='http', auth='public', methods=['POST'], website=True, csrf=True, sitemap=False) def page11_sign_submit(self, token, **post): """Process the submitted Page 11 signature.""" sign_req, status = self._get_sign_request(token) if status != 'ok': return request.redirect(f'/page11/sign/{token}') signature_data = post.get('signature_data', '') if not signature_data: return request.redirect(f'/page11/sign/{token}?error=no_signature') if signature_data.startswith('data:image'): signature_data = signature_data.split(',', 1)[1] consent_accepted = post.get('consent_declaration', '') == 'on' if not consent_accepted: return request.redirect(f'/page11/sign/{token}?error=no_consent') signer_name = post.get('signer_name', sign_req.signer_name or '') chosen_signer_type = post.get('signer_type', sign_req.signer_type or 'client') consent_signed_by = 'applicant' if chosen_signer_type == 'client' else 'agent' signer_type_labels = { 'spouse': 'Spouse', 'parent': 'Parent', 'legal_guardian': 'Legal Guardian', 'poa': 'Power of Attorney', 'public_trustee': 'Public Trustee', } vals = { 'signature_data': signature_data, 'signer_name': signer_name, 'signer_type': chosen_signer_type, 'consent_declaration_accepted': True, 'consent_signed_by': consent_signed_by, 'signed_date': fields.Datetime.now(), 'state': 'signed', 'client_first_name': post.get('client_first_name', ''), 'client_last_name': post.get('client_last_name', ''), 'client_health_card': post.get('client_health_card', ''), 'client_health_card_version': post.get('client_health_card_version', ''), } if consent_signed_by == 'agent': vals.update({ 'agent_first_name': post.get('agent_first_name', ''), 'agent_last_name': post.get('agent_last_name', ''), 'agent_middle_initial': post.get('agent_middle_initial', ''), 'agent_phone': post.get('agent_phone', ''), 'agent_unit': post.get('agent_unit', ''), 'agent_street_number': post.get('agent_street_number', ''), 'agent_street': post.get('agent_street', ''), 'agent_city': post.get('agent_city', ''), 'agent_province': post.get('agent_province', 'Ontario'), 'agent_postal_code': post.get('agent_postal_code', ''), 'signer_relationship': signer_type_labels.get(chosen_signer_type, chosen_signer_type), }) sign_req.sudo().write(vals) try: sign_req.sudo()._generate_signed_pdf() except Exception as e: _logger.error("PDF generation failed for sign request %s: %s", sign_req.id, e) try: sign_req.sudo()._update_sale_order() except Exception as e: _logger.error("Sale order update failed for sign request %s: %s", sign_req.id, e) return request.render( 'fusion_portal.portal_page11_sign_success', {'sign_request': sign_req, 'token': token}, ) @http.route('/page11/sign//download', type='http', auth='public', website=True, sitemap=False) def page11_download_pdf(self, token, **kw): """Download the signed Page 11 PDF.""" sign_req = request.env['fusion.page11.sign.request'].sudo().search([ ('access_token', '=', token), ('state', '=', 'signed'), ], limit=1) if not sign_req or not sign_req.signed_pdf: return request.redirect(f'/page11/sign/{token}') pdf_content = base64.b64decode(sign_req.signed_pdf) filename = sign_req.signed_pdf_filename or 'Page11_Signed.pdf' return request.make_response( pdf_content, headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', f'attachment; filename="{filename}"'), ('Content-Length', str(len(pdf_content))), ], )