[FIX] account_peppol: fix saving of the migration key
`account_peppol_migration_key` is a related field, stored on the `account_edi_proxy_client.user`. We want to allow users to provide a migration key when they want to register as a new peppol participant, migrating their existing peppol registration from another smp. However, before they save and validate their registration, there is no `account_edi_proxy_client.user` associated with the company and hence the `migration_key` is never saved and never sent to the IAP server. The solution in master will be to move this field to `res.company` but in stable the workaround is to store it in `ir.config_parameter` and make it a computed field, where the config parameter is updated in the inverse method on `account_peppol_migration_key`. closes odoo/odoo#129691 X-original-commit: d5edca101e6a1dd751a3c95d713831e99fc18462 Signed-off-by: Laurent Smet (las) <las@odoo.com> Signed-off-by: Aliya Tastemirova (alta) <alta@odoo.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import _, fields, models, tools
|
||||
from odoo import _, fields, models, modules, tools
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.addons.account_edi_proxy_client.models.account_edi_proxy_user import AccountEdiProxyError
|
||||
|
||||
@@ -34,7 +34,17 @@ class AccountEdiProxyClientUser(models.Model):
|
||||
and not self.active
|
||||
and not self.company_id.account_edi_proxy_client_ids.filtered(lambda u: u.proxy_type == 'peppol')
|
||||
):
|
||||
self.company_id.account_peppol_proxy_state = 'not_registered'
|
||||
self.company_id.write({
|
||||
'account_peppol_proxy_state': 'not_registered',
|
||||
'is_account_peppol_participant': False,
|
||||
})
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
f'account_peppol.migration_key_{self.company_id.id}',
|
||||
False
|
||||
)
|
||||
# commit the above changes before raising below
|
||||
if not tools.config['test_enable'] and not modules.module.current_test:
|
||||
self.env.cr.commit()
|
||||
raise AccountEdiProxyError(e.code, e.message)
|
||||
return result
|
||||
|
||||
|
||||
@@ -27,7 +27,12 @@ class ResConfigSettings(models.TransientModel):
|
||||
string="Warning",
|
||||
compute="_compute_account_peppol_endpoint_warning",
|
||||
)
|
||||
account_peppol_migration_key = fields.Char(related='account_peppol_edi_user.peppol_migration_key', readonly=False)
|
||||
# to be changed in master to be a related field on res_company
|
||||
account_peppol_migration_key = fields.Char(
|
||||
compute="_compute_account_peppol_migration_key",
|
||||
inverse="_inverse_account_peppol_migration_key",
|
||||
readonly=False,
|
||||
)
|
||||
account_peppol_phone_number = fields.Char(related='company_id.account_peppol_phone_number', readonly=False)
|
||||
account_peppol_proxy_state = fields.Selection(related='company_id.account_peppol_proxy_state', readonly=False)
|
||||
account_peppol_purchase_journal_id = fields.Many2one(related='company_id.peppol_purchase_journal_id', readonly=False)
|
||||
@@ -54,7 +59,7 @@ class ResConfigSettings(models.TransientModel):
|
||||
|
||||
def _call_peppol_proxy(self, endpoint, params=None, edi_user=None):
|
||||
if not edi_user:
|
||||
edi_user = self.company_id.account_edi_proxy_client_ids[0]
|
||||
edi_user = self.company_id.account_edi_proxy_client_ids.filtered(lambda u: u.proxy_type == 'peppol')
|
||||
|
||||
params = params or {}
|
||||
try:
|
||||
@@ -103,6 +108,20 @@ class ResConfigSettings(models.TransientModel):
|
||||
config.account_peppol_endpoint_warning = _("The endpoint number might not be correct. "
|
||||
"Please check if you entered the right identification number.")
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_account_peppol_migration_key(self):
|
||||
for config in self:
|
||||
config.account_peppol_migration_key = self.env['ir.config_parameter'].get_param(
|
||||
f'account_peppol.migration_key_{config.company_id.id}'
|
||||
)
|
||||
|
||||
def _inverse_account_peppol_migration_key(self):
|
||||
for config in self:
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
f'account_peppol.migration_key_{config.company_id.id}',
|
||||
config.account_peppol_migration_key
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# BUSINESS ACTIONS
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ from freezegun import freeze_time
|
||||
from unittest.mock import Mock, patch
|
||||
from psycopg2 import IntegrityError
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
from odoo.tests.common import tagged, TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
@@ -18,26 +18,64 @@ PDF_FILE_PATH = 'account_peppol/tests/assets/peppol_identification_test.pdf'
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPeppolParticipant(TransactionCase):
|
||||
|
||||
def _get_participant_vals(self):
|
||||
return {
|
||||
'is_account_peppol_participant': True,
|
||||
'account_peppol_eas': '9925',
|
||||
'account_peppol_endpoint': '0000000000',
|
||||
'account_peppol_phone_number': '+32483123456',
|
||||
}
|
||||
|
||||
@contextmanager
|
||||
def _patch_peppol_requests(self, reject=False):
|
||||
def _patch_peppol_requests(self, reject=False, migrate_to=False, migrated_away=False):
|
||||
responses = {
|
||||
'/peppol/1/participant_status': {
|
||||
'result': {
|
||||
'peppol_state': 'active' if not reject else 'rejected',
|
||||
}
|
||||
},
|
||||
'/peppol/1/activate_participant': {'result': {}},
|
||||
'/account_edi/2/create_user': {
|
||||
'result': {
|
||||
'id_client': ID_CLIENT,
|
||||
'refresh_token': FAKE_UUID,
|
||||
}
|
||||
},
|
||||
'/peppol/1/send_verification_code': {'result': {}},
|
||||
'/peppol/1/update_user': {'result': {}},
|
||||
'/peppol/1/verify_phone_number': {'result': {}},
|
||||
'/peppol/1/migrate_peppol_registration': {
|
||||
'result': {
|
||||
'migration_key': 'test_key',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
def _mocked_post(url, *args, **kwargs):
|
||||
response = Mock()
|
||||
response.status_code = 200
|
||||
if url.endswith('api/peppol/1/participant_status'):
|
||||
response.json = lambda: {'result': {
|
||||
'peppol_state': 'active' if not reject else 'rejected',
|
||||
}}
|
||||
elif url.endswith('/api/peppol/1/activate_participant'):
|
||||
response.json = lambda: {'result': {}}
|
||||
elif url.endswith('/iap/account_edi/2/create_user'):
|
||||
response.json = lambda: {'result': {
|
||||
'id_client': ID_CLIENT, 'refresh_token': FAKE_UUID}}
|
||||
elif url.endswith('/api/peppol/1/send_verification_code')\
|
||||
or url.endswith('/api/peppol/1/update_user')\
|
||||
or url.endswith('/api/peppol/1/verify_phone_number'):
|
||||
response.json = lambda: {'result': {}}
|
||||
else:
|
||||
if (
|
||||
url.endswith('/api/peppol/1/activate_participant')
|
||||
and migrate_to
|
||||
and not kwargs['json']['params']['migration_key']
|
||||
):
|
||||
raise UserError('No migration key was provided')
|
||||
|
||||
if migrated_away:
|
||||
response.json = lambda: {
|
||||
'result': {
|
||||
'proxy_error': {
|
||||
'code': 'no_such_user',
|
||||
'message': 'The user does not exist on the proxy',
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
|
||||
url = url.split('/api')[1] if 'iap' not in url else url.split('/iap')[1]
|
||||
if url not in responses:
|
||||
raise Exception(f'Unexpected request: {url}')
|
||||
response.json = lambda: responses[url]
|
||||
|
||||
return response
|
||||
|
||||
@@ -46,8 +84,7 @@ class TestPeppolParticipant(TransactionCase):
|
||||
|
||||
def test_create_participant_missing_data(self):
|
||||
# creating a participant without eas/endpoint/document should not be possible
|
||||
settings = self.env['res.config.settings'].create({})
|
||||
settings.write({
|
||||
settings = self.env['res.config.settings'].create({
|
||||
'is_account_peppol_participant': True,
|
||||
'account_peppol_eas': False,
|
||||
'account_peppol_endpoint': False,
|
||||
@@ -60,16 +97,8 @@ class TestPeppolParticipant(TransactionCase):
|
||||
# the account_peppol_proxy_state should correctly change to pending
|
||||
# then the account_peppol_proxy_state should change success
|
||||
# after checking participant status
|
||||
settings = self.env['res.config.settings'].create({})
|
||||
settings.write({
|
||||
'is_account_peppol_participant': True,
|
||||
'account_peppol_eas': '9925',
|
||||
'account_peppol_endpoint': '0000000000',
|
||||
'account_peppol_phone_number': '+32483123456',
|
||||
})
|
||||
company = self.env.company
|
||||
|
||||
settings.execute()
|
||||
settings = self.env['res.config.settings'].create(self._get_participant_vals())
|
||||
|
||||
with self._patch_peppol_requests():
|
||||
settings.button_create_peppol_proxy_user()
|
||||
@@ -85,16 +114,8 @@ class TestPeppolParticipant(TransactionCase):
|
||||
def test_create_reject_participant(self):
|
||||
# the account_peppol_proxy_state should change to rejected
|
||||
# if we reject the participant
|
||||
settings = self.env['res.config.settings'].create({})
|
||||
settings.write({
|
||||
'is_account_peppol_participant': True,
|
||||
'account_peppol_eas': '9925',
|
||||
'account_peppol_endpoint': '0000000000',
|
||||
'account_peppol_phone_number': '+32483123456',
|
||||
})
|
||||
company = self.env.company
|
||||
|
||||
settings.execute()
|
||||
settings = self.env['res.config.settings'].create(self._get_participant_vals())
|
||||
|
||||
with self._patch_peppol_requests(reject=True):
|
||||
settings.button_create_peppol_proxy_user()
|
||||
@@ -105,18 +126,60 @@ class TestPeppolParticipant(TransactionCase):
|
||||
@mute_logger('odoo.sql_db')
|
||||
def test_create_duplicate_participant(self):
|
||||
# should not be possible to create a duplicate participant
|
||||
settings = self.env['res.config.settings'].create({})
|
||||
settings.write({
|
||||
'is_account_peppol_participant': True,
|
||||
'account_peppol_eas': '9925',
|
||||
'account_peppol_endpoint': '0000000000',
|
||||
'account_peppol_phone_number': '+32483123456',
|
||||
})
|
||||
|
||||
settings.execute()
|
||||
settings = self.env['res.config.settings'].create(self._get_participant_vals())
|
||||
|
||||
with self._patch_peppol_requests():
|
||||
settings.button_create_peppol_proxy_user()
|
||||
with self.assertRaises(IntegrityError), self.cr.savepoint():
|
||||
settings.account_peppol_proxy_state = 'not_registered'
|
||||
settings.button_create_peppol_proxy_user()
|
||||
|
||||
def test_save_migration_key(self):
|
||||
# migration key should be saved
|
||||
settings = self.env['res.config.settings']\
|
||||
.create({
|
||||
**self._get_participant_vals(),
|
||||
'account_peppol_migration_key': 'helloo',
|
||||
})
|
||||
|
||||
with self._patch_peppol_requests(migrate_to=True):
|
||||
settings.button_create_peppol_proxy_user()
|
||||
self.assertEqual(self.env.company.account_peppol_proxy_state, 'not_verified')
|
||||
self.assertFalse(settings.account_peppol_migration_key) # the key should be reset once we've used it
|
||||
|
||||
def test_migrate_away_participant(self):
|
||||
# a participant should be able to request a migration key
|
||||
settings = self.env['res.config.settings'].create(self._get_participant_vals())
|
||||
|
||||
with self._patch_peppol_requests():
|
||||
self.assertFalse(settings.account_peppol_migration_key)
|
||||
settings.button_create_peppol_proxy_user()
|
||||
settings.account_peppol_proxy_state = 'active'
|
||||
settings.button_migrate_peppol_registration()
|
||||
self.assertEqual(self.env.company.account_peppol_proxy_state, 'active')
|
||||
self.assertEqual(settings.account_peppol_migration_key, 'test_key')
|
||||
|
||||
def test_reset_participant(self):
|
||||
# once a participant has migrated away, they should be reset
|
||||
settings = self.env['res.config.settings'].create(self._get_participant_vals())
|
||||
|
||||
with self._patch_peppol_requests():
|
||||
settings.button_create_peppol_proxy_user()
|
||||
settings.account_peppol_proxy_state = 'active'
|
||||
settings.button_migrate_peppol_registration()
|
||||
|
||||
with self._patch_peppol_requests(migrated_away=True):
|
||||
try:
|
||||
settings.button_update_peppol_user_data()
|
||||
except UserError:
|
||||
settings.execute()
|
||||
self.assertRecordValues(
|
||||
settings, [{
|
||||
'account_peppol_migration_key': False,
|
||||
'is_account_peppol_participant': False,
|
||||
'account_peppol_proxy_state': 'not_registered',
|
||||
}]
|
||||
)
|
||||
self.assertFalse(self.env.company.account_edi_proxy_client_ids.filtered(lambda u: u.proxy_type == 'peppol'))
|
||||
else:
|
||||
raise ValidationError('A UserError should be raised.')
|
||||
|
||||
Reference in New Issue
Block a user