diff --git a/src/optional/python-bindings/Makefile.am b/src/optional/python-bindings/Makefile.am index fc12148323..fa10399885 100644 --- a/src/optional/python-bindings/Makefile.am +++ b/src/optional/python-bindings/Makefile.am @@ -86,6 +86,8 @@ endif 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 \ diff --git a/src/optional/python-bindings/example_scripts/Invoice.tex b/src/optional/python-bindings/example_scripts/Invoice.tex new file mode 100644 index 0000000000..1c0701f22a --- /dev/null +++ b/src/optional/python-bindings/example_scripts/Invoice.tex @@ -0,0 +1,154 @@ +%--------------------------------------------------------------------------- +% Invoice.tex v0.1 by Christoph Holtermann (c.holtermann@gmx.de) +% +% modified from +% scrlttr2.tex v0.3. (c) by Juergen Fenn +% 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} +%--------------------------------------------------------------------------- diff --git a/src/optional/python-bindings/example_scripts/latex_invoices.py b/src/optional/python-bindings/example_scripts/latex_invoices.py new file mode 100644 index 0000000000..d8713eb449 --- /dev/null +++ b/src/optional/python-bindings/example_scripts/latex_invoices.py @@ -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 \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@fmi.uni-passau.de) and Ulrich Sibiller (uli42@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()) +