153 lines
6.4 KiB
Python
Executable File
153 lines
6.4 KiB
Python
Executable File
#! /usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
# © 2017 Alexis de Lattre <alexis.delattre@akretion.com>
|
|
|
|
from optparse import OptionParser
|
|
import sys
|
|
from facturx import generate_facturx_from_file
|
|
from facturx.facturx import logger
|
|
import logging
|
|
from os.path import isfile, isdir
|
|
|
|
__author__ = "Alexis de Lattre <alexis.delattre@akretion.com>"
|
|
__date__ = "May 2018"
|
|
__version__ = "0.4"
|
|
|
|
options = [
|
|
{'names': ('-l', '--log-level'), 'dest': 'log_level',
|
|
'action': 'store', 'default': 'info',
|
|
'help': "Set log level. Possible values: debug, info, warn, error. "
|
|
"Default value: info."},
|
|
{'names': ('-d', '--disable-xsd-check'), 'dest': 'disable_xsd_check',
|
|
'action': 'store_true', 'default': False,
|
|
'help': "De-activate XML Schema Definition check on Factur-X XML file "
|
|
"(the check is enabled by default)"},
|
|
{'names': ('-n', '--facturx-level'), 'dest': 'facturx_level',
|
|
'action': 'store', 'default': 'autodetect',
|
|
'help': "Specify the Factur-X level of the XML file. "
|
|
"Default: autodetect. If you specify a particular level instead of "
|
|
"using autodetection, you will win a very small amount of time "
|
|
"(less than 1 millisecond). "
|
|
"Possible values: minimum, basicwl, basic, en16931."},
|
|
{'names': ('-a', '--meta-author'), 'dest': 'meta_author',
|
|
'action': 'store', 'default': False,
|
|
'help': "Specify the author for PDF metadata. Default: use the vendor "
|
|
"name extracted from the Factur-X XML file."},
|
|
{'names': ('-k', '--meta-keywords'), 'dest': 'meta_keywords',
|
|
'action': 'store', 'default': False,
|
|
'help': "Specify the keywords for PDF metadata. "
|
|
"Default: 'Invoice, Factur-X'."},
|
|
{'names': ('-t', '--meta-title'), 'dest': 'meta_title',
|
|
'action': 'store', 'default': False,
|
|
'help': "Specify the title of PDF metadata. "
|
|
"Default: generic English title with information extracted from "
|
|
"the Factur-X XML file such as: 'Akretion: Invoice I1242'"},
|
|
{'names': ('-s', '--meta-subject'), 'dest': 'meta_subject',
|
|
'action': 'store', 'default': False,
|
|
'help': "Specify the subject of PDF metadata. "
|
|
"Default: generic English subject with information extracted from the "
|
|
"Factur-X XML file such as: "
|
|
"'Factur-X invoice I1242 dated 2017-08-17 issued by Akretion'"},
|
|
{'names': ('-w', '--overwrite'), 'dest': 'overwrite',
|
|
'action': 'store_true', 'default': False,
|
|
'help': "Overwrite Factur-X invoice file if it already exists."},
|
|
]
|
|
|
|
|
|
def main(options, arguments):
|
|
if options.log_level:
|
|
log_level = options.log_level.lower()
|
|
log_map = {
|
|
'debug': logging.DEBUG,
|
|
'info': logging.INFO,
|
|
'warn': logging.WARN,
|
|
'error': logging.ERROR,
|
|
}
|
|
if log_level in log_map:
|
|
logger.setLevel(log_map[log_level])
|
|
else:
|
|
logger.error(
|
|
'Wrong value for log level (%s). Possible values: %s',
|
|
log_level, ', '.join(log_map.keys()))
|
|
sys.exit(1)
|
|
|
|
if len(arguments) < 3:
|
|
logger.error(
|
|
'This command requires at least 3 arguments (%d used). '
|
|
'Use --help to get the details.', len(arguments))
|
|
sys.exit(1)
|
|
pdf_filename = arguments[0]
|
|
xml_filename = arguments[1]
|
|
facturx_pdf_filename = arguments[2]
|
|
additional_attachment_filenames = arguments[3:]
|
|
for filename in [pdf_filename, xml_filename] + additional_attachment_filenames:
|
|
if not isfile(filename):
|
|
logger.error('Argument %s is not a filename', filename)
|
|
sys.exit(1)
|
|
if isdir(facturx_pdf_filename):
|
|
logger.error(
|
|
'3rd argument %s is a directory name (should be a the '
|
|
'Factur-X PDF filename)', facturx_pdf_filename)
|
|
sys.exit(1)
|
|
xml_file = open(xml_filename, 'rb')
|
|
check_xsd = True
|
|
if options.disable_xsd_check:
|
|
check_xsd = False
|
|
pdf_metadata = None
|
|
if (
|
|
options.meta_author or
|
|
options.meta_keywords or
|
|
options.meta_title or
|
|
options.meta_subject):
|
|
pdf_metadata = {
|
|
'author': options.meta_author,
|
|
'keywords': options.meta_keywords,
|
|
'title': options.meta_title,
|
|
'subject': options.meta_subject,
|
|
}
|
|
if isfile(facturx_pdf_filename):
|
|
if options.overwrite:
|
|
logger.warning(
|
|
'File %s already exists. Overwriting it.',
|
|
facturx_pdf_filename)
|
|
else:
|
|
logger.error(
|
|
'File %s already exists. Exit.', facturx_pdf_filename)
|
|
sys.exit(1)
|
|
additional_attachments = {}
|
|
for additional_attachment_filename in additional_attachment_filenames:
|
|
additional_attachments[additional_attachment_filename] = '' # desc
|
|
try:
|
|
# The important line of code is below !
|
|
generate_facturx_from_file(
|
|
pdf_filename, xml_file, check_xsd=check_xsd,
|
|
facturx_level=options.facturx_level, pdf_metadata=pdf_metadata,
|
|
output_pdf_file=facturx_pdf_filename,
|
|
additional_attachments=additional_attachments)
|
|
except Exception as e:
|
|
logger.error(e)
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
usage = "Usage: facturx-pdfgen <regular_invoice.pdf> <factur-x_xml.xml> "\
|
|
"<facturx_invoice.pdf> <optional_attachment1.xyz> "\
|
|
"<optional_attach2.abc> [...]\n"\
|
|
"\nIf you use one of the --meta-* arguments, you should specify "\
|
|
"all the meta-* arguments because the default values for "\
|
|
"metadata only apply if none of the meta-* arguments are used."
|
|
epilog = "Author: %s\n\nVersion: %s" % (__author__, __version__)
|
|
description = "This script generate a Factur-X PDF invoice from a "\
|
|
"regular PDF/A invoice and a Factur-X XML file. "\
|
|
"It can also include additional embedded files in the PDF. "\
|
|
"To generate a valid PDF/A-3 invoice as requested by the "\
|
|
"Factur-X standard, you need to give a valid PDF/A "\
|
|
"regular invoice as input."
|
|
parser = OptionParser(usage=usage, epilog=epilog, description=description)
|
|
for option in options:
|
|
param = option['names']
|
|
del option['names']
|
|
parser.add_option(*param, **option)
|
|
options, arguments = parser.parse_args()
|
|
sys.argv[:] = arguments
|
|
main(options, arguments)
|