r21255 - gnucash/trunk/src/optional/python-bindings - Bug #651175 - Script to export invoices to LaTeX

Geert Janssens gjanssens at code.gnucash.org
Sun Sep 11 10:54:07 EDT 2011


Author: gjanssens
Date: 2011-09-11 10:54:07 -0400 (Sun, 11 Sep 2011)
New Revision: 21255
Trac: http://svn.gnucash.org/trac/changeset/21255

Added:
   gnucash/trunk/src/optional/python-bindings/example_scripts/Invoice.tex
   gnucash/trunk/src/optional/python-bindings/example_scripts/latex_invoices.py
Modified:
   gnucash/trunk/src/optional/python-bindings/Makefile.am
Log:
Bug #651175 - Script to export invoices to LaTeX
Patch by Christoph Holtermann

Modified: gnucash/trunk/src/optional/python-bindings/Makefile.am
===================================================================
--- gnucash/trunk/src/optional/python-bindings/Makefile.am	2011-09-11 14:32:58 UTC (rev 21254)
+++ gnucash/trunk/src/optional/python-bindings/Makefile.am	2011-09-11 14:54:07 UTC (rev 21255)
@@ -86,6 +86,8 @@
 
 EXTRA_DIST = \
   $(SWIG_FILES) \
+  example_scripts/Invoice.tex \
+  example_scripts/latex_invoices.py \
   example_scripts/simple_book.py \
   example_scripts/simple_session.py \
   example_scripts/simple_test.py \

