diff --git a/eo_gestion/eo_facture/facturx.py b/eo_gestion/eo_facture/facturx.py index 7ebc796..768220d 100644 --- a/eo_gestion/eo_facture/facturx.py +++ b/eo_gestion/eo_facture/facturx.py @@ -18,6 +18,7 @@ import logging import os import subprocess import tempfile +import typing import facturx from django.template.loader import render_to_string @@ -60,7 +61,19 @@ def to_pdfa(pdf_bytes: bytes, icc_profile: str = DEFAULT_ICC_PROFILE): DEFAULT_FACTURX_TEMPLATE = 'factur-x.xml' -def add_facturx_from_bytes(pdf_bytes: bytes, facturx_context: dict, template: str = DEFAULT_FACTURX_TEMPLATE): +def add_facturx_from_bytes( + pdf_bytes: bytes, + facturx_context: dict, + template: str = DEFAULT_FACTURX_TEMPLATE, + attachments: typing.Sequence[tuple[str, bytes]] = (), +): pdfa_bytes = to_pdfa(pdf_bytes) + attachments_dict = {filename: {'filedata': content} for filename, content in attachments} facturx_xml = str(render_to_string(template, facturx_context)).encode('utf-8') - return facturx.generate_facturx_from_binary(pdfa_bytes, facturx_xml) + with tempfile.NamedTemporaryFile(prefix='invoice-facturx-', suffix='.pdf') as f: + f.write(pdfa_bytes) + facturx.generate_facturx_from_file(f, facturx_xml, attachments=attachments_dict) + f.seek(0) + result = f.read() + f.close() + return result diff --git a/tests/test_facturx.py b/tests/test_facturx.py index c8986df..8c9eb6a 100644 --- a/tests/test_facturx.py +++ b/tests/test_facturx.py @@ -19,6 +19,7 @@ import io import xml.etree.ElementTree as ET import facturx +import pypdf import pytest from eo_gestion.eo_facture.facturx import add_facturx_from_bytes, to_pdfa @@ -212,3 +213,39 @@ def test_add_facturx_from_bytes_facture_avoir(fake_invoice_bytes): ], ], ] + + +# https://stackoverflow.com/questions/2438800/what-is-the-smallest-legal-zip-jar-file +MINIMAL_ZIP_FILE = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + + +def test_add_facturx_from_bytes_with_attachments(fake_invoice_bytes): + facturx_ctx = { + 'numero_de_facture': 'F20190001', + 'type_facture': '380', + 'date_emission': datetime.date(2019, 1, 1), + 'chorus_service_code': 'service-code', + 'vendeur': 'Entr\'ouvert', + 'vendeur_siret': '44317013900036', + 'vendeur_tvai': 'FR09491081899', + 'client_siret': '1234', + 'client_name': 'RGFIPD', + 'numero_engagement': '5678', + 'numero_marche': 'ABCD', + 'montant_ht': '10', + 'montant_ttc': '12', + 'montant_tva': '2', + 'taux_tva': 20.0, + } + attachments = [ + ('PJ1.zip', MINIMAL_ZIP_FILE), + ('PJ2.zip', MINIMAL_ZIP_FILE), + ] + + facturx_bytes = add_facturx_from_bytes(fake_invoice_bytes, facturx_ctx, attachments=attachments) + + pdf_reader = pypdf.PdfReader(io.BytesIO(facturx_bytes)) + assert [(k, v) for k, v in pdf_reader.attachments.items() if k != 'factur-x.xml'] == [ + ('PJ1.zip', [MINIMAL_ZIP_FILE]), + ('PJ2.zip', [MINIMAL_ZIP_FILE]), + ] diff --git a/tox.ini b/tox.ini index 59225db..c942a3d 100644 --- a/tox.ini +++ b/tox.ini @@ -20,6 +20,7 @@ setenv = deps = -rtest-requirements.txt factur-x==1.8 + pypdf commands = py.test {env:COVERAGE:} {env:JUNIT:} {posargs}