Example #1
0
def write_transactions_to_gnucash(gnucash_file, currency, all_items, dry_run=False, date_from=None):
    logging.debug("Opening GnuCash file %s..", gnucash_file)
    session = Session(gnucash_file)
    book = session.book
    commod_tab = book.get_table()
    currency = commod_tab.lookup("ISO4217", currency)

    if date_from:
        date_from = datetime.datetime.strptime(date_from, "%Y-%m-%d")

    imported_items = set()
    for item in all_items:
        if date_from and item.date < date_from:
            logging.info("Skipping entry %s (%s)", item.date.strftime("%Y-%m-%d"), item.split_amount)
            continue
        if item.as_tuple() in imported_items:
            logging.info(
                "Skipping entry %s (%s) --- already imported!", item.date.strftime("%Y-%m-%d"), item.split_amount
            )
            continue
        add_transaction(book, item, currency)
        imported_items.add(item.as_tuple())

    if dry_run:
        logging.debug("** DRY-RUN **")
    else:
        logging.debug("Saving GnuCash file..")
        session.save()
    session.end()
def main(args):
    if args.verbose:
        lvl = logging.DEBUG
    elif args.quiet:
        lvl = logging.WARN
    else:
        lvl = logging.INFO

    logging.basicConfig(level=lvl)

    all_items = []
    for fn in args.file:
        logging.debug('Reading %s..', fn)
        with open(fn) as fd:
            items = qif.parse_qif(fd)
            logging.debug('Read %s items from %s..', len(items), fn)
            all_items.extend(items)

    logging.debug('Opening GnuCash file %s..', args.gnucash_file)
    session = Session(args.gnucash_file)
    book = session.book
    commod_tab = book.get_table()
    currency = commod_tab.lookup('ISO4217', args.currency)

    for item in all_items:
        add_transaction(book, item, currency)    

    logging.debug('Saving GnuCash file..')
    session.save()
    session.end()
Example #3
0
def main():
    if len(argv) < 3:
        print "Usage: python make_securities.py <gnucash-file> <symbols-file>"
        exit(1)

    gnucash_file = argv[1]

    secs = read_symbols(argv[2])

    sess = Session(gnucash_file)

    try:
        # Make sure all the commodities exist
        ct = sess.book.get_table()

        created_secs = 0
        updated_secs = 0
        total_secs = 0
        for ns in ["CUSIP", "ISIN"]:
            total_secs += len(secs[ns])
            for c in ct.get_commodities(ns):
                matched_sec = None
                for k in secs[ns]:
                    sec = secs[ns][k]
                    if sec["id"] == c.get_cusip():
                        matched_sec = sec
                        break
                if matched_sec:
                    matched_sec["c"] = c
                    updated = False
                    if c.get_fullname() != matched_sec["name"]:
                        c.set_fullname(matched_sec["name"])
                        updated = True
                    if c.get_mnemonic() != matched_sec["symbol"]:
                        c.set_mnemonic(matched_sec["symbol"])
                        updated = True
                    if updated:
                        updated_secs += 1
                        print "DEBUG: Updating Commodity", sec["name"]
                    del secs[ns][matched_sec["id"]]
            for k in secs[ns]:
                sec = secs[ns][k]
                c = GncCommodity(sess.book, sec["name"], ns, sec["symbol"], sec["id"], 10000)
                if c:
                    ct.insert(c)
                    created_secs += 1
                    print "DEBUG: Created Commodity", sec["name"], sec["id"]
                else:
                    print "ERROR: Error creating Commodity", sec["name"]

        print "INFO:", total_secs, "commodities total,", created_secs, "created,", updated_secs, "updated."

        wait_for_backup_file(gnucash_file)
        sess.save()
    except BaseException as e:
        print "ERROR:", e
    finally:
        sess.end()
        sess.destroy()
def main():
    args = parse_cmdline()
    if args.version:
        print VERSION
        exit(0)

    if args.verbose:
        loglevel = logging.DEBUG
    elif args.quiet:
        loglevel = logging.WARN
    else:
        loglevel = logging.INFO
    logging.basicConfig(level=loglevel)

    rules = readrules(args.rulesfile)
    account_path = re.split(':', args.ac2fix)

    gnucash_session = Session(args.gnucash_file, is_new=False)
    total = 0
    imbalance = 0
    fixed = 0
    try:
        root_account = gnucash_session.book.get_root_account()
        orig_account = account_from_path(root_account, account_path)

        imbalance_pattern = re.compile(args.imbalance_ac)

        for split in orig_account.GetSplitList():
            total += 1
            trans = split.parent
            splits = trans.GetSplitList()
            trans_date = date.fromtimestamp(trans.GetDate())
            trans_desc = trans.GetDescription()
            trans_memo = trans.GetNotes()
            for split in splits:
                ac = split.GetAccount()
                acname = ac.GetName()
                logging.debug('%s: %s => %s', trans_date, trans_desc, acname)
                if imbalance_pattern.match(acname):
                    imbalance += 1
                    search_str = trans_desc
                    if args.use_memo:
                        search_str = trans_memo
                    newac = get_ac_from_str(search_str, rules, root_account)
                    if newac != "":
                        logging.debug('\tChanging account to: %s', newac.GetName())
                        split.SetAccount(newac)
                        fixed += 1

        if not args.nochange:
            gnucash_session.save()

        logging.info('Total splits=%s, imbalance=%s, fixed=%s', total, imbalance, fixed)

    except Exception as ex:
        logging.error(ex) 

    gnucash_session.end()
