266 lines
9.3 KiB
Python
Executable file
266 lines
9.3 KiB
Python
Executable file
#! /usr/bin/python3
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
"""Fill a pdf form.
|
|
|
|
Input are:
|
|
the pdf
|
|
the config file for this pdf
|
|
the data (= config-file) for other pdfs that have useful information
|
|
user input
|
|
|
|
Outputs are:
|
|
a filled pdf
|
|
the config file including the created data for use in other forms.
|
|
|
|
TODOs are:
|
|
fix in Beginn Dienstgeschäft Datum
|
|
es gibt Fälle ohne Erstattung -> Dann z.B. Teil 15. leer lassen
|
|
|
|
|
|
bei choice: zusätzlich Zahlen als Eingabeoption
|
|
-> Ja ist immer 1, nein immer 2
|
|
|
|
statt "nicht möglich" Optionen nicht anzeigen
|
|
|
|
bei Backspace: vorige Frage nochmal
|
|
Option für alles nochmal fragen
|
|
|
|
Reiseziel -> Leerzeichen entfernen in output file names
|
|
|
|
Antrag:
|
|
18: Abschlag bisher nichts eintragen
|
|
|
|
Texte verkürzen (z.B. bei Meilengutschrifte) -> nach Möglichkeit
|
|
max. 50 Zeichen (besser 45) pro Zeile
|
|
|
|
erste Abrechnung im Juni
|
|
|
|
readline benutzen
|
|
|
|
(im Antrag) überall Zukunft statt Vergangenheit, da es ja ein Antrag ist
|
|
|
|
"""
|
|
|
|
import os.path
|
|
import argparse
|
|
import itertools
|
|
from subprocess import CalledProcessError as ExternalError
|
|
import commands
|
|
import formfield
|
|
import readformdata
|
|
from constants import (NON_FORMFIELD, CONFIGFIELD, OUTPUTFIELD,
|
|
FORMOUTPUTFIELD, SUBINFO_SEP, ConfigError,
|
|
GENERALADVICE, EPILOG)
|
|
import writetopdf
|
|
|
|
|
|
def parse():
|
|
"""Create the argument parser (including the help) and parse the arguments.
|
|
|
|
Options/ Arguments:
|
|
pdffile
|
|
config
|
|
other data ("data")
|
|
outputpdf
|
|
fdf tmp file ("fdf")
|
|
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
description="Fill out a pdf.",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog=EPILOG)
|
|
parser.add_argument("pdffile",
|
|
help="The pdf file with the form.")
|
|
parser.add_argument("--outputpdf", default=None, # nargs=1,
|
|
# None = file.pdf -> file-filled.pdf
|
|
# todo: more sophisticated with name of person/ date
|
|
help="The output file with the filled form. " +
|
|
"(Default: pdffile[without .pdf]-filled.pdf or" +
|
|
" as configured in the config file.)")
|
|
parser.add_argument("--config", default=None, # nargs=1,
|
|
# None = file.pdf -> file.form
|
|
help="The config file used to know how to fill the " +
|
|
"pdf. (Default: pdffile[without .pdf].form")
|
|
parser.add_argument("--form", default=None, # nargs=1,
|
|
# None = file.pdf -> file-filled.form
|
|
help="The file where all the inputed data is saved" +
|
|
" to. (Default: pdffile[without .pdf]-filled.form" +
|
|
" or as configured in the config file.)" +
|
|
"\nThis can be used in other forms and to finish" +
|
|
" the input later.")
|
|
parser.add_argument("--data", default=None, nargs=2, action='append',
|
|
metavar=("REF", "DATAFILE"),
|
|
help="Data from other forms can be supplied via" +
|
|
" this option. " +
|
|
"REF is the reference used in the config" +
|
|
" file, the DATAFILE is the .form-file.")
|
|
parser.add_argument("--fdf", default="tmp.fdf", # nargs=1,
|
|
help="To fill the pdf a temporary fdf is created. " +
|
|
"Specify with FDF the file name for this. " +
|
|
"(Default: tmp.fdf).")
|
|
args = vars(parser.parse_args())
|
|
if not os.path.isfile(args["pdffile"]):
|
|
parser.print_help()
|
|
raise argparse.ArgumentTypeError(args["pdffile"] +
|
|
" is not a valid file.")
|
|
if args["config"] is None:
|
|
args["config"] = os.path.splitext(args["pdffile"])[0] + ".form"
|
|
if not os.path.isfile(args["config"]):
|
|
parser.print_help()
|
|
raise argparse.ArgumentTypeError(args["config"] +
|
|
" is not a valid file.")
|
|
# if args["form"] is None:
|
|
# args["form"] = os.path.splitext(args["pdffile"])[0] + "-filled.form"
|
|
# if args["outputpdf"] is None:
|
|
# args["outputpdf"] =
|
|
# os.path.splitext(args["pdffile"])[0] + "-filled.pdf"
|
|
for arg in [args["outputpdf"], args["form"]]:
|
|
if arg is not None and os.path.isfile(arg):
|
|
try:
|
|
input(arg + " is an existing file. For aborting " +
|
|
"hit Ctrl+C. For overwriting hit Enter.")
|
|
except KeyboardInterrupt:
|
|
parser.print_help()
|
|
raise argparse.ArgumentTypeError(arg + " is already an " +
|
|
"existing file.")
|
|
if args["data"] is None:
|
|
args["data"] = []
|
|
for datafile in args["data"]:
|
|
if not os.path.isfile(datafile[1]):
|
|
parser.print_help()
|
|
raise argparse.ArgumentTypeError(datafile[1] +
|
|
" is not a valid file.")
|
|
return args
|
|
|
|
|
|
def readDataPaths(configs):
|
|
"""Read which data files should be read.
|
|
|
|
Configs is a list of FormFields.
|
|
In the configs there can be a field with the FieldName "Mainconfig".
|
|
This can specify with the info Data and the data specifier-Path.
|
|
|
|
Returns:
|
|
a dict with {dataspecifier: path}, to be merged with parsing result.
|
|
|
|
"""
|
|
try:
|
|
mainconfig = formfield.FormField.findByFieldName(
|
|
configs,
|
|
CONFIGFIELD,
|
|
include=lambda f: NON_FORMFIELD in f)
|
|
except KeyError:
|
|
# nothing found, OK
|
|
return {}
|
|
else:
|
|
try:
|
|
specs = mainconfig["Data"] # specifier
|
|
except KeyError:
|
|
# nothing found, OK
|
|
return {}
|
|
else:
|
|
try:
|
|
return {spec: mainconfig[
|
|
spec + SUBINFO_SEP +
|
|
"Path"] for spec in specs}
|
|
except KeyError as e:
|
|
raise readformdata.ConfigError(
|
|
"A data file was specified but a path is missing: " +
|
|
str(e))
|
|
|
|
|
|
def getConfigvalue(fieldname, fields, argument, default):
|
|
"""Get the name of a config.
|
|
|
|
If specified on the commandline (argument is not None)
|
|
take this.
|
|
If a NON-field with the FieldName fieldname exists in fields,
|
|
take the value of this field.
|
|
If such a field does not exist or it has no value, take default.
|
|
|
|
"""
|
|
if argument is not None:
|
|
return argument
|
|
try:
|
|
field = formfield.FormField.findByFieldName(
|
|
fields, fieldname, include=lambda f: NON_FORMFIELD in f)
|
|
except KeyError:
|
|
return default
|
|
else:
|
|
try:
|
|
return field["Value"]
|
|
except KeyError:
|
|
return default
|
|
|
|
|
|
def getOutput(fields, args):
|
|
"""Generate the name of the output pdf.
|
|
|
|
If specified on the commandline (arguments["Output"] is not None, take
|
|
this.)
|
|
If a field with the name Outputconfig exists, take its value.
|
|
Otherwise generate outputfilename out of input file.
|
|
|
|
"""
|
|
default = os.path.splitext(args["pdffile"])[0] + "-filled.pdf"
|
|
return getConfigvalue(OUTPUTFIELD, fields, args["outputpdf"], default)
|
|
|
|
|
|
def getFormoutput(fields, args):
|
|
"""Generate the name of the output form file.
|
|
|
|
If specified on the commandline (arguments["form"] is not None, take
|
|
this.)
|
|
If a field with the name Formoutputconfig exists, take its value.
|
|
Otherwise generate output form filename out of input file.
|
|
|
|
"""
|
|
default = os.path.splitext(args["pdffile"])[0] + "-filled.form"
|
|
return getConfigvalue(FORMOUTPUTFIELD, fields, args["form"], default)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
arguments = parse()
|
|
except argparse.ArgumentTypeError as e:
|
|
print("Error while parsing the command line arguments:\n", e)
|
|
else:
|
|
config = readformdata.listFields([], arguments["config"])
|
|
# make dict out of [[]] list + dict from config file
|
|
data = readDataPaths(config)
|
|
for f in arguments["data"]:
|
|
data[f[0]] = f[1]
|
|
try:
|
|
data = {f: readformdata.listFields([], data[f])
|
|
for f in data}
|
|
except FileNotFoundError as e:
|
|
raise ConfigError("A data file specified in the config file or " +
|
|
"on the command line does not exist: " + str(e))
|
|
|
|
# f[0] is REF, f[1] is the file
|
|
|
|
comms = itertools.chain(*[commands.Command.extractCommands(
|
|
field, config, data) for field in config])
|
|
# comms = commands.Command.extractCommands(config[0], config, data)
|
|
# print(comms)
|
|
print(GENERALADVICE)
|
|
for command in sorted(comms):
|
|
try:
|
|
command()
|
|
except KeyboardInterrupt:
|
|
break
|
|
else:
|
|
# print(config[0])
|
|
pass
|
|
# in else: fillpdf since we do not need a pdf that is not done yet
|
|
# for testing always create
|
|
try:
|
|
writetopdf.fillpdf(config, arguments["pdffile"],
|
|
getOutput(config, arguments),
|
|
arguments["fdf"])
|
|
except ExternalError as e:
|
|
print(e)
|
|
if e.output is not None:
|
|
print(e.output)
|
|
readformdata.writeFields(config, getFormoutput(config, arguments))
|