diff --git a/addons/account/models/ir_attachment.py b/addons/account/models/ir_attachment.py index ada846fc58b..f8d30912af9 100644 --- a/addons/account/models/ir_attachment.py +++ b/addons/account/models/ir_attachment.py @@ -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, }, diff --git a/addons/account_edi_proxy_client/models/account_edi_proxy_user.py b/addons/account_edi_proxy_client/models/account_edi_proxy_user.py index 9697594d791..3b97d444b8c 100644 --- a/addons/account_edi_proxy_client/models/account_edi_proxy_user.py +++ b/addons/account_edi_proxy_client/models/account_edi_proxy_user.py @@ -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'} diff --git a/addons/account_peppol/models/account_edi_proxy_user.py b/addons/account_peppol/models/account_edi_proxy_user.py index 1809bc7acb3..5fd40b15763 100644 --- a/addons/account_peppol/models/account_edi_proxy_user.py +++ b/addons/account_peppol/models/account_edi_proxy_user.py @@ -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( diff --git a/addons/account_peppol/models/res_config_settings.py b/addons/account_peppol/models/res_config_settings.py index e700fdd123e..f47e7a68f56 100644 --- a/addons/account_peppol/models/res_config_settings.py +++ b/addons/account_peppol/models/res_config_settings.py @@ -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, diff --git a/addons/account_peppol/tests/test_peppol_messages.py b/addons/account_peppol/tests/test_peppol_messages.py index 9b802a20fa6..cc11ebf2948 100644 --- a/addons/account_peppol/tests/test_peppol_messages.py +++ b/addons/account_peppol/tests/test_peppol_messages.py @@ -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', diff --git a/addons/l10n_it_edi/models/account_edi_proxy_user.py b/addons/l10n_it_edi/models/account_edi_proxy_user.py index cbea365aee1..dbeef9059a7 100644 --- a/addons/l10n_it_edi/models/account_edi_proxy_user.py +++ b/addons/l10n_it_edi/models/account_edi_proxy_user.py @@ -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) diff --git a/addons/l10n_it_edi/models/res_config_settings.py b/addons/l10n_it_edi/models/res_config_settings.py index 19dd7ee83fd..a1eb418b590 100644 --- a/addons/l10n_it_edi/models/res_config_settings.py +++ b/addons/l10n_it_edi/models/res_config_settings.py @@ -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): diff --git a/addons/l10n_it_edi/tests/common.py b/addons/l10n_it_edi/tests/common.py index b64ab4f191a..707bde0fe60 100644 --- a/addons/l10n_it_edi/tests/common.py +++ b/addons/l10n_it_edi/tests/common.py @@ -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',