Added: gnucash/trunk/src/optional/python-bindings/example_scripts/Invoice.tex
===================================================================
--- gnucash/trunk/src/optional/python-bindings/example_scripts/Invoice.tex	                        (rev 0)
+++ gnucash/trunk/src/optional/python-bindings/example_scripts/Invoice.tex	2011-09-11 14:54:07 UTC (rev 21255)
@@ -0,0 +1,154 @@
+%---------------------------------------------------------------------------
+% Invoice.tex v0.1 by Christoph Holtermann (c.holtermann at gmx.de)
+%
+% modified from 
+% scrlttr2.tex v0.3. (c) by Juergen Fenn <juergen.fenn at gmx.de>
+% Template for a letter to be typeset with scrlttr2.cls from KOMA-Script.
+% Latest version of the LaTeX Project Public License is applicable. 
+% File may not be modified and redistributed under the same name 
+% without the author's prior consent.
+%---------------------------------------------------------------------------
+\documentclass%%
+%---------------------------------------------------------------------------
+  [fontsize=12pt,%%          Schriftgroesse
+%---------------------------------------------------------------------------
+% Satzspiegel
+   paper=a4,%%               Papierformat
+   enlargefirstpage=off,%%    Erste Seite anders
+   pagenumber=headright,%%   Seitenzahl oben mittig
+%---------------------------------------------------------------------------
+% Layout
+   headsepline=on,%%         Linie unter der Seitenzahl
+   parskip=half,%%           Abstand zwischen Absaetzen
+%---------------------------------------------------------------------------
+% Briefkopf und Anschrift
+   fromalign=right,%%        Platzierung des Briefkopfs
+   fromphone=on,%%           Telefonnummer im Absender
+   fromrule=off,%%           Linie im Absender (aftername, afteraddress)
+   fromfax=on,%%            Faxnummer
+   fromemail=on,%%           Emailadresse
+   fromurl=off,%%            Homepage
+   fromlogo=off,%%           Firmenlogo
+   addrfield=on,%%           Adressfeld fuer Fensterkuverts
+   backaddress=on,%%          ...und Absender im Fenster
+   subject=beforeopening,%%  Plazierung der Betreffzeile
+   locfield=narrow,%%        zusaetzliches Feld fuer Absender
+   foldmarks=on,%%           Faltmarken setzen
+   numericaldate=off,%%      Datum numerisch ausgeben
+   refline=narrow,%%         Geschaeftszeile im Satzspiegel
+%---------------------------------------------------------------------------
+% Formatierung
+   draft=off,%%              Entwurfsmodus
+   version=last,
+   data%%	     	     data.lco ist die Datei aus der die Rechnungsdaten gelesen werden ( invoice-data to be read from data.lco )
+]{scrlttr2}
+%---------------------------------------------------------------------------
+\usepackage[ngerman]{babel}
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage{url}
+\usepackage{eurosym}
+\usepackage{rechnung}
+\usepackage{textcomp}
+%---------------------------------------------------------------------------
+% Fonts
+\setkomafont{fromname}{\sffamily \LARGE}
+\setkomafont{fromaddress}{\sffamily}%% statt \small
+\setkomafont{pagenumber}{\sffamily}
+\setkomafont{subject}{\mdseries}
+\setkomafont{backaddress}{\mdseries}
+\usepackage{mathptmx}%% Schrift Times
+%\usepackage{mathpazo}%% Schrift Palatino
+%\setkomafont{fromname}{\LARGE}
+%---------------------------------------------------------------------------
+\begin{document}
+%---------------------------------------------------------------------------
+% Briefstil und Position des Briefkopfs
+\LoadLetterOption{DIN} %% oder: DINmtext, SN, SNleft, KOMAold.
+\makeatletter
+\@setplength{firstheadvpos}{20mm}
+\@setplength{firstheadwidth}{\paperwidth}
+\ifdim \useplength{toaddrhpos}>\z@
+  \@addtoplength[-2]{firstheadwidth}{\useplength{toaddrhpos}}
+\else
+  \@addtoplength[2]{firstheadwidth}{\useplength{toaddrhpos}}
+\fi
+\@setplength{foldmarkhpos}{6.5mm}
+%\setlength{\footskip}{1cm}
+\makeatother
+%---------------------------------------------------------------------------
+% Absender
+\setkomavar{fromname}{fromname}
+\setkomavar{fromaddress}{fromaddress}
+\setkomavar{fromphone}{fromphone}
+\renewcommand{\phonename}{Telefon}
+\setkomavar{fromfax}{fromfax}
+\setkomavar{fromemail}{fromemail}
+\setkomavar{backaddressseparator}{. }
+\setkomavar{signature}{(signature)}
+\setkomavar{frombank}{---NAME --- BANK ACCOUNT --- BANK NUMBER --- BANK NAME ---}
+\setkomavar{location}{\\[8ex]\raggedleft{\footnotesize{\usekomavar{fromaddress}\\
+	Telefon: \usekomavar{fromphone}\\Mobil: mobile-number\\Fax: \usekomavar{fromfax}\\\usekomavar{fromemail}}}}%% Neben dem Adressfenster
+%---------------------------------------------------------------------------
+\firsthead{}
+%---------------------------------------------------------------------------
+% Fußzeile
+\firstfoot{%
+	\parbox[b]{\linewidth}{%
+		\centering\def\\{, }\footnotesize\usekomavar{frombank}%
+	}%
+}%
+%---------------------------------------------------------------------------
+% Geschaeftszeilenfelder
+%\setkomavar{place}{Stadel}
+%\setkomavar{placeseparator}{, den }
+%\setkomavar{date}{\today}
+%\setkomavar{yourmail}{1. 1. 2003}%% 'Ihr Schreiben...'
+%\setkomavar{yourref} {abcdefg}%%    'Ihr Zeichen...'
+%\setkomavar{myref}{}%%      Unser Zeichen
+\setkomavar{invoice}{\usekomavar{rechnungsnummer}}%% Rechnungsnummer
+%\setkomavar{phoneseparator}{}
+
+%---------------------------------------------------------------------------
+% Versendungsart
+%\setkomavar{specialmail}{Einschreiben mit R�ckschein}
+%---------------------------------------------------------------------------
+% Anlage neu definieren
+\renewcommand{\enclname}{Anlage}
+\setkomavar{enclseparator}{: }
+%---------------------------------------------------------------------------
+% Seitenstil
+\pagestyle{plain}%% keine Header in der Kopfzeile
+%---------------------------------------------------------------------------
+% Rechnungsoptionen
+\Euro
+%---------------------------------------------------------------------------
+\begin{letter}{\usekomavar{toaddress2}}
+%---------------------------------------------------------------------------
+% Weitere Optionen
+\KOMAoptions{%%
+}
+%---------------------------------------------------------------------------
+%\setkomavar{subject}{Rechnungsnummer \usekomavar{rechnungsnummer}}
+%---------------------------------------------------------------------------
+\opening{Sehr geehrte Damen und Herren,}
+
+Ich erlaube mir, Ihnen folgende Beträge in Rechnung zu stellen:
+
+\begin{Rechnung}[N] %oder [N]
+\Steuersatz{0}{0}
+\usekomavar{entries}
+\end{Rechnung}
+
+Bitte zahlen Sie den Betrag von \Gesamtsumme \, bis zum \usekomavar{date_due} auf mein unten angegebenes Konto.
+
+\closing{Mit bestem Dank und freundlichen Grüßen,}
+%---------------------------------------------------------------------------
+%\ps{PS:}
+%\encl{}
+%\cc{}
+%---------------------------------------------------------------------------
+\end{letter}
+%---------------------------------------------------------------------------
+\end{document}
+%---------------------------------------------------------------------------

