[IMP] account_*: Proxy user refactor

- Proxy user is no longer a computed store=True field, but a proper one.
  The type cannot be deduced just by some field on the company.
  A company may be Italian and also use Peppol, so the two Proxy Users
  must be different.
- The Proxy user `get_proxy_identification` method needs a proxy_type
  argument, otherwise the method won't know if the current override
  is to be applied or not. It cannot be handled by a field of the user
  itself because it is also used contextually to the user creation.
- new `_get_default_enable_send_by_post` function on the Send and Print
  wizard, so that it can be overridden by the features of the move
- Renamed `_compute_send_mail_extra_fields`
  to `_compute_fields_from_moves_state`

Part-of: odoo/odoo#122194
This commit is contained in:
Paolo Gatti (pgi)
2023-09-19 16:37:09 +00:00
parent 16cbb825a8
commit 43fc30a3f7
8 changed files with 35 additions and 48 deletions
+6
View File
@@ -96,6 +96,9 @@ class IrAttachment(models.Model):
This function is meant to be overriden to add formats.
:returns: A list of dictionary.
* format: Optional but helps debugging.
There are other methods that require the attachment
to be an XML other than the standard one.
* check: Function to be called on the attachment to pre-check if decoding will work.
* decoder: Function to be called on the attachment to unwrap it.
"""
@@ -109,14 +112,17 @@ class IrAttachment(models.Model):
return [
{
'format': 'pdf',
'check': lambda attachment: 'pdf' in attachment.mimetype,
'decoder': self._decode_edi_pdf,
},
{
'format': 'xml',
'check': is_xml,
'decoder': self._decode_edi_xml,
},
{
'format': 'binary',
'check': lambda attachment: True,
'decoder': self._decode_edi_binary,
},
@@ -47,13 +47,7 @@ class AccountEdiProxyClientUser(models.Model):
private_key = fields.Binary(required=True, attachment=False, groups="base.group_system", help="The key to encrypt all the user's data")
private_key_filename = fields.Char(compute='_compute_private_key_filename')
refresh_token = fields.Char(groups="base.group_system")
proxy_type = fields.Selection(
selection=[],
string="Proxy type",
compute='_compute_proxy_type',
readonly=False,
store=True,
)
proxy_type = fields.Selection(selection=[], required=True)
edi_mode = fields.Selection(
selection=[
('prod', 'Production mode'),
@@ -84,11 +78,6 @@ class AccountEdiProxyClientUser(models.Model):
WHERE (active = True)
""")
@api.depends('company_id')
def _compute_proxy_type(self):
for user in self:
user.proxy_type = False
def _compute_private_key_filename(self):
for record in self:
record.private_key_filename = f'{record.id_client}_{record.edi_identification}.key'
@@ -109,7 +98,7 @@ class AccountEdiProxyClientUser(models.Model):
'''
return company.account_edi_proxy_client_ids.filtered(lambda u: u.proxy_type == proxy_type)
def _get_proxy_identification(self, company):
def _get_proxy_identification(self, company, proxy_type):
'''Returns the key that will identify company uniquely
within a specific proxy type and edi operating mode.
or raises a UserError (if the user didn't fill the related field).
@@ -127,9 +116,9 @@ class AccountEdiProxyClientUser(models.Model):
'id': uuid.uuid4().hex,
}
# Last barrier : in case the demo mode is not handled by the caller, we block access.
if self.edi_mode == 'demo':
# Last barrier : in case the demo mode is not handled by the caller, we block access.
raise Exception("Can't access the proxy in demo mode")
raise AccountEdiProxyError("block_demo_mode", "Can't access the proxy in demo mode")
try:
response = requests.post(
@@ -162,13 +151,11 @@ class AccountEdiProxyClientUser(models.Model):
return response['result']
def _register_proxy_user(self, company, proxy_type, edi_mode, edi_identification):
def _register_proxy_user(self, company, proxy_type, edi_mode):
''' Generate the public_key/private_key that will be used to encrypt the file, send a request to the proxy
to register the user with the public key and create the user with the private key.
:param company: the company of the user.
:param edi_identification: The unique ID that identifies this user on this edi network and to which the files will be addressed.
Typically the vat.
'''
# public_exponent=65537 is a default value that should be used most of the time, as per the documentation of cryptography.
# key_size=2048 is considered a reasonable default key size, as per the documentation of cryptography.
@@ -188,6 +175,7 @@ class AccountEdiProxyClientUser(models.Model):
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
edi_identification = self._get_proxy_identification(company, proxy_type)
if edi_mode == 'demo':
# simulate registration
response = {'id_client': f'demo{company.id}', 'refresh_token': 'demo'}
@@ -14,9 +14,7 @@ class AccountEdiProxyClientUser(models.Model):
_inherit = 'account_edi_proxy_client.user'
peppol_verification_code = fields.Char(string='SMS verification code')
proxy_type = fields.Selection(
selection_add=[('peppol', 'PEPPOL')],
)
proxy_type = fields.Selection(selection_add=[('peppol', 'PEPPOL')], ondelete={'peppol': 'cascade'})
# -------------------------------------------------------------------------
# HELPER METHODS
@@ -65,26 +63,18 @@ class AccountEdiProxyClientUser(models.Model):
return super()._get_server_url(proxy_type, edi_mode)
def _get_proxy_identification(self, company):
if not company.peppol_eas or not company.peppol_endpoint:
raise UserError(_("Please fill in the EAS code and the Participant ID code."))
return f'{company.peppol_eas}:{company.peppol_endpoint}'
# -------------------------------------------------------------------------
# COMPUTE METHODS
# -------------------------------------------------------------------------
def _compute_proxy_type(self):
# Extends account_edi_proxy_client
super()._compute_proxy_type()
for user in self:
if user.company_id.is_account_peppol_participant:
user.proxy_type = 'peppol'
# -------------------------------------------------------------------------
# BUSINESS ACTIONS
# -------------------------------------------------------------------------
def _get_proxy_identification(self, company, proxy_type):
if proxy_type == 'peppol':
if not company.peppol_eas or not company.peppol_endpoint:
raise UserError(
_("Please fill in the EAS code and the Participant ID code."))
return f'{company.peppol_eas}:{company.peppol_endpoint}'
return super()._get_proxy_identification(company, proxy_type)
def _cron_peppol_get_new_documents(self):
# Retrieve all new Peppol documents for every edi user in the database
edi_users = self.env['account_edi_proxy_client.user'].search(
@@ -118,9 +118,7 @@ class ResConfigSettings(models.TransientModel):
company = self.company_id
edi_proxy_client = self.env['account_edi_proxy_client.user']
edi_identification = edi_proxy_client._get_proxy_identification(company)
edi_user = edi_proxy_client.sudo()._register_proxy_user(
company, 'peppol', 'prod', edi_identification)
edi_user = edi_proxy_client.sudo()._register_proxy_user(company, 'peppol', 'prod')
self.account_peppol_proxy_state = 'not_verified'
# if there is an error when activating the participant below,
@@ -33,7 +33,7 @@ class TestPeppolMessage(TestAccountMoveSendCommon):
'account_peppol_proxy_state': 'active',
})
edi_identification = cls.env['account_edi_proxy_client.user']._get_proxy_identification(cls.env.company)
edi_identification = cls.env['account_edi_proxy_client.user']._get_proxy_identification(cls.env.company, 'peppol')
cls.proxy_user = cls.env['account_edi_proxy_client.user'].create({
'id_client': ID_CLIENT,
'proxy_type': 'peppol',
@@ -1,19 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
from odoo import _, fields, models
class AccountEdiProxyClientUser(models.Model):
_inherit = 'account_edi_proxy_client.user'
proxy_type = fields.Selection(
selection_add=[('l10n_it_edi', 'Italian EDI')],
)
proxy_type = fields.Selection(selection_add=[('l10n_it_edi', 'Italian EDI')], ondelete={'l10n_it_edi': 'cascade'})
def _get_proxy_urls(self):
urls = super()._get_proxy_urls()
urls['l10n_it_edi'] = {
'demo': False,
'prod': 'https://l10n-it-edi.api.odoo.com',
'test': 'https://iap-services-test.odoo.com',
}
@@ -25,3 +24,10 @@ class AccountEdiProxyClientUser(models.Model):
for user in self:
if user.company_id.country_code == 'IT':
user.proxy_type = 'l10n_it_edi'
def _get_proxy_identification(self, company, proxy_type):
if proxy_type == 'l10n_it_edi':
if not company.l10n_it_codice_fiscale:
raise UserError(_('Please fill your codice fiscale to be able to receive invoices from FatturaPA'))
return self.env['res.partner']._l10n_it_edi_normalized_codice_fiscale(company.l10n_it_codice_fiscale)
return super()._get_proxy_identification(company, proxy_type)
@@ -19,9 +19,7 @@ class ResConfigSettings(models.TransientModel):
readonly=False)
def _create_proxy_user(self, company_id, edi_mode):
fattura_pa = self.env.ref('l10n_it_edi.edi_fatturaPA')
edi_identification = fattura_pa._get_proxy_identification(company_id)
self.env['account_edi_proxy_client.user']._register_proxy_user(company_id, 'l10n_it_edi', edi_mode, edi_identification)
self.env['account_edi_proxy_client.user']._register_proxy_user(company_id, 'l10n_it_edi', edi_mode)
@api.depends('company_id.account_edi_proxy_client_ids', 'company_id.account_edi_proxy_client_ids.active')
def _compute_l10n_it_edi_sdicoop_demo_mode(self):
+1
View File
@@ -85,6 +85,7 @@ class TestItEdi(AccountEdiTestCommon):
# We create this because we are unable to post without a proxy user existing
cls.proxy_user = cls.env['account_edi_proxy_client.user'].create({
'proxy_type': 'l10n_it_edi',
'id_client': 'l10n_it_edi_test',
'company_id': cls.company.id,
'edi_identification': 'l10n_it_edi_test',