def main():
	args = parse_cmdline()
	if args.version:
		print VERSION
		exit(0)
	rules = readrules(args.rulesfile)
	account_path = re.split(':', args.ac2fix)
	

	gnucash_session = Session(args.gnucash_file, is_new=False)
	root_account = gnucash_session.book.get_root_account()
	orig_account = account_from_path(root_account, account_path)

	total = 0
	imbalance = 0
	fixed = 0
	for split in orig_account.GetSplitList():
		total += 1
		trans = split.parent
		splits = trans.GetSplitList()
		trans_date = date.fromtimestamp(trans.GetDate())
		trans_desc = trans.GetDescription()
		trans_memo = trans.GetNotes()
		ac = splits[0].GetAccount()
		acname = ac.GetName()
		if not args.silent:
			print trans_date,":", trans_desc, "=>", acname
		# check if acname is "Imbalance-USD"
		if acname == args.imbalance_ac:
			imbalance += 1
			search_str = trans_desc
			if args.use_memo:
				search_str = trans_memo
			newac = get_ac_from_str(search_str, rules, root_account)
			if newac != "":
				if not args.silent:
					print "\t Changing account to: ", newac.GetName()
				splits[0].SetAccount(newac)
				fixed += 1
 
	if not args.nochange:
		gnucash_session.save()
	gnucash_session.end()

	if not args.silent:
		print "Total splits=", total, " imbalance=", imbalance, " fixed=", fixed
def main():
    original_book_session = Session(argv[1], False)
    new_book_session = Session(argv[2], True)
    new_book = new_book_session.get_book()
    new_book_root = new_book.get_root_account()

    commodtable = new_book.get_table()
    # we discovered that if we didn't have this save early on, there would
    # be trouble later
    new_book_session.save()

    opening_balance_per_currency = {}
    recursivly_build_account_tree(
        original_book_session.get_book().get_root_account(),
        new_book_root,
        new_book,
        commodtable,
        opening_balance_per_currency,
        ACCOUNT_TYPES_TO_OPEN
        )

    (namespace, mnemonic) = PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE
    if (namespace, mnemonic) in opening_balance_per_currency:
        opening_trans, opening_amount = opening_balance_per_currency[
            (namespace, mnemonic)]
        simple_opening_name_used = create_opening_balance_transaction(
            commodtable, namespace, mnemonic,
            new_book_root, new_book,
            opening_trans, opening_amount,
            False )
        del opening_balance_per_currency[
            PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE]
    else:
        simple_opening_name_used = False

    for (namespace, mnemonic), (opening_trans, opening_amount) in \
            opening_balance_per_currency.iteritems() :
        simple_opening_name_used = create_opening_balance_transaction(
            commodtable, namespace, mnemonic,
            new_book_root, new_book,
            opening_trans, opening_amount,
            simple_opening_name_used )

    new_book_session.save()
    new_book_session.end()
    original_book_session.end()
class Accounting:

    def __init__(self,filename):
        self.closed = False

        self.session = Session(filename)
        self.book = self.session.book
        commod_table = self.book.get_table()
        self.EUR = commod_table.lookup('CURRENCY', 'EUR')
        
        self.receivables = self._get_account(ACCOUNT_RECEIVABLE,ACCT_TYPE_RECEIVABLE);
        self.payables = self._get_account(ACCOUNT_PAYABLE,ACCT_TYPE_PAYABLE);
        
        self.btw_collected_high = self._get_account(ACCOUNT_BTW_COLLECTED_HIGH,ACCT_TYPE_LIABILITY);
        self.btw_reported_high = self._get_account(ACCOUNT_BTW_REPORTED_HIGH,ACCT_TYPE_LIABILITY);
        self.btw_collected_low = self._get_account(ACCOUNT_BTW_COLLECTED_LOW,ACCT_TYPE_LIABILITY);
        self.btw_reported_low = self._get_account(ACCOUNT_BTW_REPORTED_LOW,ACCT_TYPE_LIABILITY);
        self.btw_collected_import = self._get_account(ACCOUNT_BTW_COLLECTED_IMPORT,ACCT_TYPE_LIABILITY);
        self.btw_reported_import = self._get_account(ACCOUNT_BTW_REPORTED_IMPORT,ACCT_TYPE_LIABILITY);
        self.btw_paid_nl = self._get_account(ACCOUNT_BTW_PAID_NL,ACCT_TYPE_ASSET);
        self.btw_reported_nl = self._get_account(ACCOUNT_BTW_REPORTED_NL,ACCT_TYPE_ASSET);
        self.btw_paid_eu = self._get_account(ACCOUNT_BTW_PAID_EU,ACCT_TYPE_ASSET);
        self.btw_reported_eu = self._get_account(ACCOUNT_BTW_REPORTED_EU,ACCT_TYPE_ASSET);
        self.btw_reported_eu = self._get_account(ACCOUNT_BTW_REPORTED_EU,ACCT_TYPE_ASSET);
        self.tax_expense = self._get_account(ACCOUNT_TAX_EXPENSE,ACCT_TYPE_EXPENSE);

        self.taxtables = self.book.TaxTableGetTables()

    def _get_account(self,name,acct_type):
        root = self.book.get_root_account()
        acct = root.lookup_by_full_name(name)
        if acct.GetType() != acct_type:
            raise Exception('Account '+name+' does not exist with type '+str(acct_type))
        return acct

    def save(self):
        self.session.save()

    def close(self):
        if not self.closed:
            self.session.end()
            self.closed = True

    def __del__(self):
        self.close()
class DenhacGncSession:
    _path = None
    _session = None
    _root = None
    _commod = None
    _currency = None

    def __init__(self, path):
        if os.path.exists(path + '.LCK'):
            raise AssertionError("""Lock file exists. Is GNUCash running?\n""")

        self._path = path
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self._session = Session(path, is_new = False)

        self._root = self.getBook().get_root_account()
        self._commod = self.getBook().get_table()
        self._currency = self._commod.lookup('CURRENCY', 'USD')

    def saveAndEndSession(self):
        self._session.save()
        self._session.end()

    def saveSession(self):
        self._session.save()

    def endSession(self):
        self._session.end()

    def cancelSession(self):
        self._session.end()
        self._session.destroy()

    def getBook(self):
        return self._session.book

    def getRoot(self):
        return self._session.book.get_root_account()

    def getCurrency(self):
        return self._currency