Added: gnucash/trunk/src/optional/python-bindings/example_scripts/latex_invoices.py
===================================================================
--- gnucash/trunk/src/optional/python-bindings/example_scripts/latex_invoices.py	                        (rev 0)
+++ gnucash/trunk/src/optional/python-bindings/example_scripts/latex_invoices.py	2011-09-11 14:54:07 UTC (rev 21255)
@@ -0,0 +1,305 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+##@file
+# @ingroup python_bindings_examples
+# @author Christoph Holtermann (c.holtermann (at) gmx.de)
+# @date May 2011
+# @brief Exports an invoice to lco-file for use with LaTeX
+#
+# The output file can be imported into KOMA-Script-letters.
+# This works primarily for germany. Internationalization welcome!
+#
+# Additional files:
+#
+# - Invoice.tex\n
+# Example template file. Should be modified according to personal needs.
+# - rechnung.sty\n
+# style file for invoices.\n
+# This file is not part of the python-bindings!\n
+# For an example where to get it see section credits below.
+#
+# Usage :
+# \code latex_invoice file://testfile \endcode
+# will create file data.lco.
+# \code latex --output-format=pdf Invoice.tex \endcode
+# should run latex on file Invoice.tex and result in Invoice.pdf. Invoice.tex includes data.lco.
+#
+# Additional information :
+#
+# - http://www.uweziegenhagen.de/latex/documents/rechnung/rechnungen.pdf (german)
+# 
+# Credits to and ideas from
+#
+# - Main function as proposed by Guido van Rossum
+#   at http://www.artima.com/weblogs/viewpost.jsp?thread=4829
+# - Invoice.tex is derived from\n
+#   scrlttr2.tex v0.3. (c) by Juergen Fenn <juergen.fenn at gmx.de>\n
+#   http://www.komascript.de/node/355\n
+#   english translation: ftp://ftp.dante.de/tex-archive/info/templates/fenn/scrlttr2en.tex
+# - rechnung.sty\n
+#   from M G Berberich (berberic at fmi.uni-passau.de) and Ulrich Sibiller (uli42 at web.de)
+#   Ver3.10 from http://www.forwiss.uni-passau.de/~berberic/TeX/Rechnung/index.html
+#
+# To Do:
+#
+# - get own contact data from gnucash
+# - have own bank information in footline
+# - nicer formatting of invoice date and date due
+# - is there anything else missing in this invoice ?
+
+try:
+    import sys
+    import getopt
+    import gnucash
+    import str_methods
+    from IPython.Shell import IPShellEmbed
+    from gnucash.gnucash_business import Customer, Employee, Vendor, Job, \
+        Address, Invoice, Entry, TaxTable, TaxTableEntry, GNC_AMT_TYPE_PERCENT, \
+            GNC_DISC_PRETAX
+    import locale
+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 get_all_lots(account):
+  """Return all lots in account and descendants"""
+  ltotal=[]
+  descs = account.get_descendants()
+  for desc in descs:
+    if type(desc).__name__ == 'SwigPyObject':
+        desc = gnucash.Account(instance=desc)
+    ll=desc.GetLotList()
+    ltotal+=ll
+  return ltotal
+
+def get_all_invoices_from_lots(account):
+  """Return all invoices in account and descendants
+
+  This is based on lots. So invoices without lots will be missed."""
+
+  lot_list=get_all_lots(account)
+  invoice_list=[]
+  for lot in lot_list:
+    if type(lot).__name__ == 'SwigPyObject':
+        lot = gnucash.GncLot(instance=lot)
+    invoice=gnucash.gnucash_core_c.gncInvoiceGetInvoiceFromLot(lot.instance)
+    if invoice:
+      invoice_list.append(Invoice(instance=invoice))
+  return invoice_list
+
+def invoice_to_lco(invoice):
+  """returns a string which forms a lco-file for use with LaTeX"""
+
+  lco_out=u"\ProvidesFile{data.lco}[]\n"
+  
+  def write_variable(ukey, uvalue, replace_linebreak=True):
+
+    outstr = u""
+    if uvalue.endswith("\n"):
+        uvalue=uvalue[0:len(uvalue)-1]
+
+    if not ukey in [u"fromaddress",u"toaddress",u"date"]:
+        outstr += u'\\newkomavar{'
+        outstr += ukey
+        outstr += u"}\n"
+
+    outstr += u"\\setkomavar{"
+    outstr += ukey
+    outstr += u"}{"
+    if replace_linebreak:
+        outstr += uvalue.replace(u"\n",u"\\\\")+"}"
+    return outstr
+
+  # Write owners address
+  add_str=u""
+  owner = invoice.GetOwner()
+  if owner.GetName() != "":
+    add_str += owner.GetName()+"\n"
+
+  addr  = owner.GetAddr()
+  if addr.GetName() != "":
+    add_str += addr.GetName().decode("UTF-8")+"\n"
+  if addr.GetAddr1() != "":
+    add_str += addr.GetAddr1().decode("UTF-8")+"\n"
+  if addr.GetAddr2() != "":
+    add_str += addr.GetAddr2().decode("UTF-8")+"\n"
+  if addr.GetAddr3() != "":
+    add_str += addr.GetAddr3().decode("UTF-8")+"\n"
+  if addr.GetAddr4() != "":
+    add_str += addr.GetAddr4().decode("UTF-8")+"\n"
+
+  lco_out += write_variable("toaddress2",add_str)
+
+  # Invoice number
+  inr_str = invoice.GetID()
+  lco_out += write_variable("rechnungsnummer",inr_str)
+
+  # date
+  date      = invoice.GetDatePosted()
+  udate     = date.strftime("%d.%m.%Y")
+  lco_out  += write_variable("date",udate)+"\n"
+
+  # date due
+  date_due  = invoice.GetDateDue()
+  udate_due = date_due.strftime("%d.%m.%Y")
+  lco_out  += write_variable("date_due",udate_due)+"\n"
+
+
+  # Write the entries
+  ent_str = u""
+  locale.setlocale(locale.LC_ALL,"de_DE")
+  for n,ent in enumerate(invoice.GetEntries()): 
+      
+      line_str = u""
+
+      if type(ent) != Entry:
+        ent=Entry(instance=ent)                                 # Add to method_returns_list
+      
+      descr = ent.GetDescription()
+      price = gnucash.GncNumeric(instance=ent.GetInvPrice()).to_double()
+      n     = gnucash.GncNumeric(instance=ent.GetQuantity())    # change gncucash_core.py
+     
+      uprice = locale.currency(price).rstrip(" EUR") 
+      un = unicode(int(float(n.num())/n.denom()))               # choose best way to format numbers according to locale
+
+      line_str =  u"\Artikel{"
+      line_str += un
+      line_str += u"}{"
+      line_str += descr.decode("UTF-8")
+      line_str += u"}{"
+      line_str += uprice
+      line_str += u"}"
+
+      #print line_str
+      ent_str += line_str
+
+  lco_out += write_variable("entries",ent_str)
+
+  return lco_out
+
+
+def main(argv=None):
+    if argv is None:
+        argv = sys.argv
+    try:
+        prog_name = argv[0]
+        with_ipshell = False
+        ignore_lock = False
+        no_latex_output = False
+        list_invoices = False
+        output_file_name = "data.lco"
+
+        try:
+            opts, args = getopt.getopt(argv[1:], "fhiln:po:", ["help"])
+        except getopt.error, 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"]:
+                print "Using ipshell"
+                with_ipshell = True
+            if opt[0] in ["-l"]:
+                print "listing all invoices"
+                list_invoices=True
+            if opt[0] in ["-n"]:
+                invoice_number = int(opt[1])
+                print "using invoice number", invoice_number
+            if opt[0] in ["-o"]:
+                output_file_name = opt[1]
+                print "using outpu file", output_file_name
+            if opt[0] in ["-p"]:
+                print "no latex output"
+                no_latex_output=True
+        if len(args)>1:
+            print "opts:",opts,"args:",args
+            raise Usage("Only one input can be accepted !")
+        if len(args)==0:
+            raise Usage("No input given !")
+        input_url = args[0]
+    except Usage, err:
+        if err.msg == "Help:":
+            retcode=0
+        else:
+            print >>sys.stderr, "Error:",err.msg
+            print >>sys.stderr, "for help use --help"
+            retcode=2
+        
+        print "Prints out all invoices that have corresponding lots."
+        print
+        print "Usage:"
+        print
+        print "Invoke with",prog_name,"input."
+        print "where input is"
+        print "   filename"
+        print "or file://filename" 
+        print "or mysql://user:password@host/databasename" 
+        print
+        print "-f             force open = ignore lock"
+        print "-h or --help   for this help"
+        print "-i             for ipython shell"
+        print "-l             list all invoices"
+        print "-n number      use invoice number (no. from previous run -l)"
+        print "-o name        use name as outputfile. default: data.lco"
+        print "-p             pretend (=no) latex output"
+        
+        return retcode
+
+    # Try to open the given input
+    try:
+        session = gnucash.Session(input_url,ignore_lock=ignore_lock)
+    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_from_lots(root_account)
+
+    if list_invoices:
+        for number,invoice in enumerate(invoice_list):
+            print str(number)+")"
+            print invoice
+
+    if not (no_latex_output):
+
+        if invoice_number == None:
+            print "Using the first invoice:"
+            invoice_number=0
+        
+        invoice=invoice_list[invoice_number]
+        print "Using the following invoice:"
+        print invoice
+    
+        lco_str=invoice_to_lco(invoice)
+
+        # Opening output file
+        f=open(output_file_name,"w")
+        lco_str=lco_str.encode("latin1")
+        f.write(lco_str)
+        f.close()
+
+    if with_ipshell:
+        ipshell= IPShellEmbed()
+        ipshell() 
+
+    #session.save()
+    session.end()
+
+if __name__ == "__main__":
+    sys.exit(main())
+



More information about the gnucash-changes mailing list