[IMP] account_edi_ubl_cii: always generate Factur-X silently

Always generate a Factur-X xml and embed it when a PDF is created. But no edi.document
is created, no warnings will be displayed on the invoice, and the PDF is not PDF/A-3.
The only purpose here is the Odoo interoperability.

Rename the 'Factur-X' option to 'Factur-X PDF/A-3' and make it only visible for FR and DE companies.

This 'Factur-X PDF/A-3' option will trigger the regular account.edi flow: create an edi.document
and show warnings on the move if errors are detected. When a PDF is printed, embed the Factur-X xml
and make the PDF a PDF/A-3. Thus, it can be used on Chorus Pro.

task-2957808

closes odoo/odoo#102311

X-original-commit: 25d4635d544a0a48ac937b35c996f2cbdb8073ec
Related: odoo/enterprise#32344
Related: odoo/documentation#2789
Signed-off-by: Laurent Smet <las@odoo.com>
Signed-off-by: Julien Van Roy <juvr@odoo.com>
This commit is contained in:
Julien Van Roy
2022-10-06 10:42:56 +02:00
parent 40ac191644
commit fdb0079e90
4 changed files with 60 additions and 19 deletions
+3 -3
View File
@@ -18,9 +18,9 @@ Note that E-FFF, NLCIUS and XRechnung (UBL) are only available for Belgian, Dutc
respectively. UBL Bis 3 is only available for companies which country is present in the `EAS list
<https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/>`_.
Note also that you need to activate PDF A in order to be able to submit a Factur-X pdf on Chorus Pro:
go to Settings > Technical (debug mode) > System Parameters > select/create one with Key: edi.use_pdfa, Value: true.
With this setting, Chorus Pro will automatically detect the "PDF/A-3 (Factur-X)" format.
Note also that in order for Chorus Pro to automatically detect the "PDF/A-3 (Factur-X)" format, you need to activate
the "Factur-X PDF/A-3" option on the journal. This option will also validate the xml against the Factur-X and Chorus
Pro rules and show the errors.
""",
'depends': ['account_edi'],
'data': [
@@ -1,17 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="edi_facturx_1_0_05" model="account.edi.format">
<field name="name">Factur-X (FR)</field>
<field name="name">Factur-X (PDF/A-3)</field>
<field name="code">facturx_1_0_05</field>
</record>
<data noupdate="1">
<record model="ir.config_parameter" id="ir_config_parameter_use_pdfa">
<field name="key">edi.use_pdfa</field>
<field name="value">false</field>
</record>
</data>
<record id="edi_nlcius_1" model="account.edi.format">
<field name="name">NLCIUS (Netherlands)</field>
<field name="code">nlcius_1</field>
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, _
from odoo.tools import str2bool
from odoo.addons.account_edi_ubl_cii.models.account_edi_common import COUNTRY_EAS
import logging
@@ -48,7 +47,9 @@ class AccountEdiFormat(models.Model):
def _get_xml_builder(self, company):
# see https://communaute.chorus-pro.gouv.fr/wp-content/uploads/2017/08/20170630_Solution-portail_Dossier_Specifications_Fournisseurs_Chorus_Facture_V.1.pdf
# page 45 -> ubl 2.1 for France seems also supported
if self.code == 'facturx_1_0_05':
# Only show the Factur-X option for DE and FR companies. When generating the PDF, add a Factur-X xml if there
# isn't an existing one. So there's always a Factur-X in the PDF, even without the option.
if self.code == 'facturx_1_0_05' and company.country_id.code in ['DE', 'FR']:
return self.env['account.edi.xml.cii']
# if the company's country is not in the EAS mapping, nothing is generated
# 'NO' has to be present in COUNTRY_EAS
@@ -84,11 +85,10 @@ class AccountEdiFormat(models.Model):
def _is_enabled_by_default_on_journal(self, journal):
# EXTENDS account_edi
# only facturx is enabled by default, the other formats aren't
self.ensure_one()
if self.code not in FORMAT_CODES:
return super()._is_enabled_by_default_on_journal(journal)
return self.code == 'facturx_1_0_05'
return False
def _ubl_cii_post_invoice(self, invoice):
# EXTENDS account_edi
@@ -96,7 +96,7 @@ class AccountEdiFormat(models.Model):
builder = self._get_xml_builder(invoice.company_id)
# For now, the errors are not displayed anywhere, don't want to annoy the user
xml_content, _ = builder._export_invoice(invoice)
xml_content, errors = builder._export_invoice(invoice)
# DEBUG: send directly to the test platform (the one used by ecosio)
#response = self.env['account.edi.common']._check_xml_ecosio(invoice, xml_content, builder._export_invoice_ecosio_schematrons())
@@ -112,7 +112,19 @@ class AccountEdiFormat(models.Model):
attachment_create_vals.update({'res_id': invoice.id, 'res_model': 'account.move'})
attachment = self.env['ir.attachment'].create(attachment_create_vals)
return {invoice: {'success': True, 'attachment': attachment}}
res = {invoice: {'attachment': attachment}}
if errors and self.code == 'facturx_1_0_05':
res[invoice].update({
'success': False,
'error': _("Errors occured while creating the EDI document (format: %s). The receiver "
"might refuse it.", builder._description)
+ '<p> <li>' + "</li> <li>".join(errors) + '</li> </p>',
'blocking_level': 'info',
})
else:
res[invoice]['success'] = True
return res
def _get_move_applicability(self, move):
# EXTENDS account_edi
@@ -140,8 +152,7 @@ class AccountEdiFormat(models.Model):
return
pdf_writer.embed_odoo_attachment(edi_document.attachment_id, subtype='text/xml')
if not pdf_writer.is_pdfa and str2bool(
self.env['ir.config_parameter'].sudo().get_param('edi.use_pdfa', 'False')):
if not pdf_writer.is_pdfa:
try:
pdf_writer.convert_to_pdfa()
except Exception as e:
@@ -3,10 +3,12 @@
from odoo import models
from odoo.tools import cleanup_xml_node
from odoo.tools.pdf import OdooPdfFileReader, OdooPdfFileWriter
from lxml import etree
import base64
from xml.sax.saxutils import escape, quoteattr
import io
class IrActionsReport(models.Model):
@@ -62,4 +64,39 @@ class IrActionsReport(models.Model):
invoice = self.env['account.move'].browse(res_id)
self._add_pdf_into_invoice_xml(invoice, stream_data)
# If Factur-X isn't already generated, generate and embed it inside the PDF
if len(res_ids) == 1:
invoice = self.env['account.move'].browse(res_ids)
edi_doc_codes = invoice.edi_document_ids.edi_format_id.mapped('code')
# If Factur-X hasn't been generated, generate and embed it anyway
if invoice.is_sale_document() \
and invoice.state == 'posted' \
and 'facturx_1_0_05' not in edi_doc_codes \
and self.env.ref('account_edi_ubl_cii.edi_facturx_1_0_05', raise_if_not_found=False):
# Add the attachments to the pdf file
pdf_stream = collected_streams[invoice.id]['stream']
# Read pdf content.
pdf_content = pdf_stream.getvalue()
reader_buffer = io.BytesIO(pdf_content)
reader = OdooPdfFileReader(reader_buffer, strict=False)
# Post-process and embed the additional files.
writer = OdooPdfFileWriter()
writer.cloneReaderDocumentRoot(reader)
# Generate and embed Factur-X
xml_content, _errors = self.env['account.edi.xml.cii']._export_invoice(invoice)
writer.addAttachment(
name=self.env['account.edi.xml.cii']._export_invoice_filename(invoice),
data=xml_content,
subtype='text/xml',
)
# Replace the current content.
pdf_stream.close()
new_pdf_stream = io.BytesIO()
writer.write(new_pdf_stream)
collected_streams[invoice.id]['stream'] = new_pdf_stream
return collected_streams