def main():

    if len(argv) < 3:
        print('not enough parameters')
        print('usage: new_book_with_opening_balances.py {source_book_url} {destination_book_url}')
        print('examples:')
        print("gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'sqlite3:///home/username/new_test.gnucash'")
        print("gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'xml:///crypthome/username/finances/new_test.gnucash'")
        return

    #have everything in a try block to unable us to release our hold on stuff to the extent possible
    try:
        original_book_session = Session(argv[1], is_new=False)
        new_book_session = Session(argv[2], is_new=True)
        new_book = new_book_session.get_book()
        new_book_root = new_book.get_root_account()

        commodtable = new_book.get_table()
        # we discovered that if we didn't have this save early on, there would
        # be trouble later
        new_book_session.save()

        opening_balance_per_currency = {}
        recursivly_build_account_tree(
            original_book_session.get_book().get_root_account(),
            new_book_root,
            new_book,
            commodtable,
            opening_balance_per_currency,
            ACCOUNT_TYPES_TO_OPEN
            )

        (namespace, mnemonic) = PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE
        if (namespace, mnemonic) in opening_balance_per_currency:
            opening_trans, opening_amount = opening_balance_per_currency[
                (namespace, mnemonic)]
            simple_opening_name_used = create_opening_balance_transaction(
                commodtable, namespace, mnemonic,
                new_book_root, new_book,
                opening_trans, opening_amount,
                False )
            del opening_balance_per_currency[
                PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE]
        else:
            simple_opening_name_used = False

        for (namespace, mnemonic), (opening_trans, opening_amount) in \
                opening_balance_per_currency.iteritems() :
            simple_opening_name_used = create_opening_balance_transaction(
                commodtable, namespace, mnemonic,
                new_book_root, new_book,
                opening_trans, opening_amount,
                simple_opening_name_used )

        new_book_session.save()
        new_book_session.end()
        original_book_session.end()
    except:
        if "original_book_session" in locals():
            original_book_session.end()
 
        if "new_book_session" in locals():
            new_book_session.end()

        raise
Example #10
0
def map_customers(request):
    rows = request.session.get("rows", [])
    map = request.session.get("map", {})

    data = []
    for row in rows:
        new_row = {}
        for index, field in map.items():
            new_row[field] = row[int(index)]
        if not new_row["amount"].startswith("-"):
            data.append(new_row)

    session = Session(settings.GNUCASH_FILE)

    CustomerFormSet = formset_factory(CustomerForm, extra=0)

    if request.method == "POST":
        formset = CustomerFormSet(request.POST,
                                  form_kwargs={"book": session.book})
        try:
            ok = dup = 0
            for form in formset.forms:
                if form.is_valid():
                    clean = form.cleaned_data
                    try:
                        commands.apply_payment(
                            session.book,
                            clean["customer"],
                            clean["amount"],
                            clean["date"],
                        )
                        ok += 1
                    except PaymentExists as e:
                        messages.warning(request, e)
                        dup += 1

            session.save()
            if ok:
                messages.info(request,
                              "Successfully imported %s transactions" % ok)
            if dup:
                messages.warning(request,
                                 "Skipped %s duplicate transactions" % dup)

        except Exception as e:
            # messages.error(request, e)
            raise

        finally:
            session.end()

        return HttpResponseRedirect(reverse("income-finish"))
    else:
        initial = []
        for row in data:
            customer = queries.match_customer(session.book,
                                              row.get("customer"))
            initial.append({
                "customer": customer,
                "amount": row.get("amount"),
                "date": row.get("date"),
                "description": row.get("customer"),
            })
        formset = CustomerFormSet(initial=initial,
                                  form_kwargs={"book": session.book})

    session.end()

    return render(
        request,
        "importer/map-customers.html",
        {
            "formset": formset,
            "rows": zip(data, formset.forms),
            "gnucash": settings.GNUCASH_FILE,
        },
    )
Example #11
0
#!/usr/bin/env python

##  @file
#   @brief Simple example for a book
#   @ingroup python_bindings_examples

import sys
from gnucash import Session

# We need to tell GnuCash the data format to create the new file as (xml://)
uri = "xml:///tmp/simple_book.gnucash"

print "uri:", uri
ses = Session(uri, is_new=True)
book = ses.get_book()

# Call some methods that produce output to show that Book works
book.get_root_account().SetDescription("hello, book")
print "Book is saved:", not book.not_saved()

print "saving..."
ses.save()

print "Book is saved:", not book.not_saved()
ses.end()
Example #12
0
# choose the account code to select
TARGET_ACCOUNT_CODE = '1234'

def mark_account_with_code_as_tax_related(account, target_code):
    """Looks at account to see if it has the target_account_code, if so
    set the account tax related flag to True and return True.
    If not, recursively tries to do the same to all children accounts
    of account.
    Returns False when recursion fails to find it.
    """
    if account.GetCode() == target_code:
        account.SetTaxRelated(True)
        return True
    else:
        for child in account.get_children():
            child = Account(instance=child)
            if mark_account_with_code_as_tax_related(child, target_code):
                return True
        return False
            
# Change this path to your own
gnucash_session = Session("xml:///home/mark/python-bindings-help/test.xac")

mark_account_with_code_as_tax_related(
    gnucash_session.book.get_root_account(),
    TARGET_ACCOUNT_CODE)

gnucash_session.save()
gnucash_session.end()
Example #13
0
from gnucash import Session, Account

TARGET_ACCOUNT_CODE = '1234'


def mark_account_with_code_as_tax_related(account, target_code):
    """Looks at account to see if it has the target_account_code, if so
    returns True.
    If not, recursively tries to do the same to all children accounts
    of account.
    Returns False when recursion fails to find it.
    """
    if account.GetCode() == target_code:
        account.SetTaxRelated(True)
        return True
    else:
        for child in account.get_children():
            child = Account(instance=child)
            if mark_account_with_code_as_tax_related(child, target_code):
                return True
        return False


gnucash_session = Session("file:/home/mark/python-bindings-help/test.xac")

