mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-25 10:20:18 -06:00
756 lines
26 KiB
Python
756 lines
26 KiB
Python
|
#**********************************************************************
|
||
|
# Gnu Cash to OpenOffice.org (gnuc2ooo.py)
|
||
|
#
|
||
|
# Makros for the download of GnuCash Data to OpenOffice.org Base
|
||
|
#
|
||
|
# Makro SetGnuCashFilePaths:
|
||
|
# Set or change the filepaths of the (GnuCash) data source
|
||
|
# and of the new OpenOffice.org database that will be created
|
||
|
# in this makro though still empty
|
||
|
#
|
||
|
# Makro fillGnuCashDB:
|
||
|
# Download data from the GnuCash data source to OpenOffice.org
|
||
|
# Base
|
||
|
#
|
||
|
#
|
||
|
#**********************************************************************
|
||
|
# Copyright (c) 2008 Knut Gerwens
|
||
|
# gnuc2ooo@alice-dsl.net
|
||
|
#
|
||
|
# This library is free software; you can redistribute it and/or
|
||
|
# modify it under the terms of the GNU Lesser General Public
|
||
|
# License as published by the Free Software Foundation; either
|
||
|
# version 2.1 of the License, or (at your option) any later version.
|
||
|
#
|
||
|
# This library is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
# Lesser General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU Lesser General Public
|
||
|
# License along with this library; if not, write to the Free Software
|
||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
#
|
||
|
# See: http://www.gnu.org/licenses/lgpl.html
|
||
|
#
|
||
|
#**********************************************************************
|
||
|
# Acknowledgements: Special thanks go to the authors on OpenOffice.org
|
||
|
# makro programming Roberto Benitez(http://www.baseprogramming.com) and
|
||
|
# Andrew Pitonyak (http://www.pitonyak.org)
|
||
|
#**********************************************************************
|
||
|
# Changes
|
||
|
# Knut Gerwens, 2008-09-16:
|
||
|
# Bugfix: locale.getlocale() -> locale.getdefaultlocale()
|
||
|
# Extension: field description in table TRN from 256 to 512 Bytes
|
||
|
#
|
||
|
# Knut Gerwens, 2008-09-20:
|
||
|
# try/unconditional except for read input, so Windows XP-Users can use
|
||
|
# the program with unzipped GnuCashFiles (no valid gzip module).
|
||
|
# try/except for sort on hierarchy (accounttree), because python 2.3.4
|
||
|
# does not support keyword argument in sort.
|
||
|
# Infobox/Success-message at end of FillGnuCashDB
|
||
|
#
|
||
|
# Knut Gerwens, 2008-09-29:
|
||
|
# Improved Errorhandling. Errors are intercepted, Some Error and
|
||
|
# Trace-Information is written to logfile GnuCashFilePaths.txt
|
||
|
#
|
||
|
# Knut Gerwens, 2008-10-02:
|
||
|
# Checkpoint-Statement at the end added, so tables are actually stored
|
||
|
# in database and not only as logfile
|
||
|
#
|
||
|
# Knut Gerwens, 2008-10-04:
|
||
|
# Improved memory-mangement. Writing to disc is enforced every 1000 rows
|
||
|
#
|
||
|
|
||
|
import uno, unohelper
|
||
|
import gzip
|
||
|
import xml.sax as sax
|
||
|
import os.path, locale
|
||
|
import time
|
||
|
|
||
|
# ********************** OPENOFFICE.ORG-API *******************************
|
||
|
# Component Context und Service Manager
|
||
|
ctx = uno.getComponentContext()
|
||
|
smgr = ctx.ServiceManager
|
||
|
# create database context
|
||
|
Context = smgr.createInstanceWithContext(
|
||
|
"com.sun.star.sdb.DatabaseContext", ctx)
|
||
|
# Star Desktop
|
||
|
Desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
|
||
|
# user directory
|
||
|
PathSettings = smgr.createInstanceWithContext(
|
||
|
"com.sun.star.util.PathSettings", ctx)
|
||
|
|
||
|
|
||
|
# ************************** PROLOG ***************************************
|
||
|
from com.sun.star.ui.dialogs.TemplateDescription import FILEOPEN_SIMPLE, FILESAVE_AUTOEXTENSION
|
||
|
lcodec = locale.getdefaultlocale()[1]
|
||
|
set_makro = "SetGnuCashFilePaths"
|
||
|
settings_textentrance = "#This file was generated by OpenOfficeMakro: "
|
||
|
settings_textinp = "GnuCashDatafile: "
|
||
|
settings_textoutp = "Registered Database in Openoffice.org: "
|
||
|
# Trace / Error - Information
|
||
|
global crout
|
||
|
crout = 'main'
|
||
|
last_input_getDBFilename = 'not available'
|
||
|
last_input_createDB = 'not available'
|
||
|
last_input_createdelete = 'not available'
|
||
|
last_input_eval_fraction = 'not available'
|
||
|
last_input_view_all_transactions = 'not available'
|
||
|
last_input___init__ = 'not available'
|
||
|
last_input_startElement = 'not available'
|
||
|
last_input_endElement = 'not available'
|
||
|
last_input_insert_statement = 'not available'
|
||
|
last_input_characters = 'not available'
|
||
|
last_input_MessageBox = 'not available'
|
||
|
insert_ct = 0
|
||
|
maxmemory = 1000
|
||
|
|
||
|
def settings_filepath():
|
||
|
userdir_url = PathSettings.UserConfig
|
||
|
userdir = unohelper.fileUrlToSystemPath(userdir_url)
|
||
|
userfile = os.path.join(userdir, 'GnuCashFilePaths.txt')
|
||
|
return userfile
|
||
|
|
||
|
def getGCFilename():
|
||
|
global crout
|
||
|
crout = 'getGCFilename'
|
||
|
fp_read.Title = "Pick Output Data File of GnuCash Program"
|
||
|
fp_read.initialize((FILEOPEN_SIMPLE,))
|
||
|
fp_read.MultiSelectionMode = False
|
||
|
if fp_read.execute():
|
||
|
return fp_read.Files[0]
|
||
|
|
||
|
def getDBFilename(default):
|
||
|
global crout
|
||
|
crout = 'getDBFilename'
|
||
|
global last_input_getDBFilename
|
||
|
## last_input_getDBFilename = str(default) + '\n'
|
||
|
|
||
|
fp_write.Title = "Enter Database Filename"
|
||
|
fp_write.MultiSelectionMode = False
|
||
|
try:
|
||
|
fp_write.appendFilter("Base Files (*.odb)", "*.odb")
|
||
|
except:
|
||
|
fp_write.setCurrentFilter("Base Files (*.odb)")
|
||
|
fp_write.initialize((FILESAVE_AUTOEXTENSION,))
|
||
|
fp_write.setDefaultName(default)
|
||
|
if fp_write.execute():
|
||
|
return fp_write.Files[0]
|
||
|
|
||
|
def createDB(db_defaultname):
|
||
|
global crout
|
||
|
crout = 'createDB'
|
||
|
global last_input_createDB
|
||
|
## last_input_createDB = str(db_defaultname)
|
||
|
|
||
|
fileurl=getDBFilename(db_defaultname)
|
||
|
if fileurl:
|
||
|
DB = Context.createInstance()
|
||
|
DB.URL = "sdbc:embedded:hsqldb"
|
||
|
DB.DatabaseDocument.storeAsURL(fileurl, ())
|
||
|
filepath = unohelper.fileUrlToSystemPath(fileurl)
|
||
|
filename = os.path.basename(filepath)
|
||
|
datasource = Context.getByName(fileurl)
|
||
|
dbname = filename[:-4]
|
||
|
Context.registerObject(dbname, datasource)
|
||
|
return dbname
|
||
|
else:
|
||
|
return None
|
||
|
|
||
|
def exec_SetGnuCashFilePaths():
|
||
|
""" Definition of data source and target files, creation of empty database """
|
||
|
|
||
|
global fp_read, fp_write
|
||
|
global crout
|
||
|
crout = 'SetGnuCashFilePaths'
|
||
|
# uno service for filepickers
|
||
|
# There was a bug under ubuntu 8.04 when I took the normal,
|
||
|
# i.e. Gnom FilePicker, so I had to take the Office File Picker
|
||
|
fp_read = smgr.createInstanceWithContext(
|
||
|
"com.sun.star.ui.dialogs.OfficeFilePicker", ctx)
|
||
|
fp_write = smgr.createInstanceWithContext(
|
||
|
"com.sun.star.ui.dialogs.OfficeFilePicker", ctx)
|
||
|
|
||
|
GCFileURL = getGCFilename()
|
||
|
if GCFileURL:
|
||
|
GCFile = unohelper.fileUrlToSystemPath(GCFileURL)
|
||
|
else:
|
||
|
return None
|
||
|
settings = open(settings_filepath(), 'w')
|
||
|
entrance_line = settings_textentrance + set_makro + '\n'
|
||
|
settings.write(entrance_line)
|
||
|
settings.write(settings_textinp)
|
||
|
settings.write(GCFile.encode(lcodec) + '\n')
|
||
|
|
||
|
gcfilename = os.path.basename(GCFile)
|
||
|
dbname = createDB(gcfilename)
|
||
|
if dbname:
|
||
|
settings.write(settings_textoutp)
|
||
|
settings.write(dbname.encode(lcodec) + '\n')
|
||
|
else:
|
||
|
return None
|
||
|
|
||
|
settings.close()
|
||
|
|
||
|
MessageBox('A new Openoffice.org database has been created.\n' +
|
||
|
'To fill with data please run makro "fillGnuCashDB."',
|
||
|
MsgType="infobox")
|
||
|
|
||
|
def read_filepaths():
|
||
|
global crout
|
||
|
crout = 'read_filepaths'
|
||
|
try:
|
||
|
settings = open(settings_filepath(), 'r')
|
||
|
except IOError:
|
||
|
return []
|
||
|
gcfile = ""
|
||
|
dbname = ""
|
||
|
for line in settings:
|
||
|
lineparts = line.split(": ")
|
||
|
if lineparts[0] == settings_textinp[:-2]:
|
||
|
gcfile = lineparts[1].rstrip().decode(lcodec)
|
||
|
elif lineparts[0] == settings_textoutp[:-2]:
|
||
|
dbname = lineparts[1].rstrip().decode(lcodec)
|
||
|
else:
|
||
|
pass
|
||
|
|
||
|
settings.close()
|
||
|
if gcfile == "" or dbname == "":
|
||
|
return []
|
||
|
else:
|
||
|
return [gcfile, dbname]
|
||
|
|
||
|
# *********************** TABLES ooo-DB **********************************
|
||
|
|
||
|
# Three definitions for account: must be kept in sync
|
||
|
create_account = """CREATE TABLE ACCOUNT (
|
||
|
NAME VARCHAR(256),
|
||
|
ID VARCHAR(256),
|
||
|
TYPE VARCHAR(256),
|
||
|
DESCRIPTION VARCHAR(256),
|
||
|
PARENT VARCHAR(256))
|
||
|
"""
|
||
|
insert_account = """INSERT INTO ACCOUNT(
|
||
|
NAME, ID, TYPE, DESCRIPTION, PARENT)
|
||
|
VALUES (?, ?, ?, ?, ?)"""
|
||
|
## """
|
||
|
def init_account():
|
||
|
global crout
|
||
|
crout = 'init_account'
|
||
|
account0 = {}.fromkeys(['name', 'id', 'type', 'description', 'parent'], '')
|
||
|
return account0
|
||
|
|
||
|
|
||
|
# Definitions transaction: must be kept in sync
|
||
|
# As many reports will evaluate on a monthly base I prefer to store
|
||
|
# date:year/month and date/day into separate columns
|
||
|
create_trn = """ CREATE TABLE TRN (
|
||
|
ID VARCHAR(256) NOT NULL,
|
||
|
NUM VARCHAR(256),
|
||
|
DESCRIPTION VARCHAR(512),
|
||
|
DATE_YM CHAR(7),
|
||
|
DATE_D CHAR(2)
|
||
|
)
|
||
|
"""
|
||
|
insert_trn = """INSERT INTO TRN(
|
||
|
ID, NUM, DESCRIPTION, DATE_YM, DATE_D)
|
||
|
VALUES (?, ?, ?, ?, ?)"""
|
||
|
def init_trn():
|
||
|
global crout
|
||
|
crout = 'init_trn'
|
||
|
trn0 = {}.fromkeys(['id', 'num', 'description', 'date_ym', 'date_d'], '')
|
||
|
return trn0
|
||
|
|
||
|
# Definitions for splits
|
||
|
create_split = """ CREATE TABLE SPLIT (
|
||
|
ID VARCHAR(256) NOT NULL,
|
||
|
TRN_ID VARCHAR(256),
|
||
|
VALUE DOUBLE,
|
||
|
QUANTITY DOUBLE,
|
||
|
ACCOUNT VARCHAR(256)
|
||
|
)
|
||
|
"""
|
||
|
insert_split = """INSERT INTO SPLIT(
|
||
|
ID, TRN_ID, VALUE, QUANTITY, ACCOUNT)
|
||
|
VALUES (?, ?, ?, ?, ?)"""
|
||
|
def init_split():
|
||
|
global crout
|
||
|
crout = 'init_split'
|
||
|
split0 = {}.fromkeys(['id', 'trn_id', 'value', 'quantity', 'account'], '')
|
||
|
return split0
|
||
|
|
||
|
# Definitions for acct_tree, will be completed before execution
|
||
|
create_accttree0 = """CREATE TABLE ACCTTREE (ID VARCHAR(256) NOT NULL"""
|
||
|
insert_accttree0 = """INSERT INTO ACCTTREE VALUES (?"""
|
||
|
|
||
|
|
||
|
def createdelete(create_statement, table_name):
|
||
|
global crout
|
||
|
crout = 'createdelete'
|
||
|
global last_input_createdelete
|
||
|
## last_input_createdelete = str(create_statement) + ' ' + str(table_name)
|
||
|
|
||
|
try:
|
||
|
Stmt.execute(create_statement)
|
||
|
except:
|
||
|
if table_name:
|
||
|
Stmt.execute("DELETE FROM " + table_name)
|
||
|
|
||
|
def eval_fraction(cont):
|
||
|
global crout
|
||
|
crout = 'eval_fraction'
|
||
|
global last_input_eval_fraction
|
||
|
## last_input_eval_fraction = str(cont)
|
||
|
|
||
|
l_split = cont.split('/')
|
||
|
numerator = cont.split('/')[0]
|
||
|
denominator = cont.split('/')[1]
|
||
|
if denominator.isdigit() and float(denominator) != 0:
|
||
|
floatnumber = float(numerator) / float(denominator)
|
||
|
else:
|
||
|
floatnumber = 0
|
||
|
return floatnumber
|
||
|
|
||
|
def accounttree():
|
||
|
global crout
|
||
|
crout = 'accounttree'
|
||
|
accrowlist = []
|
||
|
accrowdict = {}
|
||
|
accrowsresult = Stmt.executeQuery("SELECT ID, PARENT, NAME, TYPE FROM ACCOUNT")
|
||
|
while accrowsresult.next():
|
||
|
acc = []
|
||
|
for i in range(accrowsresult.Columns.Count):
|
||
|
acc.append(accrowsresult.getString(i + 1))
|
||
|
accrowlist.append(acc)
|
||
|
for acc in accrowlist:
|
||
|
accrowdict.update({acc[0]: acc[1:]})
|
||
|
hierarchy = []
|
||
|
maxlvl = 0
|
||
|
for acc in accrowdict:
|
||
|
namelist = []
|
||
|
clist = accrowdict[acc]
|
||
|
while clist[0]:
|
||
|
namelist.append(clist[1])
|
||
|
clist = accrowdict[clist[0]]
|
||
|
namelist.reverse()
|
||
|
maxlvl = max(maxlvl, len(namelist))
|
||
|
namelist.insert(0, acc)
|
||
|
hierarchy.append(namelist)
|
||
|
try:
|
||
|
hierarchy.sort(key=lambda l: l[1:])
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
filler = []
|
||
|
create_accttree = create_accttree0
|
||
|
insert_accttree = insert_accttree0
|
||
|
for i in range(maxlvl):
|
||
|
create_accttree += ", " + "LEVEL" + str(i + 1) + " VARCHAR(256)"
|
||
|
insert_accttree += ", ?"
|
||
|
filler.append(' ')
|
||
|
create_accttree += ')'
|
||
|
insert_accttree += ')'
|
||
|
createdelete(create_accttree, "ACCTTREE")
|
||
|
Stmt_ins_accttree = Connection.prepareStatement(insert_accttree)
|
||
|
for namelist in hierarchy:
|
||
|
i = len(namelist)
|
||
|
t_namelist = tuple(namelist + filler[i-1:])
|
||
|
ct = 0
|
||
|
for col in t_namelist:
|
||
|
ct = ct + 1
|
||
|
Stmt_ins_accttree.setString(ct, col)
|
||
|
Stmt_ins_accttree.executeUpdate()
|
||
|
createdelete("CREATE INDEX ACCTTREE_ID ON ACCTTREE (ID)", None)
|
||
|
return maxlvl
|
||
|
|
||
|
def view_all_transactions(ct_lvl):
|
||
|
global crout
|
||
|
crout = 'view_all_transactions'
|
||
|
global last_input_view_all_transactions
|
||
|
## last_input_view_all_transactions = str(ct_lvl)
|
||
|
|
||
|
def vardefs(ct_lvl = ct_lvl):
|
||
|
global crout
|
||
|
crout = 'vardefs'
|
||
|
v2 = """"ACCTTREE"."LEVEL?" AS "LEVEL?",
|
||
|
"""
|
||
|
v4 = """ "LEVEL?","""
|
||
|
vd2 = ""
|
||
|
vd4 = ""
|
||
|
for i in range(ct_lvl):
|
||
|
sl = str(i + 1)
|
||
|
vd2 = vd2 + v2.replace("?", sl)
|
||
|
vd4 = vd4 + v4.replace("?", sl)
|
||
|
vtup = (vd2, vd4)
|
||
|
return vtup
|
||
|
|
||
|
## viewdef =
|
||
|
## "ACCTTREE"."LEVEL1" AS "LEVEL1",
|
||
|
## "ACCTTREE"."LEVEL2" AS "LEVEL2",
|
||
|
## "ACCTTREE"."LEVEL3" AS "LEVEL3",
|
||
|
## "ACCTTREE"."LEVEL4" AS "LEVEL4",
|
||
|
## "LEVEL1", "LEVEL2", "LEVEL3", "LEVEL4",
|
||
|
##
|
||
|
viewdef1 = """CREATE VIEW ALL_TRANSACTIONS AS
|
||
|
SELECT "ACCOUNT"."TYPE" AS "ACCOUNT-TYPE",
|
||
|
"""
|
||
|
viewdef3 = """ "ACCOUNT"."NAME" AS "ACCOUNT-NAME",
|
||
|
"TRN"."DATE_YM" AS "DATE_YM", "TRN".
|
||
|
"DATE_D" AS "DATE_D",
|
||
|
"TRN"."NUM" AS "TRN-NUMBER",
|
||
|
"TRN"."DESCRIPTION" AS "DESCRIPTION",
|
||
|
CAST ( "SPLIT"."VALUE" AS "DECIMAL" ) AS "VALUE"
|
||
|
FROM "SPLIT", "TRN", "ACCOUNT", "ACCTTREE"
|
||
|
WHERE "TRN"."ID" = "SPLIT"."TRN_ID"
|
||
|
AND "ACCOUNT"."ID" = "SPLIT"."ACCOUNT"
|
||
|
AND "ACCTTREE"."ID" = "SPLIT"."ACCOUNT"
|
||
|
AND "SPLIT"."VALUE" != '0'
|
||
|
ORDER BY"""
|
||
|
viewdef5 = """ "DATE_YM", "DATE_D",
|
||
|
"TRN-NUMBER", "DESCRIPTION" """
|
||
|
|
||
|
vtup = vardefs()
|
||
|
viewdef2 = vtup[0]
|
||
|
viewdef4 = vtup[1]
|
||
|
|
||
|
viewdef = viewdef1 + viewdef2 + viewdef3 + viewdef4 + viewdef5
|
||
|
|
||
|
Stmt.execute(viewdef)
|
||
|
|
||
|
#**************************** SAX / XML ***********************************
|
||
|
|
||
|
class GCContent(sax.handler.ContentHandler):
|
||
|
|
||
|
def __init__(self):
|
||
|
global crout
|
||
|
crout = '__init__'
|
||
|
global last_input___init__
|
||
|
## last_input___init__ = str(self)
|
||
|
|
||
|
self.account = init_account()
|
||
|
self.trn = init_trn()
|
||
|
self.split = init_split()
|
||
|
self.tbl = ''
|
||
|
self.name = ''
|
||
|
self.status_date_posted = False
|
||
|
self.date_posted = ''
|
||
|
self.status_template_trns = False
|
||
|
|
||
|
def startElement(self, name, attrs):
|
||
|
global crout
|
||
|
crout = 'startElement'
|
||
|
global last_input_startElement
|
||
|
last_input_startElement = str(name.encode(lcodec))
|
||
|
|
||
|
if ':' in name:
|
||
|
self.tbl = name.split(':')[0]
|
||
|
self.key = name.split(':')[1]
|
||
|
|
||
|
|
||
|
def endElement(self, name):
|
||
|
global crout
|
||
|
crout = 'endElement'
|
||
|
global last_input_endElement
|
||
|
last_input_endElement = str(name.encode(lcodec))
|
||
|
|
||
|
def insert_statement(kind, value_dict):
|
||
|
global crout
|
||
|
global last_input_insert_statement
|
||
|
crout = 'insert_statement'
|
||
|
last_input_insert_statement = str(kind.encode(lcodec)) + ' ' + str(value_dict)
|
||
|
global insert_ct
|
||
|
insert_ct = insert_ct + 1
|
||
|
if insert_ct >= maxmemory:
|
||
|
Stmt.execute("CHECKPOINT")
|
||
|
insert_ct = insert_ct - maxmemory
|
||
|
if kind == 'account':
|
||
|
Stmt_ins_account.setString(1, value_dict['name'])
|
||
|
Stmt_ins_account.setString(2, value_dict['id'])
|
||
|
Stmt_ins_account.setString(3, value_dict['type'])
|
||
|
Stmt_ins_account.setString(4, value_dict['description'])
|
||
|
Stmt_ins_account.setString(5, value_dict['parent'])
|
||
|
Stmt_ins_account.executeUpdate()
|
||
|
elif kind == 'trn':
|
||
|
Stmt_ins_trn.setString(1, value_dict['id'])
|
||
|
Stmt_ins_trn.setString(2, value_dict['num'])
|
||
|
Stmt_ins_trn.setString(3, value_dict['description'])
|
||
|
Stmt_ins_trn.setString(4, value_dict['date_ym'])
|
||
|
Stmt_ins_trn.setString(5, value_dict['date_d'])
|
||
|
Stmt_ins_trn.executeUpdate()
|
||
|
elif kind == 'split':
|
||
|
Stmt_ins_split.setString(1, value_dict['id'])
|
||
|
Stmt_ins_split.setString(2, value_dict['trn_id'])
|
||
|
Stmt_ins_split.setDouble(3, value_dict['value'])
|
||
|
Stmt_ins_split.setDouble(4, value_dict['quantity'])
|
||
|
Stmt_ins_split.setString(5, value_dict['account'])
|
||
|
Stmt_ins_split.executeUpdate()
|
||
|
|
||
|
if name == 'gnc:account':
|
||
|
for tup in self.account.iteritems():
|
||
|
self.account[tup[0]] = tup[1].rstrip()
|
||
|
if self.status_template_trns == False:
|
||
|
insert_statement('account', self.account)
|
||
|
self.account = init_account()
|
||
|
self.tbl = ''
|
||
|
self.key = ''
|
||
|
elif name == 'trn:date-posted':
|
||
|
self.trn['date_ym'] = self.date_posted[0:7]
|
||
|
self.trn['date_d'] = self.date_posted[8:10]
|
||
|
self.status_date_posted = False
|
||
|
self.date_posted = ''
|
||
|
elif name == 'trn:split':
|
||
|
self.split['trn_id'] = self.trn['id']
|
||
|
for tup in self.split.iteritems():
|
||
|
self.split[tup[0]] = tup[1].rstrip()
|
||
|
self.split['value'] = eval_fraction(self.split['value'])
|
||
|
self.split['quantity'] = eval_fraction(self.split['quantity'])
|
||
|
if self.status_template_trns == False:
|
||
|
insert_statement('split', self.split)
|
||
|
self.split = init_split()
|
||
|
self.tbl = ''
|
||
|
self.key = ''
|
||
|
elif name == 'gnc:transaction':
|
||
|
for tup in self.trn.iteritems():
|
||
|
self.trn[tup[0]] = tup[1].rstrip()
|
||
|
if self.status_template_trns == False:
|
||
|
insert_statement('trn', self.trn)
|
||
|
self.trn = init_trn()
|
||
|
self.tbl = ''
|
||
|
self.key = ''
|
||
|
elif name == 'gnc:template-transactions':
|
||
|
self.status_template_trns = False
|
||
|
elif name == 'gnc:book':
|
||
|
createdelete("CREATE INDEX ACCOUNT_ID ON ACCOUNT (ID)", None)
|
||
|
createdelete("CREATE INDEX TRN_ID ON TRN (ID)", None)
|
||
|
createdelete("CREATE INDEX SPLIT_ID ON SPLIT (ID)", None)
|
||
|
createdelete("CREATE INDEX S_TRN_ID ON SPLIT (TRN_ID)", None)
|
||
|
createdelete("CREATE INDEX S_ACCOUNT ON SPLIT (ACCOUNT)", None)
|
||
|
|
||
|
|
||
|
def characters(self, content):
|
||
|
global crout
|
||
|
crout = 'characters'
|
||
|
global last_input_characters
|
||
|
## last_input_characters = str(self) + ' ' + str(content.encode(lcodec))
|
||
|
|
||
|
if self.tbl == 'act':
|
||
|
if self.key in self.account:
|
||
|
self.account[self.key] += content
|
||
|
elif self.tbl == 'trn':
|
||
|
if self.key in self.trn:
|
||
|
self.trn[self.key] += content
|
||
|
elif self.key == 'date-posted':
|
||
|
self.status_date_posted = True
|
||
|
elif self.tbl == 'ts':
|
||
|
if self.key == 'date' and self.status_date_posted == True:
|
||
|
self.date_posted += content
|
||
|
elif self.tbl == 'split':
|
||
|
if self.key in self.split:
|
||
|
self.split[self.key] += content
|
||
|
elif self.tbl == 'gnc':
|
||
|
if self.key == 'template-transactions':
|
||
|
self.status_template_trns = True
|
||
|
|
||
|
# ***************************** MSGBOX / XRAY *****************************
|
||
|
# Show a message box with the UNO based toolkit
|
||
|
# This function was copied and adapted from OpenOffice.org API - Code Snippet Base
|
||
|
# http://codesnippets.services.openoffice.org
|
||
|
|
||
|
from com.sun.star.awt import Rectangle
|
||
|
from com.sun.star.awt import WindowDescriptor
|
||
|
|
||
|
from com.sun.star.awt.WindowClass import MODALTOP
|
||
|
from com.sun.star.awt.VclWindowPeerAttribute import OK, OK_CANCEL, YES_NO, YES_NO_CANCEL, RETRY_CANCEL, DEF_OK, DEF_CANCEL, DEF_RETRY, DEF_YES, DEF_NO
|
||
|
|
||
|
def MessageBox(MsgText, MsgTitle="GnuCash to Ooo", MsgType="messbox", MsgButtons=OK, ParentWin=None):
|
||
|
global crout
|
||
|
crout = 'MessageBox'
|
||
|
global last_input_MessageBox
|
||
|
## last_input_MessageBox = str(MsgText)
|
||
|
|
||
|
if not ParentWin:
|
||
|
doc = XSCRIPTCONTEXT.getDocument()
|
||
|
try:
|
||
|
ParentWin = doc.CurrentController.Frame.ContainerWindow
|
||
|
except AttributeError:
|
||
|
ParentWin = doc.Frame.ContainerWindow
|
||
|
|
||
|
|
||
|
MsgType = MsgType.lower()
|
||
|
|
||
|
#available msg types
|
||
|
MsgTypes = ("messbox", "infobox", "errorbox", "warningbox", "querybox")
|
||
|
|
||
|
if not ( MsgType in MsgTypes ):
|
||
|
MsgType = "messbox"
|
||
|
|
||
|
#describe window properties.
|
||
|
aDescriptor = WindowDescriptor()
|
||
|
aDescriptor.Type = MODALTOP
|
||
|
aDescriptor.WindowServiceName = MsgType
|
||
|
aDescriptor.ParentIndex = -1
|
||
|
aDescriptor.Parent = ParentWin
|
||
|
#aDescriptor.Bounds = Rectangle()
|
||
|
aDescriptor.WindowAttributes = MsgButtons
|
||
|
|
||
|
tk = ParentWin.getToolkit()
|
||
|
msgbox = tk.createWindow(aDescriptor)
|
||
|
|
||
|
msgbox.setMessageText(MsgText)
|
||
|
if MsgTitle :
|
||
|
msgbox.setCaptionText(MsgTitle)
|
||
|
|
||
|
return msgbox.execute()
|
||
|
|
||
|
## callXray(DB)
|
||
|
|
||
|
##def callXray(obj):
|
||
|
## """Macro to call Basic XRay by Bernard Marcelly from Python."""
|
||
|
##
|
||
|
### Only works if the according libraries are loaded at start of program
|
||
|
### See http://wiki.services.openoffice.org/wiki/Extensions_development_basic#X-Ray_tool
|
||
|
##
|
||
|
## sURL = "vnd.sun.star.script:XRayTool._Main.Xray?language=Basic&location=application"
|
||
|
##
|
||
|
## oMSPF = smgr.createInstanceWithContext(
|
||
|
## "com.sun.star.script.provider.MasterScriptProviderFactory", ctx)
|
||
|
## oMSP = oMSPF.createScriptProvider('')
|
||
|
## oScript = oMSP.getScript(sURL)
|
||
|
## oScript.invoke((obj,), (), ())
|
||
|
##
|
||
|
##
|
||
|
|
||
|
# ***************************** MAIN PROGRAM ******************************
|
||
|
|
||
|
def exec_fillGnuCashDB():
|
||
|
"""Fill OpenOffice.org database with newest GnuCash data"""
|
||
|
global crout
|
||
|
crout = 'exec_fillGnuCashDB'
|
||
|
filepaths = read_filepaths()
|
||
|
if not filepaths:
|
||
|
MessageBox('Reading filepaths not successfull.\n' +
|
||
|
'Please run makro ' + '"' + set_makro + '"', MsgType="errorbox")
|
||
|
return False
|
||
|
|
||
|
gcfile = filepaths[0]
|
||
|
dbname = filepaths[1]
|
||
|
|
||
|
answer = MessageBox('Update database ' + dbname +'?', MsgType = "querybox", MsgButtons=YES_NO)
|
||
|
if not answer == 2: # 2 = YES, 3 = NO
|
||
|
return False
|
||
|
|
||
|
global DB, Connection, Stmt
|
||
|
# get the database
|
||
|
DB=Context.getByName(dbname)
|
||
|
dbhandler = smgr.createInstanceWithContext(
|
||
|
"com.sun.star.sdb.InteractionHandler", ctx)
|
||
|
# get connection to database
|
||
|
Connection=DB.connectWithCompletion(dbhandler)
|
||
|
# create Statement object
|
||
|
Stmt=Connection.createStatement()
|
||
|
|
||
|
# create base Tables
|
||
|
createdelete(create_account, "ACCOUNT")
|
||
|
createdelete(create_trn, "TRN")
|
||
|
createdelete(create_split, "SPLIT")
|
||
|
# drop indices
|
||
|
Stmt.execute("DROP INDEX ACCOUNT_ID IF EXISTS")
|
||
|
Stmt.execute("DROP INDEX TRN_ID IF EXISTS")
|
||
|
Stmt.execute("DROP INDEX SPLIT_ID IF EXISTS")
|
||
|
Stmt.execute("DROP INDEX S_TRN_ID IF EXISTS")
|
||
|
Stmt.execute("DROP INDEX S_ACCOUNT_ID IF EXISTS")
|
||
|
Stmt.execute("DROP INDEX ACCTTREE_ID IF EXISTS")
|
||
|
# drop derived tables
|
||
|
Stmt.execute("DROP VIEW ALL_TRANSACTIONS IF EXISTS")
|
||
|
Stmt.execute("DROP TABLE ACCTTREE IF EXISTS")
|
||
|
|
||
|
# read GnuCash Data
|
||
|
try:
|
||
|
f = gzip.open(gcfile)
|
||
|
gcxml = f.read()
|
||
|
except:
|
||
|
f = open(gcfile)
|
||
|
gcxml = f.read()
|
||
|
|
||
|
global Stmt_ins_account, Stmt_ins_trn, Stmt_ins_split
|
||
|
# create preparedStatement objects
|
||
|
Stmt_ins_account = Connection.prepareStatement(insert_account)
|
||
|
Stmt_ins_trn = Connection.prepareStatement(insert_trn)
|
||
|
Stmt_ins_split = Connection.prepareStatement(insert_split)
|
||
|
|
||
|
# parse data and insert into database
|
||
|
handler = GCContent()
|
||
|
parser = sax.make_parser()
|
||
|
parser.setContentHandler(handler)
|
||
|
parser.feed(gcxml)
|
||
|
f.close()
|
||
|
ct_lvl = accounttree()
|
||
|
view_all_transactions(ct_lvl)
|
||
|
# write checkpoint so all tables are stored in database
|
||
|
# (and not only in logfile)
|
||
|
Stmt.execute("CHECKPOINT")
|
||
|
DB.DatabaseDocument.store()
|
||
|
# close connection
|
||
|
Connection.close()
|
||
|
MessageBox('Database ' + dbname + ' has been successfully updated.',
|
||
|
MsgType="infobox")
|
||
|
|
||
|
def issue_error_messages(args):
|
||
|
logfile = settings_filepath()
|
||
|
settings = open(logfile, 'a')
|
||
|
entrance_line = '\nErrorlogging ' + time.ctime() + '\n'
|
||
|
settings.write(entrance_line)
|
||
|
strMsg = "Error! %s %s " % (args.__class__.__name__, args) + '\n'
|
||
|
settings.write(strMsg)
|
||
|
current_routine = 'current routine = ' + crout + '\n'
|
||
|
settings.write(current_routine)
|
||
|
## input_info = 'last input getDBFilename: ' + last_input_getDBFilename + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input createDB: ' + last_input_createDB + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input createdelete: ' + last_input_createdelete + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input eval_fraction: ' + last_input_eval_fraction + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input view_all_transactions: ' + last_input_view_all_transactions + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input __init__: ' + last_input___init__ + '\n'
|
||
|
## settings.write(input_info)
|
||
|
input_info = 'last input startElement: ' + last_input_startElement + '\n'
|
||
|
settings.write(input_info)
|
||
|
input_info = 'last input endElement: ' + last_input_endElement + '\n'
|
||
|
settings.write(input_info)
|
||
|
input_info = 'last input insert_statement: ' + last_input_insert_statement + '\n'
|
||
|
settings.write(input_info)
|
||
|
## input_info = 'last input characters: ' + last_input_characters + '\n'
|
||
|
## settings.write(input_info)
|
||
|
## input_info = 'last input MessageBox: ' + last_input_MessageBox + '\n'
|
||
|
## settings.write(input_info)
|
||
|
strMsg = strMsg + 'For further information look into file\n' + logfile
|
||
|
MessageBox(strMsg, MsgType="errorbox")
|
||
|
settings.close()
|
||
|
return
|
||
|
|
||
|
|
||
|
def fillGnuCashDB():
|
||
|
global crout
|
||
|
crout = 'fillGnuCashDB'
|
||
|
try:
|
||
|
exec_fillGnuCashDB()
|
||
|
except Exception, args:
|
||
|
issue_error_messages(args)
|
||
|
return
|
||
|
|
||
|
def SetGnuCashFilePaths():
|
||
|
global crout
|
||
|
crout = 'SetGnuCashFilePaths'
|
||
|
try:
|
||
|
exec_SetGnuCashFilePaths()
|
||
|
except Exception, args:
|
||
|
issue_error_messages(args)
|
||
|
return
|
||
|
|
||
|
g_exportedScripts = fillGnuCashDB, SetGnuCashFilePaths,
|
||
|
|