odoo18/addons_extensions/sign/tests/test_sign_controllers.py

229 lines
12 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from unittest.mock import patch
from freezegun import freeze_time
from odoo.http import Request
from .sign_request_common import SignRequestCommon
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
from odoo.addons.sign.controllers.main import Sign
from odoo.exceptions import AccessError, ValidationError
from odoo.addons.website.tools import MockRequest
from odoo.tests import tagged
from odoo.tools import formataddr
class TestSignControllerCommon(SignRequestCommon, HttpCaseWithUserDemo):
def setUp(self):
super().setUp()
self.SignController = Sign()
def _json_url_open(self, url, data, **kwargs):
data = {
"id": 0,
"jsonrpc": "2.0",
"method": "call",
"params": data,
}
headers = {
"Content-Type": "application/json",
**kwargs.get('headers', {})
}
return self.url_open(url, data=json.dumps(data).encode(), headers=headers)
@tagged('post_install', '-at_install')
class TestSignController(TestSignControllerCommon):
# test float auto_field display
def test_sign_controller_float(self):
sign_request = self.create_sign_request_no_item(signer=self.partner_1, cc_partners=self.partner_4)
text_type = self.env['sign.item.type'].search([('name', '=', 'Text')])
# the partner_latitude expects 7 zeros of decimal precision
text_type.auto_field = 'partner_latitude'
token_a = self.env["sign.request.item"].search([('sign_request_id', '=', sign_request.id)]).access_token
with MockRequest(sign_request.env):
values = self.SignController.get_document_qweb_context(sign_request.id, token=token_a)
sign_type = list(filter(lambda sign_type: sign_type["name"] == "Text", values["sign_item_types"]))[0]
latitude = sign_type["auto_value"]
self.assertEqual(latitude, 0)
# test auto_field with wrong partner field
def test_sign_controller_dummy_fields(self):
text_type = self.env['sign.item.type'].search([('name', '=', 'Text')])
# we set a dummy field that raises an error
with self.assertRaises(ValidationError):
text_type.auto_field = 'this_is_not_a_partner_field'
# we set a field the demo user does not have access and must not be able to set as auto_field
self.patch(type(self.env['res.partner']).function, 'groups', 'base.group_system')
with self.assertRaises(AccessError):
text_type.with_user(self.user_demo).auto_field = 'function'
# test auto_field with multiple sub steps
def test_sign_controller_multi_step_auto_field(self):
self.partner_1.company_id = self.env.ref('base.main_company')
self.partner_1.company_id.country_id = self.env.ref('base.be').id
sign_request = self.create_sign_request_no_item(signer=self.partner_1, cc_partners=self.partner_4)
text_type = self.env['sign.item.type'].search([('name', '=', 'Text')])
text_type.auto_field = 'company_id.country_id.name'
token_a = self.env["sign.request.item"].search([('sign_request_id', '=', sign_request.id)]).access_token
with MockRequest(sign_request.env):
values = self.SignController.get_document_qweb_context(sign_request.id, token=token_a)
sign_type = list(filter(lambda sign_type: sign_type["name"] == "Text", values["sign_item_types"]))[0]
country = sign_type["auto_value"]
self.assertEqual(country, "Belgium")
def test_sign_request_requires_auth_when_credits_are_available(self):
sign_request = self.create_sign_request_1_role_sms_auth(self.partner_1, self.env['res.partner'])
sign_request_item = sign_request.request_item_ids[0]
self.assertFalse(sign_request_item.signed_without_extra_auth)
self.assertEqual(sign_request_item.role_id.auth_method, 'sms')
sign_vals = self.create_sign_values(sign_request.template_id.sign_item_ids, sign_request_item.role_id.id)
with patch('odoo.addons.iap.models.iap_account.IapAccount.get_credits', lambda self, x: 10):
response = self._json_url_open(
'/sign/sign/%d/%s' % (sign_request.id, sign_request_item.access_token),
data={'signature': sign_vals}
).json()['result']
self.assertFalse(response.get('success'))
self.assertTrue(sign_request_item.state, 'sent')
self.assertFalse(sign_request_item.signed_without_extra_auth)
def test_sign_request_allows_no_auth_when_credits_are_not_available(self):
sign_request = self.create_sign_request_1_role_sms_auth(self.partner_1, self.env['res.partner'])
sign_request_item = sign_request.request_item_ids[0]
self.assertFalse(sign_request_item.signed_without_extra_auth)
self.assertEqual(sign_request_item.role_id.auth_method, 'sms')
sign_vals = self.create_sign_values(sign_request.template_id.sign_item_ids, sign_request_item.role_id.id)
with patch('odoo.addons.iap.models.iap_account.IapAccount.get_credits', lambda self, x: 0):
response = self._json_url_open(
'/sign/sign/%d/%s' % (sign_request.id, sign_request_item.access_token),
data={'signature': sign_vals}
).json()['result']
self.assertTrue(response.get('success'))
self.assertTrue(sign_request_item.state, 'completed')
self.assertTrue(sign_request.state, 'done')
self.assertTrue(sign_request_item.signed_without_extra_auth)
def test_sign_from_mail_no_expiry_params(self):
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
url = '/sign/document/mail/%s/%s' % (sign_request.id, sign_request.request_item_ids[0].access_token)
response = self.url_open(url)
self.assertEqual(response.status_code, 404)
self.assertTrue('The signature request might have been deleted or modified.' in response.text)
def test_sign_from_mail_link_not_expired(self):
with freeze_time('2020-01-01'):
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
sign_request_item_id = sign_request.request_item_ids[0]
timestamp = sign_request_item_id._generate_expiry_link_timestamp()
expiry_hash = sign_request_item_id._generate_expiry_signature(sign_request_item_id.id, timestamp)
url = '/sign/document/mail/%(sign_request_id)s/%(access_token)s?timestamp=%(timestamp)s&exp=%(exp)s' % {
'sign_request_id': sign_request.id,
'access_token': sign_request.request_item_ids[0].access_token,
'timestamp': timestamp,
'exp': expiry_hash
}
response = self.url_open(url)
self.assertEqual(response.status_code, 200)
self.assertTrue('/sign/document/%s/%s' % (sign_request.id, sign_request_item_id.access_token) in response.url)
def test_sign_from_mail_with_expired_link(self):
with freeze_time('2020-01-01'):
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
sign_request_item_id = sign_request.request_item_ids[0]
timestamp = sign_request_item_id._generate_expiry_link_timestamp()
expiry_hash = sign_request_item_id._generate_expiry_signature(sign_request_item_id.id, timestamp)
with freeze_time('2020-01-04'):
url = '/sign/document/mail/%(sign_request_id)s/%(access_token)s?timestamp=%(timestamp)s&exp=%(exp)s' % {
'sign_request_id': sign_request.id,
'access_token': sign_request.request_item_ids[0].access_token,
'timestamp': timestamp,
'exp': expiry_hash
}
response = self.url_open(url)
self.assertEqual(response.status_code, 403)
self.assertTrue('This link has expired' in response.text)
def test_shared_sign_request_without_expiry_params(self):
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
sign_request.state = 'shared'
sign_request_item_id = sign_request.request_item_ids[0]
url = '/sign/document/mail/%s/%s' % (sign_request.id, sign_request_item_id.access_token)
response = self.url_open(url)
self.assertEqual(response.status_code, 200)
self.assertTrue('/sign/document/%s/%s' % (sign_request.id, sign_request_item_id.access_token) in response.url)
def test_sign_from_resend_expired_link(self):
with freeze_time('2020-01-01'):
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
sign_request_item_id = sign_request.request_item_ids[0]
timestamp = sign_request_item_id._generate_expiry_link_timestamp()
expiry_hash = sign_request_item_id._generate_expiry_signature(sign_request_item_id.id, timestamp)
url = '/sign/document/mail/%(sign_request_id)s/%(access_token)s?timestamp=%(timestamp)s&exp=%(exp)s' % {
'sign_request_id': sign_request.id,
'access_token': sign_request.request_item_ids[0].access_token,
'timestamp': timestamp,
'exp': expiry_hash
}
response = self.url_open(url)
self.assertEqual(response.status_code, 200)
self.assertTrue('/sign/document/%s/%s' % (sign_request.id, sign_request_item_id.access_token) in response.url)
sign_request_item = {sign_request_item.role_id: sign_request_item for sign_request_item in sign_request.request_item_ids}
sign_request_item_customer = sign_request_item[self.role_customer]
sign_request_item_customer.sudo()._edit_and_sign(self.single_role_customer_sign_values)
mail = self.env['mail.mail'].search([('email_to', '=', formataddr((self.partner_1.name, self.partner_1.email)))])
self.assertEqual(len(mail.ids), 2)
with freeze_time('2020-01-04'):
self.start_tour(url, 'sign_resend_expired_link_tour', login='demo')
def test_cancel_request_as_public_user(self):
"""
Test that a public user can cancel a sign request and that a cancellation log is recorded on the partner_id.
"""
sign_request = self.create_sign_request_1_role(self.partner_1, self.env['res.partner'])
sign_request_item = sign_request.request_item_ids[0]
url = '/sign/sign_confirm_cancel/%(item_id)s' % {
'item_id': sign_request_item.id,
}
# Set the environment user as the public user
self.env.user = self.public_user
# Send a request to cancel the sign request item
self.authenticate(None, None)
post_data = {
'access_token': sign_request_item.access_token,
'csrf_token': Request.csrf_token(self),
}
response = self.url_open(url, data=post_data)
self.assertEqual(response.status_code, 200)
self.assertEqual(sign_request.state, 'canceled', "Sign request state should be 'canceled'")
self.assertEqual(sign_request_item.state, 'canceled', "Sign request item state should be 'canceled'")
sign_cancel_log = self.env['sign.log'].search([
('sign_request_id', '=', sign_request.id),
('action', '=', 'cancel')
])
self.assertTrue(sign_cancel_log, "A sign cancel log should be created")
self.assertEqual(sign_cancel_log.request_state, 'canceled',
"Log request state should be 'canceled'")
self.assertEqual(sign_cancel_log.partner_id, self.partner_1,
"Log partner_id should match partner_1")
self.assertEqual(sign_cancel_log.sign_request_item_id.id, sign_request_item.id,
"Log should reference the correct request item")