# -*- coding: utf-8 -*- import base64 import io from odoo import Command from odoo.exceptions import AccessError, UserError from odoo.tests import tagged from odoo.tools import file_open from odoo.tools.pdf import OdooPdfFileWriter from odoo.addons.sign.tests.sign_request_common import SignRequestCommon GIF = b"R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs=" @tagged('post_install', '-at_install') class TestCaseDocumentsBridgeSign(SignRequestCommon): """ """ def setUp(self): super(TestCaseDocumentsBridgeSign, self).setUp() with file_open('sign/static/demo/sample_contract.pdf', "rb") as f: pdf_content = f.read() self.folder_a = self.env['documents.document'].create({ 'name': 'folder A', 'type': 'folder', }) self.folder_a_a = self.env['documents.document'].create({ 'name': 'folder A - A', 'type': 'folder', 'folder_id': self.folder_a.id, }) self.documents = self.env['documents.document'].create([{ 'datas': base64.encodebytes(pdf_content), 'name': f'file_{idx}.pdf', 'folder_id': self.folder_a_a.id, } for idx in range(2)]) self.document_pdf_0 = self.documents[0] def test_bridge_folder_workflow(self): """ tests the create new business model (sign). """ self.assertFalse(self.document_pdf_0.res_model) action = self.documents.document_sign_create_sign_template(self.folder_a.id) self.assertFalse(self.document_pdf_0.res_model) template_id = action.get('params', {}).get('id') template = self.env['sign.template'].browse(template_id) document = self.env['sign.document'].search([('template_id', '=', template.id)], limit=1) self.assertTrue(document.exists(), 'failed at workflow_bridge_dms_account template') self.assertTrue(template.exists(), 'failed at workflow_bridge_dms_account template') def test_sign_action(self): """ Test sign a document from Document app using the workflow rule. """ action = self.document_pdf_0.document_sign_create_sign_template(self.folder_a.id) template_id = action.get('params', {}).get('id') template = self.env['sign.template'].browse(template_id) document = self.env['sign.document'].search([('template_id', '=', template.id)], limit=1) # Create a sign item directly for the new template self.env['sign.item'].create({ 'type_id': self.env.ref('sign.sign_item_type_text').id, 'required': True, 'responsible_id': self.env.ref('sign.sign_item_role_default').id, 'page': 1, 'posX': 0.273, 'posY': 0.158, 'document_id': document.id, 'width': 0.150, 'height': 0.015, }) sign_request = self.env['sign.request'].create({ 'template_id': template.id, 'reference': template.display_name, 'request_item_ids': [Command.create({ 'partner_id': self.partner_1.id, 'role_id': self.env.ref('sign.sign_item_role_default').id, })], }) sign_request_item = sign_request.request_item_ids[0] sign_values = self.create_sign_values(template.sign_item_ids, self.env.ref('sign.sign_item_role_default').id) with self.allow_pdf_render(): sign_request_item.with_context(force_report_rendering=True).sign(sign_values) self.assertEqual(sign_request_item.state, 'completed', 'The sign.request.item should be completed') def test_signed_documents_access_rights(self): """ Test access rights and owner of signed/certificate documents. """ Document = self.env["documents.document"] Partner = self.env["res.partner"] User = self.env["res.users"] users = User.create([ { "name": f"test_sign_owner_{group}", "login": f"test_sign_owner_{group}@ex.com", "email": f"test_sign_owner_{group}@ex.com", "group_ids": [Command.set([self.env.ref(group).id])] } for group in ("base.group_portal", "base.group_user", "sign.group_sign_user", "sign.group_sign_manager") ]) user_sign_manager = users[-1] self.template_1_role.folder_id = self.folder_a self.folder_a.action_update_access_rights(partners={user_sign_manager.partner_id: ('edit', False)}) all_documents_signed = self.env['documents.document'] for user in users: with self.subTest(user_name=user.name): sign_request = self.create_sign_request_1_role(user.partner_id, Partner) # See /sign/sign// controller with self.allow_pdf_render(): sign_request.request_item_ids[0].with_user(user).sudo().with_context(force_report_rendering=True).sign( {str(self.template_1_role.sign_item_ids[0].id): "Test Sign"}) self.env['documents.access'].invalidate_model() documents_signed = Document.search( [('res_model', '=', 'sign.request'), ('res_id', '=', sign_request.id)]) all_documents_signed |= documents_signed self.assertEqual(len(documents_signed), 2) self.assertFalse(documents_signed.owner_id, "Owner of the signed/certificate documents must be false.") for doc in documents_signed: self.assertEqual(doc.access_via_link, "none") self.assertEqual(doc.access_internal, "none") self.assertTrue(doc.is_access_via_link_hidden) self.assertFalse(doc.owner_id) self.assertEqual(doc.partner_id, user.partner_id) access_by_partner = {access.partner_id: access for access in doc.access_ids} self.assertEqual(len(doc.access_ids), 1 if user == user_sign_manager else 2) access_manager = access_by_partner.get(user_sign_manager.partner_id) self.assertTrue(access_manager) self.assertEqual(access_manager.role, "edit") self.assertFalse(access_manager.expiration_date) if user != user_sign_manager: access_signer = access_by_partner.get(user.partner_id) self.assertTrue(access_signer) self.assertEqual(access_signer.role, "view") self.assertFalse(access_signer.expiration_date) if user == user_sign_manager: break doc.with_user(user).mapped("name") with self.assertRaises( AccessError, msg="Users without edit permission on the folder cannot edit the signature", ): doc.with_user(user).write({"name": "New name"}) # user_sign_manager have edit access on all the signed documents self.assertEqual(len(all_documents_signed), 8) for doc in all_documents_signed: doc.with_user(user_sign_manager).name = "Name overridden by the manager" def test_correct_reference_doc_set(self): """Verifies that the correct reference document is linked to a sign request. Ensures that when documents have identical checksums, the sign request is only linked to the document it originated from.""" writer = OdooPdfFileWriter() writer.addBlankPage(width=200, height=200) stream = io.BytesIO() writer.write(stream) # create a document self.env['documents.document'].create({ 'name': 'another.pdf', 'datas': base64.b64encode(stream.getvalue()), 'access_internal': 'view', 'folder_id': self.folder_a_a.id, }) # create a document to sign with the same content document_to_sign = self.env['documents.document'].create({ 'name': 'test.pdf', 'datas': base64.b64encode(stream.getvalue()), 'access_internal': 'view', 'folder_id': self.folder_a_a.id, }) with self.subTest("Ensure sign request does not link to unrelated documents and cause access errors"): # create a sign template with the same content then request a signature with self.with_user(self.user_1.login): attachment = self.env['ir.attachment'].create({ 'name': 'test.pdf', 'datas': base64.b64encode(stream.getvalue()), 'mimetype': 'application/pdf', }) template = self.env['sign.template'].create({ 'folder_id': self.folder_a_a.id, }) self.env['sign.document'].create({ 'attachment_id': attachment.id, 'template_id': template.id, }) wizard = self.env['sign.send.request'].create({ 'template_id': template.id, 'subject': 'test test', 'filename': 'test.pdf', 'signer_id': self.user_1.partner_id.id, }) unrelated_request = wizard.create_request() wizard._create_request_log_note(unrelated_request) self.assertIsNone(unrelated_request.reference_doc, "Sign request should not be linked to unrelated documents") with self.subTest("Ensure sign request links to the correct document"): # create a sign request from the document_to_sign action = document_to_sign.document_sign_create_sign_template() document_sign_template = self.env['sign.template'].browse(action['params']['id']) wizard = self.env['sign.send.request'].create({ 'template_id': document_sign_template.id, 'subject': 'test test', 'filename': 'test.pdf', 'signer_id': self.env.user.partner_id.id, }) related_request = wizard.create_request() wizard._create_request_log_note(related_request) # Verify that the request got linked to the document_to_sign self.assertEqual(related_request.reference_doc, document_to_sign) def test_import_document(self): """ This test verifies that a user can import a document from the Documents app and create a sign template from it by calling the action_import_and_create method. """ writer = OdooPdfFileWriter() writer.addBlankPage(width=200, height=200) stream = io.BytesIO() writer.write(stream) # Create a document document = self.env['documents.document'].create({ 'name': 'test_import_document.pdf', 'datas': base64.b64encode(stream.getvalue()), 'access_internal': 'view', 'folder_id': self.folder_a_a.id, }) # Create a wizard for importing documents wizard = self.env['sign.import.documents'].with_user(self.env.user).create({ 'selected_document': document.id, }) # Perform the import and create action result = wizard.action_import_and_create() # Assertions to verify the result self.assertEqual(result['type'], 'ir.actions.client') self.assertEqual(result['tag'], 'sign.Template') self.assertTrue(result['params']['id'], "Template ID should be created") # Verify template creation template = self.env['sign.template'].browse(result['params']['id']) self.assertTrue(template.exists(), "Sign template should be created") def test_signed_document_requester_access(self): """ Verifies that the requester of a sign request has at least view access to the signed document. """ Document = self.env["documents.document"] User = self.env["res.users"] signer, requester = User.create([{ "name": f"test_sign_{role}", "login": f"test_sign_{role}@ex.com", "email": f"test_sign_{role}@ex.com", "group_ids": [Command.set([self.env.ref("sign.group_sign_manager").id])] } for role in ("signer", "requester")]) self.template_1_role.folder_id = self.folder_a sign_request = self.env['sign.request'].with_user(requester).create({ 'template_id': self.template_1_role.id, 'reference': self.template_1_role.display_name, 'request_item_ids': [Command.create({ 'partner_id': signer.partner_id.id, 'role_id': self.role_signer_1.id, })], }) with self.allow_pdf_render(): sign_request.request_item_ids[0].with_user(signer).sudo().with_context(force_report_rendering=True).sign( {str(self.template_1_role.sign_item_ids[0].id): "Test Sign"}) documents_signed = Document.search( [('res_model', '=', 'sign.request'), ('res_id', '=', sign_request.id)]) self.assertEqual(len(documents_signed), 2) for doc in documents_signed: # The requester has view access to the signed document access_by_partner = doc.access_ids.grouped('partner_id') requester_access = access_by_partner[requester.partner_id] self.assertIsNotNone(requester_access, "The requester should have access to the signed document") doc.with_user(requester).check_access('read')