Create transaction in GnuCash in response to an email?

2.1k Views Asked by At

I would like to create a script which is triggered by an email filter which, when run, creates two transactions in GnuCash. I see that GnuCash has Python bindings but the documentation is sparse at best... a better term would be "nonexistent".

Is it possible to write a script which will create transactions in GnuCash? If so, what would the very basic code look like? I just need a starting point; once I have that I can script this fairly well myself.

2

There are 2 best solutions below

0
On

Here is an alternative solution using piecash (https://github.com/sdementen/piecash, version 0.10.1), a modern python library to work with gnucash books (disclaimer: I am the author)

from piecash import open_book, Transaction, Split
from datetime import datetime
from decimal import Decimal

# open the book
with open_book("/path/to/file.gnucash", 
               open_if_lock=True, 
               readonly=False) as mybook:
    today = datetime.now()
    # retrieve the currency from the book
    USD = mybook.currencies(mnemonic="USD")
    # define the amount as Decimal
    amount = Decimal("25.35")
    # retrieve accounts
    to_account = mybook.accounts(fullname="Expenses:Some Expense Account")
    from_account = mybook.accounts(fullname="Assets:Current Assets:Checking")
    # create the transaction with its two splits
    Transaction(
        post_date=today,
        enter_date=today,
        currency=USD,
        description="Transaction Description!",
        splits=[
            Split(account=to_account,
                  value=amount,
                  memo="Split Memo!"),
            Split(account=from_account,
                  value=-amount,
                  memo="Other Split Memo!"),
        ]
    )
    # save the book
    mybook.save()
1
On

Here's a template, along with a couple of account lookup functions which are sorely lacking in the library. You can place all of the transaction code into a function, then hand in whatever data you need to create the two custom transactions. Then just call the transaction function from your email listener, and you should be in business.

from gnucash import Session, Account, Transaction, Split, GncNumeric
import gnucash
from datetime import datetime

def lookup_account_by_path(parent, path):
    acc = parent.lookup_by_name(path[0])
    if acc.get_instance() == None:
        raise Exception('Account path {} not found'.format(':'.join(path)))
    if len(path) > 1:
        return lookup_account_by_path(acc, path[1:])
    return acc

def lookup_account(root, name):
    path = name.split(':')
    return lookup_account_by_path(root, path)

session = Session("/path/to/file.gnucash") #, ignore_lock=True)
   # or use URI string: ('mysql://USER:PASSWORD@HOST/DATABASE')

today = datetime.now()
book = session.book # All actions are performed through the book object (or its children)
root = book.get_root_account() # Parent of all accounts
currency = book.get_table().lookup('ISO4217', "USD")
tx = Transaction(book)
tx.BeginEdit()
tx.SetCurrency(currency)
tx.SetDateEnteredTS(today)
tx.SetDatePostedTS(today) # or another datetime object for the transaction's "register date"
tx.SetDescription("Transaction Description!")
#tx.SetNum(int_variable) # if you need a transaction number

sp1 = Split(book) # First half of transaction
sp1.SetParent(tx)
# The lookup string needs to match your account path exactly.
sp1.SetAccount(lookup_account(root, "Expenses:Some Expense Account"))
# amount is an int (no $ or .), so $5.23 becomes amount=523
sp1.SetValue(GncNumeric(amount, 100)) # Assuming you only have one split
# For multiple splits, you need to make sure the totals all balance out.
sp1.SetAmount(GncNumeric(amount, 100))
sp1.SetMemo("Split Memo!") # optional

sp2 = Split(book) # Need a balancing split
sp2.SetParent(tx)
sp2.SetAccount(lookup_account(root, "Assets:Current Assets:Checking"))
sp2.SetValue(sp1.GetValue().neg())
sp2.SetAmount(sp1.GetValue().neg())
sp2.SetMemo("Other Split Memo!") # optional

tx.CommitEdit() # Finish editing transaction
session.save()
session.end()