diff --git a/bindings/python/example_scripts/qof.py b/bindings/python/example_scripts/qof.py new file mode 100644 index 0000000000..8d009548bc --- /dev/null +++ b/bindings/python/example_scripts/qof.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 + +## @file +# @brief Some examples for qof queries +# @author Christoph Holtermann +# @date 2022-03-06 +# @ingroup python_bindings_examples +# @note incomplete set of qof examples, to be extended + +import datetime +from random import randint +from gnucash import Session, SessionOpenMode, Account, Transaction, Split, GncNumeric, Query +from gnucash import QOF_COMPARE_GTE, QOF_COMPARE_GT, QOF_QUERY_AND, QOF_QUERY_OR, QOF_STRING_MATCH_NORMAL +from gnucash import gnucash_core_c +from gnucash import gnucash_core + +# We need to tell GnuCash the data format to create the new file as (xml://) +uri = "xml:///tmp/qof.gnucash" + +def createAccounts(book): + root_account = book.get_root_account() + commodtable = book.get_table() + currency = commodtable.lookup("CURRENCY", "EUR") + ses.save() + + print('Create two accounts ("Account A", "Account B")') + accountA = Account(book) + accountA.SetCommodity(currency) + accountA.SetName("Account A") + root_account.append_child(accountA) + + accountB = Account(book) + accountB.SetCommodity(currency) + accountB.SetName("Account B") + root_account.append_child(accountB) + + #ses.save() + + return accountA, accountB + +def createRandomTransactions(book, accountA, accountB): + split = Split(book) + + currency = book.get_table().lookup("CURRENCY", "EUR") + + print("Create 100 random transactions") + for i in range(100): + + trans = Transaction(book) + trans.BeginEdit() + trans.SetCurrency(currency) + trans.SetDate(randint(1,28), randint(1,12), randint(1900,2000)) + trans.SetDescription("Transaction "+str(i)) + + value = randint(0,10000) + + value1 = GncNumeric(value, 100) + value2 = GncNumeric(-value, 100) + + split1 = Split(book) + split1.SetValue(value1) + split1.SetAccount(accountA) + split1.SetMemo("A" + str(i)) + split1.SetParent(trans) + + split2 = Split(book) + split2.SetValue(value2) + split2.SetAccount(accountB) + split2.SetMemo("B" + str(i)) + split2.SetParent(trans) + + trans.CommitEdit() + +def query_transactions(book, terms=[]): + + query = Query() + query.search_for('Trans') + query.set_book(book) + + if terms: + for term in terms: + query.add_term(*term) + + transactions = [] + + for transaction in query.run(): + transaction = Transaction(instance=transaction) # ToDo: query.run() should return objects + transactions.append(transaction) + + query.destroy() + return transactions + +def query_splits(book, terms=[]): + + query = Query() + query.search_for('Split') + query.set_book(book) + + if terms: + for term in terms: + query.add_term(*term) + + splits = [] + + for split in query.run(): + split = Split(instance=split) # ToDo: query.run() should return objects + splits.append(split) + + query.destroy() + return splits + +with Session(uri, SessionOpenMode.SESSION_NEW_STORE) as ses: + + book = ses.get_book() + accountA, accountB = createAccounts(book) + createRandomTransactions(book, accountA, accountB) + + # TRANSACTIONS + # + # get all transactions + transactions_all = query_transactions(book) + print("Query all: " + str(len(transactions_all)) + " transactions.") + + # query date + threshold = datetime.datetime(1950,1,1) + QOF_DATE_MATCH_NORMAL = 2 + terms = [(['date-posted'], gnucash_core.QueryDatePredicate(QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, threshold), QOF_QUERY_AND)] + transactions_2 = query_transactions(book, terms) + print("Query transactions with date > 1950: " + str(len(transactions_2)) + " (Should be about 50).") + + # query description + QOF_COMPARE_CONTAINS = 7 + isRegex = False + terms = [(['desc'], gnucash_core.QueryStringPredicate(QOF_COMPARE_CONTAINS, "Transaction 5", QOF_STRING_MATCH_NORMAL, isRegex), QOF_QUERY_AND)] + transactions_3 = query_transactions(book, terms) + print("Query transaction with description containing 'Transaction 5': " + str(len(transactions_3)) + " (Should be 11).") + + # SPLITS + # + # query memo + QOF_COMPARE_CONTAINS = 7 + isRegex = False + terms = [(['memo'], gnucash_core.QueryStringPredicate(QOF_COMPARE_CONTAINS, "A22", QOF_STRING_MATCH_NORMAL, isRegex), QOF_QUERY_AND)] + splits_1 = query_splits(book, terms) + print("Query splits with memo containing 'A22': " + str(len(splits_1)) + " (Should be 1).") + + # query description + QOF_COMPARE_CONTAINS = 7 + isRegex = False + terms = [(['trans', 'desc'], gnucash_core.QueryStringPredicate(QOF_COMPARE_CONTAINS, "Transaction 5", QOF_STRING_MATCH_NORMAL, isRegex), QOF_QUERY_AND)] + splits_2 = query_splits(book, terms) + print("Query splits with transaction description containing 'Transaction 5': " + str(len(splits_2)) + " (Should be 22).") + + # query memo and desc + QOF_COMPARE_CONTAINS = 7 + isRegex = False + terms = [(['memo'], gnucash_core.QueryStringPredicate(QOF_COMPARE_CONTAINS, "A22", QOF_STRING_MATCH_NORMAL, isRegex), QOF_QUERY_AND)] + terms += [(['trans', 'desc'], gnucash_core.QueryStringPredicate(QOF_COMPARE_CONTAINS, "Transaction 55", QOF_STRING_MATCH_NORMAL, isRegex), QOF_QUERY_OR)] + splits_4 = query_splits(book, terms) + print("Query splits with memo containing 'A22' or transaction desc containing 'Transaction 55': " + str(len(splits_4)) + " (Should be 3).") + + # query split value + threshold = GncNumeric(5000, 100) + QOF_NUMERIC_MATCH_ANY = 1 + terms = [(["amount"], gnucash_core_c.qof_query_numeric_predicate(QOF_COMPARE_GT, QOF_NUMERIC_MATCH_ANY, threshold.instance), QOF_QUERY_AND)] + splits_3 = query_splits(book, terms) + print("Query splits with amount > " + str(threshold) + ": " + str(len(splits_3)) + " (Should be about 50).")