barbacompta/eo_gestion/eo_facture/facturx.py

88 lines
3.3 KiB
Python

# barbacompta - invoicing for dummies
# Copyright (C) 2010-2012 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import os
import subprocess
import tempfile
import facturx
from django.template.loader import render_to_string
logger = logging.getLogger(__name__)
GS_INCLUDE_DIR = os.path.join(os.path.dirname(__file__), 'gs-includes')
DEFAULT_ICC_PROFILE = os.path.join(GS_INCLUDE_DIR, 'compatibleWithAdobeRGB1998.icc')
def to_pdfa(pdf_bytes: bytes, icc_profile: str = DEFAULT_ICC_PROFILE):
with tempfile.NamedTemporaryFile() as output_fd, tempfile.NamedTemporaryFile() as input_fd:
input_fd.write(pdf_bytes)
input_fd.flush()
args = [
'gs',
'-dPDFA',
'-dBATCH',
'-dNOPAUSE',
'-sICCProfile=' + icc_profile,
'-sProcessColorModel=DeviceCMYK',
'-sDEVICE=pdfwrite',
'-dPDFACompatibilityPolicy=2',
# ghostscript needs percent character in output filename to be quoted
'-sOutputFile=' + output_fd.name.replace('%', '%%'),
# give right to GS of reading local PDF_def.ps and ICC profile
'-I' + GS_INCLUDE_DIR,
'PDFA_def.ps',
input_fd.name,
]
logger.debug('converting to PDF/A, calling %s', args)
completed = subprocess.run(args, capture_output=True, text=True, check=False)
logger.debug('ghostscript result %s', completed)
if completed.returncode != 0:
logger.error('ghostcript call failed %s', completed)
completed.check_returncode()
return output_fd.read()
def add_facturx_from_facture(facture):
pdf_bytes = facture.pdf()
facturx_context = {
'numero_de_facture': facture.code(),
'type_facture': '380',
'date_emission': facture.emission,
'chorus_service_code': facture.client.chorus_structure.service_code,
'vendeur': 'Entr\'ouvert',
'vendeur_siret': '44317013900036',
'vendeur_tvai': 'FR09491081899',
'client_siret': facture.client.chorus_structure.siret,
'client_name': facture.client.chorus_structure.name,
'numero_engagement': '',
'montant_ht': str(facture.montant),
'montant_ttc': str(facture.montant_ttc),
'montant_tva': str(facture.tva),
}
return add_facturx_from_bytes(pdf_bytes, facturx_context)
DEFAULT_FACTURX_TEMPLATE = 'factur-x.xml'
def add_facturx_from_bytes(pdf_bytes: bytes, facturx_context: dict, template: str = DEFAULT_FACTURX_TEMPLATE):
pdfa_bytes = to_pdfa(pdf_bytes)
facturx_xml = str(render_to_string(template, facturx_context)).encode('utf-8')
return facturx.generate_facturx_from_binary(pdfa_bytes, facturx_xml)