mark_account_with_code_as_tax_related(gnucash_session.book.get_root_account(),
                                      TARGET_ACCOUNT_CODE)

gnucash_session.save()
gnucash_session.end()
Example #14
0
    session.destroy()
    quit() # Or try next invoice
else: # No currebt invoice found so create a new invoice TODO need to lookup next free Invoice ID perhaps?
  print "Creating a new invoice"
  invoice = Invoice(book, 'TEST', gbp, customer ) # I know, need to check of this exists too!!  But this is a test script so...
  # NB Gnucash will happily make another invoice/bill with the same ID!  I think this is a bad thing.
  invoice.SetDateOpened(datetime.date.today())

if invoice: # Test code
  invoice.GetID()

# Create a new entry and populate it.  Normally there would be a loop for each entry required, reading from a csv or similar
entry = gnucash.gnucash_business.Entry(book, invoice)
entry.SetDate(datetime.date.today())
entry.SetDateEntered(datetime.date.today())
entry.SetDescription ("Some stuff I sold")
entry.SetAction("Material")
entry.SetInvAccount(income)
entry.SetQuantity( GncNumeric(1) )
gnc_price = GncNumeric(1040, 100) ## = price x 100 then set denom to 100
entry.SetInvPrice(gnc_price)
#entry.SetInvTaxTable(tax_table)
entry.SetInvTaxIncluded(False)


session.save() #
session.end()
session.destroy()


def main():
    args = parse_cmdline()
    if args.version:
        print(VERSION)
        exit(0)

    if args.verbose:
        loglevel = logging.DEBUG
    elif args.quiet:
        loglevel = logging.WARN
    else:
        loglevel = logging.INFO
    logging.basicConfig(level=loglevel)

    rules = readrules(args.rulesfile)
    account_path = re.split(':', args.ac2fix)

    gnucash_session = Session(args.gnucash_file, is_new=False)
    total = 0
    imbalance = 0
    fixed = 0
    confirmed = None
    try:
        root_account = gnucash_session.book.get_root_account()
        orig_account = account_from_path(root_account, account_path)

        imbalance_pattern = re.compile(args.imbalance_ac)

        for split in orig_account.GetSplitList():
            total += 1
            trans = split.parent
            splits = trans.GetSplitList()
            trans_date = trans.GetDate().date()
            trans_desc = trans.GetDescription()
            trans_memo = trans.GetNotes()
            for split in splits:
                ac = split.GetAccount()
                acname = ac.GetName()
                amount = eval(str(split.GetAmount()))
                # "Debit balance accounts" are represented with a negative sign
                # internally, so the amounts need their signs flipped.
                # Refer to section 2.1.3 Debits and Credits in the GnuCash docs,
                # the rearranged accounting equation to see why.
                if account_path[0] in ('Assets', 'Expenses'):
                    amount = -amount
                logging.debug('%s: %s => %s', trans_date, trans_desc, acname)
                if imbalance_pattern.match(acname):
                    imbalance += 1
                    search_str = trans_desc
                    if args.use_memo:
                        search_str = trans_memo
                    newac = get_ac_from_str(search_str, rules, root_account)
                    if newac != "":
                        if args.confirm:
                            print(
                                bold + green + '\nFound a match!\n' + end +
                                '{}: "{}" = {:.2f}\nFix account "{}" to "{}"?'.
                                format(trans_date, cyan + trans_desc +
                                       end, amount, acname, cyan +
                                       newac.GetName() + end))
                            if confirmed != 'all':
                                confirmed = input(
                                    "Press ENTER to fix, "
                                    "'all' to fix all remaining, "
                                    "'s' to skip, 'q' to quit: ").lower(
                                    ).strip()
                            if confirmed == 'q':
                                print("Quitting...")
                                gnucash_session.end()
                                sys.exit()
                            elif confirmed not in ('', 'all'):
                                # If not ENTER, 'y', or 'all', then skip!
                                print("Skipping...")
                                continue
                            print("Fixing...")
                        logging.debug('\tChanging account to: %s',
                                      newac.GetName())
                        split.SetAccount(newac)
                        fixed += 1

        if not args.nochange:
            gnucash_session.save()

        logging.info('Total splits=%s, imbalance=%s, fixed=%s', total,
                     imbalance, fixed)

    except Exception as ex:
        logging.error(ex)

    gnucash_session.end()
Example #16
0
#!/usr/bin/env python3

##  @file
#   @brief Simple example for a book
#   @ingroup python_bindings_examples

import sys
from gnucash import Session

# We need to tell GnuCash the data format to create the new file as (xml://)
uri = "xml:///tmp/simple_book.gnucash"

print("uri:", uri)
ses = Session(uri, is_new=True)
book = ses.get_book()

#Call some methods that produce output to show that Book works
book.get_root_account().SetDescription("hello, book")
print("Book is saved:", not book.session_not_saved())

print("saving...")
ses.save()

