[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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user