#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # gnucash-cdnpayroll.py -- example script for inserting cdnpayroll results into gnucash # # Copyright (C) 2011 Ben McGunigle # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, contact: # Free Software Foundation Voice: +1-617-542-5942 # 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 # Boston, MA 02110-1301, USA gnu@gnu.org # # @author Ben McGunigle #Example usage: #./gnucash-cdnpayroll.py --rate=12 --hours=38 --label="Joe's Paycheque" --date=2011-05-31 --payperiod=52 from cdnpayroll import cdnpayroll from gnucash import Session, GncNumeric, Transaction, Split, Account import sys, getopt, dateutil.parser from datetime import datetime #parameters for cdnpayroll. See http://cdnpayroll.gemlog.ca/ for more options # remember to set your province and WCB rate params = {"RESIDES":"BC", "TD1P":1, "TD1F":1, "P":26, "WCBrate":0.0} #You are going to run this on a test.gnucash file first, aren't you? gnucash_file = "/YOUR/GNUCASH/FILE/HERE.gnucash" # Beware: your account names may vary. Set them here. acct_set = {} acct_set['gross'] = ("Expenses", "Payroll Expenses") acct_set['fed'] = ("Liabilities", "Payroll", "Federal") acct_set['prov'] = ("Liabilities", "Payroll", "Provincial") acct_set['empCPPexp'] = ("Expenses", "Payroll Expenses", "CPP") acct_set['empCPP'] = ("Liabilities", "Payroll", "Employer CPP") acct_set['empEIexp'] = ("Expenses", "Payroll Expenses", "EI") acct_set['empEI'] = ("Liabilities", "Payroll", "Employer EI") acct_set['WCBexp'] = ("Expenses", "Payroll Expenses", "WComp") acct_set['WCB'] = ("Liabilities", "Payroll", "WComp") acct_set['CPP'] = ("Liabilities", "Payroll", "CPP") acct_set['EI'] = ("Liabilities", "Payroll", "EI") acct_set['net'] = ("Assets", "Current Assets", "Chequing Account") cr_or_db = {} cr_or_db['gross'] = True cr_or_db['fed'] = False cr_or_db['prov'] = False cr_or_db['empCPPexp'] =True cr_or_db['empCPP'] = False cr_or_db['empEIexp'] = True cr_or_db['empEI'] = False cr_or_db['WCBexp'] = True cr_or_db['WCB'] = False cr_or_db['CPP'] = False cr_or_db['EI'] = False cr_or_db['net'] = False #Determines the order of entries in the split transaction Keyset = ('gross', 'fed', 'prov', 'empCPPexp', 'empCPP', 'empEIexp', 'empEI', 'WCBexp', 'WCB', 'CPP', 'EI', 'net') # ^ configuration, v hacking You should be able to get it working with the stuff above. longopts = ['income=', 'hours=', 'rate=', 'label=', 'date=', 'payperiod='] opts, argmts = getopt.getopt(sys.argv[1:], 'i:h:r:l:d:p:', longopts) o_hours = 0 o_rate = 0 o_description = "" o_date = datetime.today() for flag, val in opts: if flag in ('-i', '--income'): params['I'] = float(val) elif flag in ('-h', '--hours'): o_hours = float(val) elif flag in ('-r', '--rate'): o_rate = float(val) elif flag in ('-l', '--label'): o_description = val elif flag in ('-d', '--date'): o_date = dateutil.parser.parse(val) elif flag in ('-p', '--payperiod'): params['P'] = int(val) else: print "Invalid option" sys.exit() if not params.has_key('I'): if o_hours and o_rate: params['I'] = o_hours * o_rate else: print "Need --income or --hours and --rate" sys.exit() res = cdnpayroll(params) payvals = {} payvals['gross'] = res['grossb4hp'] payvals['fed'] = res['feds'] payvals['prov'] = res['prov'] payvals['empCPPexp'] = res['Cemp'] payvals['empCPP'] = res['Cemp'] payvals['empEIexp'] = res['EIemp'] payvals['empEI'] = res['EIemp'] payvals['WCBexp'] = res['WCB'] payvals['WCB'] = res['WCB'] payvals['CPP'] = res['C'] payvals['EI'] = res['EI'] payvals['net'] = res['netpay'] # Convert account strings to account objects session = Session(gnucash_file, is_new=False) root_account = session.book.get_root_account() def account_from_path(top_account, account_path, original_path=None): if original_path==None: original_path = account_path account, account_path = account_path[0], account_path[1:] account = top_account.lookup_by_name(account) if account.get_instance() == None: raise Exception( "path " + ''.join(original_path) + " could not be found") if len(account_path) > 0 : return account_from_path(account, account_path, original_path) else: return account for (key, value) in acct_set.items(): acct_set[key] = account_from_path(root_account, value) commod_tab = session.book.get_table() CAD = commod_tab.lookup("ISO4217","CAD") trans = Transaction(session.book) trans.BeginEdit() trans.SetCurrency(CAD) trans.SetDescription(o_description) tdate = (o_date.day, o_date.month, o_date.year) trans.SetDate( *tdate) for key in Keyset: split = Split(session.book) split.SetParent(trans) split.SetAccount(acct_set[key]) #GncNumeric likes integers, so we multiply by 100 and give it 100 as the denominator (second parameter) #See gnc-numeric.h for more details the_val = round(payvals[key]*100) if cr_or_db[key]: split.SetValue(GncNumeric(the_val,100)) # SetValue, SetAmount??? No, I don't know why. split.SetAmount(GncNumeric(the_val,100)) else: split.SetValue(GncNumeric(the_val,100).neg()) split.SetAmount(GncNumeric(the_val,100).neg()) trans.CommitEdit() session.save() session.end() session.destroy()