print("Book is saved:", not book.session_not_saved())
ses.end()
Example #17
0
class Gnucash:
    __seendict = {}

    def __init__(self, book_uri):
        self._session = Session(book_uri=book_uri)
        self._book = self._session.book
        self._root_account = self._book.get_root_account()

        self._commodity_table = self._book.get_table()

        # todo: implement as class w/ getattr
        self.commods = {}
        self.commods["USD"] = self._commodity_table.lookup("ISO4217", "USD")

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self._session.end()

    def save(self):
        self._session.save()

    def seen(self, acct, num):
        if repr(acct) not in self.__seendict:
            l = []
            for split in acct.GetSplitList():
                txn = split.parent
                if txn.GetNum() not in l:
                    l.append(txn.GetNum().strip())
            self.__seendict[repr(acct)] = l

        return num in self.__seendict[repr(acct)]

    def _account_from_path(self, 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 self._account_from_path(account, account_path, original_path)
        else:
            return account

    def account(self, account_path):
        return self._account_from_path(self._root_account, account_path.split(":"))

    def rat(self, value):
        s = int(round(value * 100))
        return GncNumeric(s, 100)

    def NewTransaction(self):
        t = Transaction(self._book)
        t.BeginEdit()
        t.SetCurrency(self.commods["USD"])
        return t

    def NewSplit(self, txn, acct, amount):
        s = Split(self._book)
        s.SetParent(txn)
        s.SetAccount(acct)
        s.SetAmount(self.rat(amount))
        s.SetValue(self.rat(amount))
        return s

    def TransactionReadyToCommit(self, txn):
        for split in txn.GetSplitList():
            if split.GetValue().to_double() == 0.0:
                split.Destroy()

        return txn.IsBalanced()

    def InvoiceLookupByID(self, id):
        return self._book.InvoiceLookupByID(id)

    def PayInvoiceWithTransaction(self, invoice, txn, acct, gross, memo, num):
        invoice.BeginEdit()
        invoice.ApplyPayment(txn, acct, self.rat(-gross), self.rat(1), txn.RetDatePostedTS(), memo, num)
        invoice.CommitEdit()

    def ApplyPaymentToCustomer(self, customer, txn, post_acct, from_acct, gross, memo, num):
        customer.BeginEdit()
        customer.ApplyPayment(
            txn, None, post_acct, from_acct, self.rat(-gross), self.rat(1), txn.RetDatePostedTS(), memo, num, True
        )
        customer.CommitEdit()

    def GetCustomerByEmail(self, email):
        q = Query()
        q.search_for("gncCustomer")
        q.set_book(self._book)

        c = None

        for result in q.run():
            tmp = Customer(instance=result)
            if tmp.GetAddr().GetEmail().lower() == email.lower():
                c = tmp
                break

        q.destroy()

        return c
Example #18
0
split3.SetValue(num2)
split3.SetAccount(savings_acct)
split3.SetParent(trans2)

trans1.SetCurrency(cad)
trans1.SetDate(14, 3, 2006)
trans1.SetDescription("Groceries")

trans2.SetCurrency(cad)
trans2.SetDate(7, 11, 1995)
trans2.SetDescription("Opening Savings Balance")

split2 = Split(book)
split2.SetAccount(savings_acct)
split2.SetParent(trans1)
split2.SetValue(num1.neg())

split4 = Split(book)
split4.SetAccount(opening_acct)
split4.SetParent(trans2)
split4.SetValue(num2.neg())


trans1.CommitEdit()
trans2.CommitEdit()

session.save()
session.end()
session.destroy()
def main():

    if len(argv) < 3:
        print('not enough parameters')
        print(
            'usage: new_book_with_opening_balances.py {source_book_url} {destination_book_url}'
        )
        print('examples:')
        print(
            "gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'sqlite3:///home/username/new_test.gnucash'"
        )
        print(
            "gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'xml:///crypthome/username/finances/new_test.gnucash'"
        )
        return

    #have everything in a try block to unable us to release our hold on stuff to the extent possible
    try:
        original_book_session = Session(argv[1], is_new=False)
        new_book_session = Session(argv[2], is_new=True)
        new_book = new_book_session.get_book()
        new_book_root = new_book.get_root_account()

        commodtable = new_book.get_table()
        # we discovered that if we didn't have this save early on, there would
        # be trouble later
        new_book_session.save()

        opening_balance_per_currency = {}
        recursivly_build_account_tree(
            original_book_session.get_book().get_root_account(), new_book_root,
            new_book, commodtable, opening_balance_per_currency,
            ACCOUNT_TYPES_TO_OPEN)

        (namespace, mnemonic) = PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE
        if (namespace, mnemonic) in opening_balance_per_currency:
            opening_trans, opening_amount = opening_balance_per_currency[(
                namespace, mnemonic)]
            simple_opening_name_used = create_opening_balance_transaction(
                commodtable, namespace, mnemonic, new_book_root, new_book,
                opening_trans, opening_amount, False)
            del opening_balance_per_currency[
                PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE]
        else:
            simple_opening_name_used = False

        for (namespace, mnemonic), (opening_trans, opening_amount) in \
                opening_balance_per_currency.items() :
            simple_opening_name_used = create_opening_balance_transaction(
                commodtable, namespace, mnemonic, new_book_root, new_book,
                opening_trans, opening_amount, simple_opening_name_used)

        new_book_session.save()
        new_book_session.end()
        original_book_session.end()
    except:
        if "original_book_session" in locals():
            original_book_session.end()

        if "new_book_session" in locals():
            new_book_session.end()

        raise
Example #20
0
        session.end()
        session.destroy()
        quit()  # Or try next invoice
else:  # No currebt invoice found so create a new invoice TODO need to lookup next free Invoice ID perhaps?
    print "Creating a new invoice"
    invoice = Invoice(
        book, 'TEST', gbp, customer
    )  # I know, need to check of this exists too!!  But this is a test script so...
    # NB Gnucash will happily make another invoice/bill with the same ID!  I think this is a bad thing.
    invoice.SetDateOpened(datetime.date.today())

if invoice:  # Test code
    invoice.GetID()

# Create a new entry and populate it.  Normally there would be a loop for each entry required, reading from a csv or similar
entry = gnucash.gnucash_business.Entry(book, invoice)
entry.SetDate(datetime.date.today())
entry.SetDateEntered(datetime.date.today())
entry.SetDescription("Some stuff I sold")
entry.SetAction("Material")
entry.SetInvAccount(income)
entry.SetQuantity(GncNumeric(1))
gnc_price = GncNumeric(1040, 100)  ## = price x 100 then set denom to 100
entry.SetInvPrice(gnc_price)
#entry.SetInvTaxTable(tax_table)
entry.SetInvTaxIncluded(False)

session.save()  #
session.end()
session.destroy()
def main():
	if len(argv) < 4:
		print 'Usage: python ofxml_make_commodity_accounts.py <gnucash-file> <ofxml-file> <accountmap-file>'
		exit(1)
		
	gnucash_file=argv[1]
	
	doc=ElementTree(file=argv[2])
	
	acctids=doc.findall('./INVSTMTMSGSRSV1/INVSTMTTRNRS/INVSTMTRS/INVACCTFROM/ACCTID')
	if len(acctids)!=1:
		print 'ERROR: No unique account number found in OFX: found', len(acctids)
		return
	acctid=acctids[0].text.strip()
	acctcur='any'
	m=re.search('^(.*)-([A-Z]{3})$',acctid)
	if m:
		acctid=m.group(1)
		acctcur=m.group(2)
	print "INFO: Account number:", acctid, "Currency:", acctcur

	fitids={}
	for itran in doc.findall('.//INVBUY')+doc.findall('.//INVSELL')+doc.findall('.//REINVEST'):
		fitid=itran.find('./INVTRAN/FITID')
		if not fitid is None:
			fitid=fitid.text.strip()
		if fitid in fitids:
			print "ERROR: Non-unique FITID found:", fitid
			exit(1)
		fitids[fitid]=itran
		
	# Fantastic, the FITID is not saved by GnuCash for income transactions...
	# Index by (date,amount,memo) instead
	incometrns={}
	for itran in doc.findall('.//INCOME'):
		fields={}
		for path in ('INVTRAN/DTTRADE', 'INVTRAN/MEMO', 'TOTAL'):
			el=itran.find('./'+path)
			if not el is None and len(el.text.strip())>0:
				fields[path]=el.text.strip()
		if len(fields)!=3:
			print "ERROR: Can't create identifier for INCOME transaction, ignoring."
		incometrns[(fields['INVTRAN/DTTRADE'][0:8],fields['INVTRAN/MEMO'],Fraction(fields['TOTAL']))]=itran

	sess=Session(gnucash_file)
	
	try:
		# Find GNC parent account
		root=sess.book.get_root_account()
		matched_accts=find_acct_by_number_and_currency(root,acctid,acctcur)
		if len(matched_accts)==0:
			from_iban=conv_iban(acctid)
			if from_iban:
				matched_accts=find_acct_by_number_and_currency(root,from_iban,acctcur)
			
		if len(matched_accts)!=1:
			print 'ERROR: No unique account this number/currency; found', len(matched_accts)
			return
		
		acct=matched_accts[0]
		print 'DEBUG: Found parent account:',acct.GetName()
		
		accountmap=read_accountmap(argv[3],acct.GetCode()+'-'+acct.GetCommodity().get_mnemonic())

		# Find child Stock/Mutual accounts
		secaccts=[] # SwigPyObject is not Hashable :(
		for cacct in acct.get_descendants():
			atype=cacct.GetType()
			if atype==gnucash_core.ACCT_TYPE_STOCK or atype==gnucash_core.ACCT_TYPE_MUTUAL:
				secaccts.append(cacct.get_instance())
				
		# Find income accounts
		incaccts=[] # SwigPyObject is not Hashable :(
		for typ in accountmap:
			if typ[0:6]=="INCOME":
				inst=find_acct_by_path(root,accountmap[typ]).get_instance()
				if not (inst is None or inst in incaccts):
					incaccts.append(inst)

		if len(incaccts)==0 and len(incometrns)>0:
			print 'WARNING: no income accounts defined for account',acct.GetCode()+'-'+acct.GetCommodity().get_mnemonic()
			print 'WARNING: income transactions will not be fixed'

		# Go through all transactions
		for tran in _py_xaccSplitListGetUniqueTransactions(acct.GetSplitList()):
			# Consider fixing if transaction ...
			# ... has exactly 2 splits
			# ... has 1 split with a child Stock/Mutual account
			# ... has 1 split with an online ID
			splits=tran.GetSplitList()
			if len(splits)==2:
				cashsplit=None
				secsplit=None
				incsplit=None
				online_id=None
				for split in splits:
					if split.GetAccount().get_instance() in secaccts:
						secsplit=split
					if split.GetAccount().get_instance() in incaccts:
						incsplit=split
					if split.GetAccount().get_instance()==acct.get_instance():
						cashsplit=split
					oid=_py_gnc_import_get_split_online_id(sess,split)
					if not oid is None:
						if online_id is None:
							online_id=oid
						else:
							online_id=False
				if not (cashsplit is None or secsplit is None or online_id is None or online_id is False):
					if not online_id in fitids:
						# This can happen if we encounter a transaction outside of this OFX period
						#print 'DEBUG: FITID',online_id,'not found in OFX file.'
						continue
					fix_buysell_transaction(tran,secsplit,cashsplit,fitids[online_id],root,accountmap)
				elif not (cashsplit is None or incsplit is None):
					date=tran.RetDatePostedTS().strftime('%Y%m%d')
					memo=re.sub(' +',' ',tran.GetDescription()) # GnuCash importer likes to insert spaces randomly
					amt=gnc_numeric_to_fraction(cashsplit.GetAmount())
					if not (date,memo,amt) in incometrns:
						# This can happen if we encounter a transaction outside of this OFX period
						#print "DEBUG: No match for income transaction",date,memo,amt
						continue
					fix_income_transaction(tran,incsplit,cashsplit,incometrns[(date,memo,amt)],root,accountmap)

		wait_for_backup_file(gnucash_file)
		sess.save()
	except BaseException as e:
		print 'ERROR:',e
	finally:    
		sess.end()
		sess.destroy()
Example #22
0
def map_accounts(request):
    rows = request.session.get("rows", [])
    map = request.session.get("map", {})
    statement = request.session.get("statement", "bank")
    if statement == "bank":
        bank_account = settings.GNUCASH_BANK_ACCOUNT
    else:
        bank_account = settings.GNUCASH_CARD_ACCOUNT

    data = []
    for row in rows:
        new_row = {}
        for index, field in map.items():
            new_row[field] = row[int(index)]
        # @todo: split into debit/credit views
        if statement == "card" or (new_row["amount"].startswith("-")
                                   or "VIRTUALSTOCK" in new_row["account"]):
            data.append(new_row)

    AccountFormSet = formset_factory(AccountForm, extra=0)

    if request.method == "POST":
        session = Session(settings.GNUCASH_FILE)
        formset = AccountFormSet(request.POST,
                                 form_kwargs={'book': session.book})

        root = session.book.get_root_account()
        if statement == "bank":
            bank = root.lookup_by_name(settings.GNUCASH_BANK_ACCOUNT)
        else:
            bank = root.lookup_by_name(settings.GNUCASH_CARD_ACCOUNT)

        check = queries.get_duplicate_check_data(bank)
        log.debug(check)

        try:
            ok = dup = 0
            for form in formset.forms:
                if form.is_valid():
                    clean = form.cleaned_data
                    if [clean["date"], clean["amount"]] not in check:
                        create_split_transaction(
                            session.book,
                            bank_account,
                            str(clean["account"]),
                            clean["date"],
                            str(clean["description"]),
                            clean["amount"],
                            vat_incl=clean["vat_incl"],
                        )
                        ok += 1
                    else:
                        log.debug(
                            "Skipped %s %s %s" % (
                                clean["date"].strftime("%Y-%m-%d"),
                                clean["description"],
                                clean["amount"],
                            ), )
                        dup += 1

            session.save()
            messages.info(request,
                          "Successfully imported %s transactions" % ok)
            if dup:
                messages.warning(request,
                                 "Skipped %s duplicate transactions" % dup)

        except Exception as e:
            messages.error(request, e)

        finally:
            session.end()

        return HttpResponseRedirect(reverse("expenses-finish"))
    else:
        initial = []
        for row in data:
            account, vat_incl = queries.match_account(row.get("account"),
                                                      row.get("amount", 0))
            initial.append({
                "account": account,
                "amount": row.get("amount"),
                "date": row.get("date"),
                "description": row.get("account"),
                "vat_incl": vat_incl,
            })
        formset = AccountFormSet(initial=initial)

    return render(
        request,
        "importer/map-accounts.html",
        {
            "formset": formset,
            "rows": zip(data, formset.forms),
            "gnucash": settings.GNUCASH_FILE,
        },
    )
# command-line options
gnucash_filename = argv[1]
first_invoice_number = argv[2]
description = argv[3]
invoice_value = gnc_numeric_from_decimal(Decimal(argv[4]))
customer_ids = argv[5:]

#Check that the date is set correctly for a batch of invoices.
#Generally, the date should be set to the beginning of each month
#for the month of the billing period.

invoice_date = datetime.date(2012, 8, 1)

session = Session(gnucash_filename, is_new=False)
session.save() # this seems to make a difference in more complex cases

book = session.book
root_account = book.get_root_account()

commodity_table = book.get_table()
USD = commodity_table.lookup('CURRENCY', 'USD')

assets = root_account.lookup_by_name("Assets")
receivables = assets.lookup_by_name("Accounts Receivable")

# This assumes you have an income subaccount of the form "Income:Member Dues"
# The lookup fails if the parent account is specified.
# IE root_account.lookup_by_name("Income:Member Dues") does not work.

income = root_account.lookup_by_name("Member Dues")
def main():
    args = parse_cmdline()
    if args.version:
        print VERSION
        exit(0)

    if args.verbose:
        loglevel = logging.DEBUG
    elif args.quiet:
        loglevel = logging.WARN
    else:
        loglevel = logging.INFO
    logging.basicConfig(level=loglevel)

    rules = readrules(args.rulesfile, args.xml)

    account_path = re.split(':', args.ac2fix)

    gnucash_session = Session(args.gnucash_file, is_new=False)
    total = 0
    imbalance = 0
    fixed = 0
    try:
        root_account = gnucash_session.book.get_root_account()
        orig_account = account_from_path(root_account, account_path)

        imbalance_pattern = re.compile(args.imbalance_ac)

        for split in orig_account.GetSplitList():
            total += 1
            trans = split.parent
            splits = trans.GetSplitList()
            trans_date = date.fromtimestamp(trans.GetDate())
            trans_desc = trans.GetDescription()
            trans_memo = trans.GetNotes()
            for split in splits:
                ac = split.GetAccount()
                acname = ac.GetName()
                logging.debug('%s: %s => %s', trans_date, trans_desc, acname)
                if imbalance_pattern.match(acname):
                    imbalance += 1
                    search_str = trans_desc
                    if args.use_memo:
                        search_str = trans_memo
                    newac = get_ac_from_str(search_str, rules, root_account)
                    if newac != "":
                        logging.debug('\tChanging account to: %s',
                                      newac.GetName())
                        split.SetAccount(newac)
                        fixed += 1

        if not args.nochange:
            gnucash_session.save()

        logging.info('Total splits=%s, imbalance=%s, fixed=%s', total,
                     imbalance, fixed)

    except Exception as ex:
        logging.error(ex)

    gnucash_session.end()
Example #25
0
#!/usr/bin/env python3
##  @file
#   @brief Example Script simple sqlite create 
#   @ingroup python_bindings_examples

from gnucash import Session, Account
from os.path import abspath
from gnucash.gnucash_core_c import ACCT_TYPE_ASSET

s = Session('sqlite3://%s' % abspath('test.blob'), is_new=True)
# this seems to make a difference in more complex cases
s.save()

book = s.book
root = book.get_root_account()
a = Account(book)
root.append_child(a)
a.SetName('wow')
a.SetType(ACCT_TYPE_ASSET)

commod_table = book.get_table()
a.SetCommodity( commod_table.lookup('CURRENCY', 'CAD') )
s.save()

s.end()
def main():
	if len(argv) < 3:
		print 'Usage: python ofxml_make_commodity_accounts.py <gnucash-file> <ofxml-file> [symbols-file]'
		exit(1)
		
	gnucash_file=argv[1]
	
	symbols_file=False
	if len(argv)>=4:
		symbols_file=read_symbols(argv[3])
	
	doc=ElementTree(file=argv[2])
	
	acctids=doc.findall('./INVSTMTMSGSRSV1/INVSTMTTRNRS/INVSTMTRS/INVACCTFROM/ACCTID')
	if len(acctids)!=1:
		print 'ERROR: No unique account number found in OFX: found', len(acctids)
		return
	acctid=acctids[0].text.strip()
	acctcur='any'
	m=re.search('^(.*)-([A-Z]{3})$',acctid)
	if m:
		acctid=m.group(1)
		acctcur=m.group(2)
	print "INFO: Account number:", acctid, "Currency:", acctcur

	missing_symbols=False
	secs=[]
	for sec in doc.findall('./SECLISTMSGSRSV1/SECLIST/*/SECINFO'):
		id=sec.findall('./SECID/UNIQUEID')[0].text.strip()
		type=sec.findall('./SECID/UNIQUEIDTYPE')[0].text.strip()
		name=sec.findall('./SECNAME')[0].text.strip()
		symbol=sec.findall('./TICKER')
		if len(symbol):
			symbol=symbol[0].text.strip()
		else:
			symbol=None
		if symbols_file:
			if id in symbols_file[type]:
				name=symbols_file[type][id]['name']
				symbol=symbols_file[type][id]['symbol']
			else:
				print "WARNING: Missing symbol for", type, id, name, symbol
				missing_symbols=True
		secs.append({'id': id, 'type': type, 'name': name, 'symbol': symbol})

	print "DEBUG: Found", len(secs), "commodities."

	sess=Session(gnucash_file)
	
	try:
		# Make sure all the commodities exist
		ct=sess.book.get_table()
		
		for ns in ['CUSIP','ISIN']:
			for c in ct.get_commodities(ns):
				matched_sec=None
				for sec in secs:
					if sec['type']==ns and sec['id']==c.get_cusip():
						sec['c']=c
						break

		missing_secs=False
		for i,sec in enumerate(secs):
			if not 'c' in sec:
				print 'WARNING: Missing commodity', sec['type'],sec['id'],sec['name'],sec['symbol']
				missing_secs=True
				
		if missing_secs or missing_symbols:
			print 'ERROR: Missing symbols or commodities, aborting.'
			return
		
		# Find GNC parent account
		root=sess.book.get_root_account()
		matched_accts=find_acct_by_number_and_currency(root,acctid,acctcur)
		if len(matched_accts)==0:
			from_iban=conv_iban(acctid)
			if from_iban:
				matched_accts=find_acct_by_number_and_currency(root,from_iban,acctcur)
			
		if len(matched_accts)!=1:
			print 'ERROR: No unique account this number/currency; found', len(matched_accts)
			return
		
		acct=matched_accts[0]
		print 'DEBUG: Found parent account:',acct.GetName()
		
		# Make sure the account has the appropriate stock accounts
		created_accounts=0
		for sec in secs:
			matched_acct=None
			for secacct in acct.get_children():
				if secacct.GetCommodity().get_instance()==sec['c'].get_instance():
					matched_acct=secacct
					break
			if not matched_acct:
				secacct=Account(sess.book)
				if secacct:
					secacct.SetName(sec['name'])
					secacct.SetType(gnucash.ACCT_TYPE_STOCK)
					secacct.SetCommodity(sec['c'])
					secacct.SetCode(sec['id'])
					acct.append_child(secacct)
					created_accounts+=1
					print 'DEBUG: Created Account',sec['name']
				else:
					print 'ERROR: Error creating Account',sec['name']
					
		print 'INFO:',len(secs),'accounts total',created_accounts,'created.'
		
		wait_for_backup_file(gnucash_file)
		sess.save()
	except BaseException as e:
		print 'ERROR:',e
	finally:    
		sess.end()
		sess.destroy()
Example #27
0
  print('Need at least one Split to get currency info ... ')
  raise SystemExit
cur = ac.GetSplitList()[0].GetParent().GetCurrency()

# Get stock data
pl = pdb.get_prices(stock,cur)
if len(pl)<1:
  print('Need at least one database entry to clone ...')
  raise SystemExit

pl0 = pl[0]
for i in range(1,len(pl)):
  pdb.remove_price(pl[i])

for i in range(0,len(stock_date)):
  p_new = pl0.clone(book)
  p_new = gnucash.GncPrice(instance=p_new)
  print('Adding',i,stock_date[i],stock_price[i])
  p_new.set_time(stock_date[i])
  v = p_new.get_value()
  v.num = int(Fraction.from_float(stock_price[i]).limit_denominator(100000).numerator)
  v.denom = int(Fraction.from_float(stock_price[i]).limit_denominator(100000).denominator)
  p_new.set_value(v)
  p_new.set_source("Finance::Quotes::Historic")
  pdb.add_price(p_new)

# Clean up
session.save()
session.end()
session.destroy()
Example #28
0
from os.path import abspath
from sys import argv
import datetime
from datetime import timedelta
from gnucash import Session, Account, GncNumeric
from gnucash.gnucash_business import Customer, Employee, Vendor, Job, \
    Address, Invoice, Entry, TaxTable, TaxTableEntry, GNC_AMT_TYPE_PERCENT, \
    GNC_DISC_PRETAX
from gnucash.gnucash_core_c import \
    ACCT_TYPE_ASSET, ACCT_TYPE_RECEIVABLE, ACCT_TYPE_INCOME, \
    GNC_OWNER_CUSTOMER, ACCT_TYPE_LIABILITY

s = Session(argv[1], is_new=True)
# this seems to make a difference in more complex cases
s.save()

book = s.book
root = book.get_root_account()
commod_table = book.get_table()
CAD = commod_table.lookup('CURRENCY', 'CAD')

a = Account(book)
root.append_child(a)
a.SetName('Assets')
a.SetType(ACCT_TYPE_ASSET)
a.SetCommodity(CAD)

a2 = Account(book)
a.append_child(a2)
a2.SetName('Recievables')