gnucash/bindings/python/example_scripts/gncinvoice_jinja.py
c-holtermann 0434acbe10 reformat two python example scripts with black
use black python code formatter on latex_invoices.py and gncinvoice_jinja.py
2020-06-21 16:23:32 +02:00

239 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
##@file
# @brief exports an invoice from gnucash using a template file, see \ref py_invoice_export
# @ingroup python_bindings_examples
# @author Christoph Holtermann (c.holtermann (at) gmx.de)
# @date 2014-2018
#
# @details
# Input is a template file that will be filled with information from
# gnucash Invoices. Jinja2 templating engine is being used for this.
# Templates can be Latex, Html or anything.
#
# Example templates for german invoices:
# - Invoice.tex.tmpl
# - Invoice_2.tex.tmpl
#
# This is a sequel to latex_invoices.py that exported to a lco file
# to be imported into a LaTeX letter.
# The approach used here is not as dependent on external files and
# more modular as it allows to use arbitrary templates
#
# Doxygen docs:
# - https://code.gnucash.org/docs/MAINT or MASTER
# - see page \ref py_invoice_export
#
# Questions / Issues:
# - How much logic in the template, how much preprocessing in this file ?
# - Internationalization - currencies, formatting of numbers
# - Providing data of gnucash owner
try:
import locale
import os
import sys
import getopt
import gnucash
import str_methods
import jinja2
from gncinvoicefkt import *
from gnucash import SessionOpenMode
except ImportError as import_error:
print("Problem importing modules.")
print(import_error)
sys.exit(2)
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
if argv is None:
argv = sys.argv
try:
# default values
prog_name = argv[0]
ignore_lock = True
filename_template = None
filename_output = None
no_output = False
list_invoices = False
invoice_number = None
invoice_id = None
filename_from_invoice = False
output_path = None
with_ipshell = False
try:
opts, args = getopt.getopt(argv[1:], "fhliI:t:o:OP:", ["help"])
except getopt.error as msg:
raise Usage(msg)
for opt in opts:
if opt[0] in ["-f"]:
print("ignoring lock")
ignore_lock = True
if opt[0] in ["-h", "--help"]:
raise Usage("Help:")
if opt[0] in ["-I"]:
invoice_id = opt[1]
print("using invoice ID '" + str(invoice_id) + "'.")
if opt[0] in ["-i"]:
print("Using ipshell")
with_ipshell = True
if opt[0] in ["-o"]:
filename_output = opt[1]
print("using output file", filename_output)
if opt[0] in ["-O"]:
if filename_output:
print("given output filename will be overwritten,")
print("creating output filename from Invoice data.")
filename_from_invoice = True
if opt[0] in ["-t"]:
filename_template = opt[1]
print("using template file", filename_template)
if opt[0] in ["-l"]:
list_invoices = True
print("listing invoices")
if opt[0] in ["-P"]:
output_path = opt[1]
print("output path is", output_path + ".")
# Check for correct input
if len(args) > 1:
print("opts:", opts, "args:", args)
raise Usage("Only one input possible !")
if len(args) == 0:
raise Usage("No input given !")
input_url = args[0]
# Check for correct template
if not filename_template:
no_output = True
if not list_invoices:
raise Usage("No template given !")
# Check for output file
if not (filename_output or filename_from_invoice):
if filename_template:
filename_output = filename_template + ".out"
print("no output filename given, will be:", filename_output)
except Usage as err:
if err.msg == "Help:":
retcode = 0
else:
print("Error:", err.msg, file=sys.stderr)
print("for help use --help", file=sys.stderr)
retcode = 2
print()
print("Usage:")
print()
print("Invoke with", prog_name, "gnucash_url.")
print("where input is")
print(" filename")
print("or file://filename")
print("or mysql://user:password@host/databasename")
print()
print("-f force open = ignore lock (read only)")
print("-l list all invoices")
print("-h or --help for this help")
print("-I ID use invoice ID")
print("-t filename use filename as template file")
print("-o filename use filename as output file")
print("-O create output filename by date, owner and invoice number")
print("-P path path for output file. Overwrites path in -o option")
return retcode
# Try to open the given input
try:
print(
"Opening", input_url, " (ignore-lock = read-only)." if ignore_lock else "."
)
session = gnucash.Session(
input_url,
SessionOpenMode.SESSION_READ_ONLY
if ignore_lock
else SessionOpenMode.SESSION_NORMAL_OPEN,
)
except Exception as exception:
print("Problem opening input.")
print(exception)
return 2
book = session.book
root_account = book.get_root_account()
comm_table = book.get_table()
EUR = comm_table.lookup("CURRENCY", "EUR")
invoice_list = get_all_invoices(book)
if list_invoices:
for number, invoice in enumerate(invoice_list):
print(str(number) + ")")
print(invoice)
if not (no_output):
if invoice_id:
invoice = book.InvoiceLookupByID(invoice_id)
if not invoice:
print("ID not found.")
return 2
if invoice_number:
invoice = invoice_list[invoice_number]
print("Using the following invoice:")
print(invoice)
path_template = os.path.dirname(filename_template)
filename_template_basename = os.path.basename(filename_template)
loader = jinja2.FileSystemLoader(path_template)
env = jinja2.Environment(loader=loader)
template = env.get_template(filename_template_basename)
# company = gnucash_business.Company(book.instance)
output = template.render(invoice=invoice, locale=locale) # , company=company)
if filename_from_invoice:
filename_date = invoice.GetDatePosted().strftime(
"%Y-%m-%d"
) # something like 2014-11-01
filename_owner_name = str(invoice.GetOwner().GetName())
filename_invoice_id = str(invoice.GetID())
filename_output = (
filename_date
+ "_"
+ filename_owner_name
+ "_"
+ filename_invoice_id
+ ".tex"
)
if output_path:
filename_output = os.path.join(
output_path, os.path.basename(filename_output)
)
print("Writing output", filename_output, ".")
with open(filename_output, "w") as f:
f.write(output)
if with_ipshell:
import IPython
IPython.embed()
if __name__ == "__main__":
sys.exit(main())