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()
Beispiel #2
0
    def test_session_with_new_file(self):
        """create Session with new xml file"""
        from tempfile import TemporaryDirectory
        from urllib.parse import urlunparse
        with TemporaryDirectory() as tempdir:
            uri = urlunparse(("xml", tempdir, "tempfile", "", "", ""))
            with Session(uri, SessionOpenMode.SESSION_NEW_STORE) as ses:
                pass

            # try to open nonexistent file without NEW mode - should raise Exception
            uri = urlunparse(("xml", tempdir, "tempfile2", "", "", ""))
            with Session() as ses:
                with self.assertRaises(GnuCashBackendException):
                    ses.begin(uri, mode=SessionOpenMode.SESSION_NORMAL_OPEN)

            # try to open nonexistent file without NEW mode - should raise Exception
            # use deprecated arg is_new
            uri = urlunparse(("xml", tempdir, "tempfile2", "", "", ""))
            with Session() as ses:
                with self.assertRaises(GnuCashBackendException):
                    ses.begin(uri, is_new=False)

            uri = urlunparse(("xml", tempdir, "tempfile3", "", "", ""))
            with Session() as ses:
                ses.begin(uri, mode=SessionOpenMode.SESSION_NEW_STORE)

            # test using deprecated args
            uri = urlunparse(("xml", tempdir, "tempfile4", "", "", ""))
            with Session() as ses:
                ses.begin(uri, is_new=True)
Beispiel #3
0
 def test_get_book_from_current_session(self):
     from gnucash import _sw_app_utils
     from gnucash import Book
     self.ses_instance = _sw_app_utils.gnc_get_current_session()
     self.ses = Session(instance=self.ses_instance)
     self.book = self.ses.get_book()
     self.assertIsInstance(obj=self.book, cls=Book)
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()
Beispiel #5
0
class CommoditySession(TestCase):
    def setUp(self):
        self.ses = Session()
        self.book = self.ses.get_book()
        self.table = self.book.get_table()

    def tearDown(self):
        self.ses.end()
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()
Beispiel #7
0
class TestCommands(TestCase):
    def setUp(self):
        self.session = Session(
            os.path.join(os.path.dirname(os.path.abspath(__file__)),
                         "test.gnucash"))

    def tearDown(self):
        self.session.end()

    def test_create_split_transaction_vat(self):
        commands.create_split_transaction(
            self.session.book,
            settings.GNUCASH_BANK_ACCOUNT,
            "Internet",
            date.today(),
            "ADSL",
            Decimal("539.00"),
        )

    def test_create_split_transaction_novat(self):
        commands.create_split_transaction(
            self.session.book,
            settings.GNUCASH_BANK_ACCOUNT,
            "Internet",
            date.today(),
            "ADSL",
            Decimal("539.00"),
            False,
        )

    def test_pay_invoice(self):
        commands.pay_invoice(self.session.book, "000002", Decimal("99.99"),
                             date.today())

    def test_pay_invoice_exists(self):
        self.assertRaises(
            PaymentExists,
            commands.pay_invoice,
            self.session.book,
            "000001",
            Decimal("9.99"),
            date.today(),
        )

    def test_apply_payment(self):
        commands.apply_payment(self.session.book, "000001", Decimal("99.99"),
                               date.today())

    def test_apply_payment_exists(self):
        self.assertRaises(
            PaymentExists,
            commands.apply_payment,
            self.session.book,
            "000001",
            Decimal("9.99"),
            date(2019, 11, 21),
        )
Beispiel #8
0
 def __init__(self, file, currency, is_new=False):
     self.session = Session(file, is_new)
     try:
         self.book = self.session.book
         self.commod_tab = self.book.get_table()
         self.currency = self.commod_tab.lookup('ISO4217', currency)
         self.root = self.book.get_root_account()
     except Exception as ex:
         pass
Beispiel #9
0
def customer_choices(book=None):
    choices = [("", "---------")]
    if not book:
        session = Session(settings.GNUCASH_FILE)
        book = session.book
    for c in queries.get_customers(book):
        choices.append((c.GetID(), c.GetName()))
    if "session" in locals():
        session.end()
    return choices
Beispiel #10
0
def account_choices(book=None):
    choices = [("", "---------")]
    if not book:
        session = Session(settings.GNUCASH_FILE)
        book = session.book
    for ac in queries.get_accounts(book.get_root_account()):
        choices.append((ac.name, ac.name))
    if "session" in locals():
        session.end()
    return choices
Beispiel #11
0
    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")
Beispiel #12
0
    def setUp(self):
        self.util = Util()
        self.account = Nubank(self.util.DEFAULT_ACCOUNT_SRC_FILE)
        self.ledger = Ledger(self.account, self.util.DEFAULT_CURRENCY, False,
                             self.util.DEFAULT_GNUCASH_FILE)

        session = Session(self.util.DEFAULT_GNUCASH_FILE)
        self.book = session.book
        self.currency = self.book.get_table().lookup(
            'ISO4217', self.util.DEFAULT_CURRENCY)
        session.end()
Beispiel #13
0
class GnucashBook(object):
    """docstring for GnucashBook."""
    def __init__(self, file, currency, is_new=False):
        self.session = Session(file, is_new)
        try:
            self.book = self.session.book
            self.commod_tab = self.book.get_table()
            self.currency = self.commod_tab.lookup('ISO4217', currency)
            self.root = self.book.get_root_account()
        except Exception as ex:
            pass
#            logging.error(ex)

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

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

    def write_transactions(self, transactions):
        for transaction in transactions:

            tx = Transaction(self.book)
            tx.BeginEdit()
            tx.SetCurrency(self.currency)
            tx.SetDateEnteredTS(datetime.datetime.now())
            tx.SetDatePostedTS(transaction.datetime)
            tx.SetDescription(transaction.description)
            tx.SetNotes(transaction.note)

            for split in transaction.splits:
                sp = Split(self.book)
                sp.SetParent(tx)
                sp.SetAccount(GnucashBook.lookup_account(self, split.account))
                sp.SetMemo(split.memo)
                amount = int(
                    Decimal(split.amount) * self.currency.get_fraction())
                sp.SetValue(GncNumeric(amount, self.currency.get_fraction()))
                sp.SetAmount(GncNumeric(amount, self.currency.get_fraction()))

            tx.CommitEdit()

    def close(self, nochange):
        if not nochange:
            self.session.save()
        self.session.end()
Beispiel #14
0
 def _loadarchive(self):
     if self._cache is not None:
         return
     session      = Session(self.url, True, False, False)
     root         = session.book.get_root_account()
     book         = session.book
     account      = book.get_root_account()
     commod_table = book.get_table()
     pdb          = book.get_price_db()
     df           = full_price_list(commod_table, pdb)
     df['value']  = df['num'] * 1.0 / df['denom']
     session.end()
     session.destroy()
     self._cache  = dropdupe(df, ['date', 'namespace', 'commod'])
Beispiel #15
0
    def __init__(self, fmon, gnc_file, mode):
        self.prod = (mode == PROD)
        self.mon_file = fmon

        self.session = Session(gnc_file)
        self.book = self.session.book

        self.root = self.book.get_root_account()
        self.root.get_instance()

        self.price_db = self.book.get_price_db()

        commod_tab = self.book.get_table()
        self.currency = commod_tab.lookup("ISO4217", "CAD")
Beispiel #16
0
def sessionForFile(input_file):
    try:
        return Session(os.path.abspath(input_file))
    except GnuCashBackendException, backend_exception:
        if ERR_BACKEND_LOCKED in backend_exception.errors:
            eprint("Cannot open %s, file is locked." % input_file)
        raise
Beispiel #17
0
def create_transactions(args, conf, url, txs, dry_run):

  try:
    session = Session(url, ignore_lock=True)
  except GnuCashBackendException, backend_exception:
    print "Error: %s" % backend_exception
    exit(1)
Beispiel #18
0
    def gnc_open(cls, path=None):

        if GncFile.status:
            return GncFile.status
        else:
            if path is not None:
                GncFile.path = path
            else:
                path = GncFile.path
            if not os.path.exists(path):
                print """GnuCash file (%s) does not exist. """ % path
                raise Exception('GnuCash file missing')
            if os.path.exists(path + '.LCK'):
                print """Lock file exists. Is GNUCash running?\n"""
                raise Exception('GnuCash locked')

            try:
                GncFile.s = Session(GncFile.path, is_new=False)
            except:
                raise Exception('Could not open GnuCash file')

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

            GncFile.status = True
            return GncFile.status
    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 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
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()
Beispiel #22
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()
Beispiel #23
0
class TestSession(TestCase):
    def test_create_empty_session(self):
        self.ses = Session()

    def test_session_deprecated_arguments(self):
        """use deprecated arguments ignore_lock, is_new, force_new"""
        self.ses = Session(ignore_lock=False, is_new=True, force_new=False)

    def test_session_mode(self):
        """use mode argument"""
        self.ses = Session(mode=SessionOpenMode.SESSION_NORMAL_OPEN)

    def test_session_with_new_file(self):
        """create Session with new xml file"""
        from tempfile import TemporaryDirectory
        from urllib.parse import urlunparse
        with TemporaryDirectory() as tempdir:
            uri = urlunparse(("xml", tempdir, "tempfile", "", "", ""))
            with Session(uri, SessionOpenMode.SESSION_NEW_STORE) as ses:
                pass

            # try to open nonexistent file without NEW mode - should raise Exception
            uri = urlunparse(("xml", tempdir, "tempfile2", "", "", ""))
            with Session() as ses:
                with self.assertRaises(GnuCashBackendException):
                    ses.begin(uri, mode=SessionOpenMode.SESSION_NORMAL_OPEN)

            # try to open nonexistent file without NEW mode - should raise Exception
            # use deprecated arg is_new
            uri = urlunparse(("xml", tempdir, "tempfile2", "", "", ""))
            with Session() as ses:
                with self.assertRaises(GnuCashBackendException):
                    ses.begin(uri, is_new=False)

            uri = urlunparse(("xml", tempdir, "tempfile3", "", "", ""))
            with Session() as ses:
                ses.begin(uri, mode=SessionOpenMode.SESSION_NEW_STORE)

            # test using deprecated args
            uri = urlunparse(("xml", tempdir, "tempfile4", "", "", ""))
            with Session() as ses:
                ses.begin(uri, is_new=True)

    def test_app_utils_get_current_session(self):
        from gnucash import _sw_app_utils
        self.ses_instance = _sw_app_utils.gnc_get_current_session()
        self.ses = Session(instance=self.ses_instance)
        self.assertIsInstance(obj=self.ses, cls=Session)

    def test_get_book_from_current_session(self):
        from gnucash import _sw_app_utils
        from gnucash import Book
        self.ses_instance = _sw_app_utils.gnc_get_current_session()
        self.ses = Session(instance=self.ses_instance)
        self.book = self.ses.get_book()
        self.assertIsInstance(obj=self.book, cls=Book)
    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 __init__(self):
        if os.path.exists(self._path + '.LCK'):
            raise AssertionError("""Lock file exists. Is GNUCash running?\n""")

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

        self._root = self.getBook().get_root_account()
        self._commod = self.getBook().get_table()
        self._currency = self._commod.lookup('CURRENCY', 'USD')
Beispiel #26
0
    def runTest(self):
        self.instrument_main()

        try:
            from accregex import Account
            from accregex.AccountUtil import gnc_numeric_to_python_Decimal
            from gnucash import Session
            session = Session(AccregexTest.reg_doc_example, is_new=False, ignore_lock=False)
            parking_expense_account = Account.get_account(session.book.get_root_account(), parking_expense_account_full_name)
            actual_balance = gnc_numeric_to_python_Decimal(parking_expense_account.GetBalance())
            expected_balance = Decimal(25)

            self.assertEqual(actual_balance, expected_balance)
            
            #TODO: check that the actual transaction in Assets:Current Assets:Checking Account was changed
            session.end()
            
            #put the gnucash file back the way we found it
            shutil.move(AccregexTest.reg_doc_example + ".bak", AccregexTest.reg_doc_example)
        except:
            #in case of error close the session and re-raise
            #equivalent to a "finally" block
            if "session" in locals():
                session.end()
            raise
Beispiel #27
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 = 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()
Beispiel #29
0
def open_book(gnucashfile, account2fix):
    """Read a GNU Cash file

    :param gnucashfile: path to the GNU Cash file
    :param account2fix: list with the path of the account
    :returns: session object, root account and origin account
    :rtype:

    """
    gnucash_session = Session(gnucashfile, is_new=False)
    root_account = gnucash_session.book.get_root_account()
    orig_account = account_from_path(root_account, account2fix)
    return (gnucash_session, root_account, orig_account)
Beispiel #30
0
def find_av_main():
    exe = argv[0].split('/')[-1]
    if len(argv) < 6:
        print("NOT ENOUGH parameters!")
        print("usage: {} <book url> <year> <month> <day> <space-separated path to the account of interest>".format(exe))
        print("PROGRAM EXIT!")
        return

    print("\nrunning {} at run-time: {}\n".format(exe, str(datetime.now())))

    global gnucash_session
    try:
        (gnucash_file, str_year, str_month, str_day) = argv[1:5]
        print("find asset values in {} on {}-{}-{}".format(gnucash_file, str_year, str_month, str_day))

        val_year, val_month, val_day = [int(blah) for blah in (str_year, str_month, str_day)]
        date_of_interest = date(val_year, val_month, val_day)

        account_path = argv[5:]
        print("account_path = {}\n".format(str(account_path)))

        gnucash_session = Session(gnucash_file, is_new=False)
        book = gnucash_session.book

        commod_tab = book.get_table()
        # noinspection PyPep8Naming
        CAD = commod_tab.lookup("ISO4217", "CAD")

        root_account = book.get_root_account()

        account_of_interest = account_from_path(root_account, account_path)
        acct_name = account_of_interest.GetName()

        total = get_asset_balance(account_of_interest, date_of_interest, CAD)

        # get the list of all descendant accounts
        descendants = account_of_interest.get_descendants()

        if len(descendants) > 0:
            # get the values for EACH sub-account too
            print("\nDescendants of {}:".format(acct_name))
            for subAcct in descendants:
                total += get_asset_balance(subAcct, date_of_interest, CAD)

        print("total {} value = {}${}".format(acct_name, CAD.get_mnemonic(), total))

        # no save needed, we're just reading...
        gnucash_session.end()

    except Exception as ae:
        print("Exception: {}".format(ae))
        if "gnucash_session" in locals() and gnucash_session is not None:
            gnucash_session.end()

    print("\n >>> PROGRAM ENDED.")
Beispiel #31
0
class TestSession(TestCase):
    def test_create_empty_session(self):
        self.ses = Session()

    def test_app_utils_get_current_session(self):
        from gnucash import _sw_app_utils
        self.ses_instance = _sw_app_utils.gnc_get_current_session()
        self.ses = Session(instance=self.ses_instance)
        self.assertIsInstance(obj=self.ses, cls=Session)

    def test_get_book_from_current_session(self):
        from gnucash import _sw_app_utils
        from gnucash import Book
        self.ses_instance = _sw_app_utils.gnc_get_current_session()
        self.ses = Session(instance=self.ses_instance)
        self.book = self.ses.get_book()
        self.assertIsInstance(obj=self.book, cls=Book)
 def handle(self, *args, **options):
     try:
         s = Session(settings.GNUCASH_FILE)
         book = s.book
         with open(args[0], "r") as f:
             reader = csv.DictReader(f)
             for row in reader:
                 number = row["invoice"]
                 amount = Decimal(row["amount"])
                 date = parser.parse(row["date"])
                 try:
                     pay_invoice(book, number, amount, date)
                 except PaymentExists as e:
                     print("%s... skipping" % e)
         s.save()
     finally:
         s.end()
Beispiel #33
0
def open_gnucash(gnucash_file):
    from gnucash import Session
    from financespy import gnucash_backend
    from financespy.gnucash_backend import GnucashBackend

    path = Path(gnucash_file)
    metadata_file = re.sub("[.]gnucash$", ".json", path.name)
    metadata = read_metadata(str(path.parent / metadata_file))

    session = Session(gnucash_file)

    gnucash_account = gnucash_backend.account_for(
        session, metadata.properties["account_backend"]
    )

    if not metadata.categories:
        metadata.categories = gnucash_backend.categories_from(
            session, metadata.properties["account_categories"]
        )

    backend = GnucashBackend(session=session, account=gnucash_account)

    return Account(backend, metadata)
Beispiel #34
0
 def test_create_empty_session(self):
     self.ses = Session()
Beispiel #35
0
 def test_session_deprecated_arguments(self):
     """use deprecated arguments ignore_lock, is_new, force_new"""
     self.ses = Session(ignore_lock=False, is_new=True, force_new=False)
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()
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()
Beispiel #38
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()
Beispiel #39
0
    
    data.append(tmp)

f.close()

stock_date = []
stock_price = []
for i in range(1,len(data)):
    year = int(data[i].rsplit(',')[1].rsplit('/')[0])
    month = int(data[i].rsplit(',')[1].rsplit('/')[1])
    day = int(data[i].rsplit(',')[1].rsplit('/')[2])
    stock_date.append(datetime.datetime(year,month,day))
    stock_price.append(float(data[i].rsplit(',')[5]))

# Initialize Gnucash session
session = Session(url, True, False, False)
root = session.book.get_root_account()
book = session.book
account = book.get_root_account()
pdb = book.get_price_db()
comm_table = book.get_table()
ac = find_account(account,'Intel')[0] 

stock = ac.GetCommodity()
# Add the prices
pdb = book.get_price_db()
if len(ac.GetSplitList())<1:
  print('Need at least one Split to get currency info ... ')
  raise SystemExit
cur = ac.GetSplitList()[0].GetParent().GetCurrency()
Beispiel #40
0
 def test_app_utils_get_current_session(self):
     from gnucash import _sw_app_utils
     self.ses_instance = _sw_app_utils.gnc_get_current_session()
     self.ses = Session(instance=self.ses_instance)
     self.assertIsInstance(obj=self.ses, cls=Session)
Beispiel #41
0
 def setUp(self):
     self.ses = Session()
     self.book = self.ses.get_book()
     self.table = self.book.get_table()
     self.currency = self.table.lookup('CURRENCY', 'EUR')
def main():

    if len(argv) < 10:
        print('not enough parameters')
        print('usage: account_analysis.py {book url} {start year} {start month, numeric} {period type: monthly, quarterly, or yearly} {number of periods to show, from start year and month} {whether to show debits: debits-show for true, all other values false} {whether to show credits: credits-show for true, all other values false} {space separated account path, as many nested levels as desired} ')
        print('examples:\n')
        print("The following example analyzes 12 months of 'Assets:Test Account' from /home/username/test.gnucash, starting in January of 2010, and shows both credits and debits")
        print("gnucash-env python account_analysis.py '/home/username/test.gnucash' 2010 1 monthly 12 debits-show credits-show Assets 'Test Account'\n")
        print("The following example analyzes 2 quarters of 'Liabilities:First Level:Second Level' from /home/username/test.gnucash, starting March 2011, and shows credits but not debits")
        print("gnucash-env python account_analysis.py '/home/username/test.gnucash' 2011 3 quarterly 2 debits-noshow credits-show Liabilities 'First Level' 'Second Level")
        return

    try:
        (gnucash_file, start_year, start_month, period_type, periods,
         debits_show, credits_show) = argv[1:8]
        start_year, start_month, periods = [int(blah)
                                            for blah in (start_year, start_month,
                                                         periods) ]

        debits_show = debits_show == DEBITS_SHOW
        credits_show = credits_show == CREDITS_SHOW

        account_path = argv[8:]

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

        # a list of all the periods of interest, for each period
        # keep the start date, end date, a list to store debits and credits,
        # and sums for tracking the sum of all debits and sum of all credits
        period_list = [
            [start_date, end_date,
             [], # debits
             [], # credits
             ZERO, # debits sum
             ZERO, # credits sum
             ]
            for start_date, end_date in generate_period_boundaries(
                start_year, start_month, period_type, periods)
            ]
        # a copy of the above list with just the period start dates
        period_starts = [e[0] for e in period_list ]

        # insert and add all splits in the periods of interest
        for split in account_of_interest.GetSplitList():
            trans = split.parent
            trans_date = date.fromtimestamp(trans.GetDate())

            # use binary search to find the period that starts before or on
            # the transaction date
            period_index = bisect_right( period_starts, trans_date ) - 1

            # ignore transactions with a date before the matching period start
            # (after subtracting 1 above start_index would be -1)
            # and after the last period_end
            if period_index >= 0 and \
                    trans_date <= period_list[len(period_list)-1][1]:

                # get the period bucket appropriate for the split in question
                period = period_list[period_index]

                # more specifically, we'd expect the transaction date
                # to be on or after the period start, and  before or on the
                # period end, assuming the binary search (bisect_right)
                # assumptions from above are are right..
                #
                # in other words, we assert our use of binary search
                # and the filtered results from the above if provide all the
                # protection we need
                assert( trans_date>= period[0] and trans_date <= period[1] )

                split_amount = gnc_numeric_to_python_Decimal(split.GetAmount())

                # if the amount is negative, this is a credit
                if split_amount < ZERO:
                    debit_credit_offset = 1
                # else a debit
                else:
                    debit_credit_offset = 0

                # store the debit or credit Split with its transaction, using the
                # above offset to get in the right bucket
                #
                # if we wanted to be really cool we'd keep the transactions
                period[2+debit_credit_offset].append( (trans, split) )

                # add the debit or credit to the sum, using the above offset
                # to get in the right bucket
                period[4+debit_credit_offset] += split_amount

        csv_writer = csv.writer(stdout)
        csv_writer.writerow( ('period start', 'period end', 'debits', 'credits') )

        def generate_detail_rows(values):
            return (
                ('', '', '', '', trans.GetDescription(),
                 gnc_numeric_to_python_Decimal(split.GetAmount()))
                for trans, split in values )


        for start_date, end_date, debits, credits, debit_sum, credit_sum in \
                period_list:
            csv_writer.writerow( (start_date, end_date, debit_sum, credit_sum) )

            if debits_show and len(debits) > 0:
                csv_writer.writerow(
                    ('DEBITS', '', '', '', 'description', 'value') )
                csv_writer.writerows( generate_detail_rows(debits) )
                csv_writer.writerow( () )
            if credits_show and len(credits) > 0:
                csv_writer.writerow(
                    ('CREDITS', '', '', '', 'description', 'value') )
                csv_writer.writerows( generate_detail_rows(credits) )
                csv_writer.writerow( () )

        # no save needed, we're just reading..
        gnucash_session.end()
    except:
        if "gnucash_session" in locals():
            gnucash_session.end()

        raise
Beispiel #43
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()
Beispiel #44
0
def main():
    (gnucash_file, start_year, start_month, period_type, periods,
     debits_show, credits_show) = argv[1:8]
    start_year, start_month, periods = [int(blah)
                                        for blah in (start_year, start_month,
                                                     periods) ]

    debits_show = debits_show == DEBITS_SHOW
    credits_show = credits_show == CREDITS_SHOW

    account_path = argv[8:]

    gnucash_session = Session("sqlite3://%s" % gnucash_file, is_new=False)
    root_account = gnucash_session.book.get_root_account()
    account_of_interest = account_from_path(root_account, account_path)

    # a list of all the periods of interest, for each period
    # keep the start date, end date, a list to store debits and credits,
    # and sums for tracking the sum of all debits and sum of all credits
    period_list = [
        [start_date, end_date,
         [], # debits
         [], # credits
         ZERO, # debits sum
         ZERO, # credits sum
         ]
        for start_date, end_date in generate_period_boundaries(
            start_year, start_month, period_type, periods)
        ]
    # a copy of the above list with just the period start dates
    period_starts = [e[0] for e in period_list ]
    
    # insert and add all splits in the periods of interest
    for split in account_of_interest.GetSplitList():
        split = Split(instance=split)
        trans = split.parent
        trans_date = date.fromtimestamp(trans.GetDate())

        # use binary search to find the period that starts before or on
        # the transaction date
        period_index = bisect_right( period_starts, trans_date ) - 1
        
        # ignore transactions with a date before the matching period start
        # (after subtracting 1 above start_index would be -1)
        # and after the last period_end
        if period_index >= 0 and \
                trans_date <= period_list[len(period_list)-1][1]:

            # get the period bucket appropriate for the split in question
            period = period_list[period_index]

            # more specifically, we'd expect the transaction date
            # to be on or after the period start, and  before or on the
            # period end, assuming the binary search (bisect_right)
            # assumptions from above are are right..
            #
            # in other words, we assert our use of binary search
            # and the filtered results from the above if provide all the
            # protection we need
            assert( trans_date>= period[0] and trans_date <= period[1] )
            
            split_amount = gnc_numeric_to_python_Decimal(split.GetAmount())

            # if the amount is negative, this is a credit
            if split_amount < ZERO:
                debit_credit_offset = 1
            # else a debit
            else:
                debit_credit_offset = 0

            # store the debit or credit Split with its transaction, using the
            # above offset to get in the right bucket
            #
            # if we wanted to be really cool we'd keep the transactions
            period[2+debit_credit_offset].append( (trans, split) )
    
            # add the debit or credit to the sum, using the above offset
            # to get in the right bucket
            period[4+debit_credit_offset] += split_amount

    csv_writer = csv.writer(stdout)
    csv_writer.writerow( ('period start', 'period end', 'debits', 'credits') )
    
    def generate_detail_rows(values):
        return (
            ('', '', '', '', trans.GetDescription(),
             gnc_numeric_to_python_Decimal(split.GetAmount()))
            for trans, split in values )
            

    for start_date, end_date, debits, credits, debit_sum, credit_sum in \
            period_list:
        csv_writer.writerow( (start_date, end_date, debit_sum, credit_sum) )

        if debits_show and len(debits) > 0:
            csv_writer.writerow(
                ('DEBITS', '', '', '', 'description', 'value') )
            csv_writer.writerows( generate_detail_rows(debits) )
            csv_writer.writerow( () )
        if credits_show and len(credits) > 0:
            csv_writer.writerow(
                ('CREDITS', '', '', '', 'description', 'value') )
            csv_writer.writerows( generate_detail_rows(credits) )
            csv_writer.writerow( () )

    # no save needed, we're just reading..
    gnucash_session.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()
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
Beispiel #47
0
 def test_session_mode(self):
     """use mode argument"""
     self.ses = Session(mode=SessionOpenMode.SESSION_NORMAL_OPEN)
Beispiel #48
0
class BookSession( TestCase ):
    def setUp(self):
        self.ses = Session()
        self.book = self.ses.get_book()
class DenhacGncSession:
    _path = envproperties.gnucdbstring
    _session = None
    _root = None
    _commod = None
    _currency = None

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

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self._session = Session(self._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

# 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.
from gnucash import Session

# -------------------------------------------
# Configuration options can be changed here :

cur_mnemonic="EUR"                      # Currency that prices are shown in. Possibilities include "EUR","GBP",...
namespace_name = ""                     # If no namespace_name is set, all namespaces will be shown
show_prices = True                      # If True, all prices for commodity are shown
commodity_fullname = ""                 # If no name is given, all commoditys in namespace will be shown
FILE = "PATH_TO_YOUR_TEST_FILE"         # File is not saved but use a copy anyway

# Configuration end
# -------------------------------------------

session = Session(FILE, True, False, False)

root = session.book.get_root_account()
book = session.book
pdb = book.get_price_db()
comm_table = book.get_table()

cur = comm_table.lookup("CURRENCY", cur_mnemonic)
cur_name = cur.get_fullname()


if namespace_name != "":                    # Show single namespace
  namespaces [ comm_table.find_namespace(namespace_name) ]

else:                                 # Show all namespaces
  namespaces=comm_table.get_namespaces_list()
Beispiel #52
0
class GnuCash():
    """ 

    In "/home/user/.odontuxrc" lies the odontux configuration, that tells
    about gnucash.
    
    In order that several dentists may use odontux together, the 
    "profissionnalaccounting_url", which specify the gnucash account place is 
    store in the user (ROLE_DENTIST) session :
    "models.users.OdontuxUser.profissionnalaccounting_url".
    
    The inside of gnucash needs at least :
        * assets  ( all of the dentist assets )
            * receivables  ( what the patient owes to the dentist )
            * dentalfund  ( what the patient paid to the dentist, but ain't 
                            usable right away ; needs to pass by the bank )
        * incomes  ( all of the dentist incomes )
            * dentalincomes  ( incomes coming from dental practice activity )

    While coding the assistant/secretary salary, the buying of dental supplies
    and all, we'll add "outcomes", liabilities...

    See commands/compta.py for :
        * assets
            * dentalfund
            * check
            * cash
            * card
            * transfer
            * paypal
    """
    def __init__(self, patient_id, dentist_id):
        self.parser = ConfigParser.ConfigParser()
        home = os.path.expanduser("~")
        self.parser.read(os.path.join(home, ".odontuxrc"))
        self.dentist = ( meta.session.query(users.OdontuxUser)
            .filter(users.OdontuxUser.id == dentist_id)
            .one()
        )
        profissionnalaccounting_url = self.dentist.gnucash_url.encode("utf_8")
        if profissionnalaccounting_url[-3:] == "xml":
            self.gnucashtype = "xml"
        elif "postgresql" in profissionnalaccounting_url.split("://"):
            self.gnucashtype = "postgresql"
        else:
            self.gnucashtype = "xml"

        assets = constants.ASSETS
        receivables = constants.RECEIVABLES
        dentalfund = constants.DENTAL_FUND

        incomes = constants.INCOMES
        dentalincomes = constants.DENTAL_INCOMES

        # Precise on which patient we'll work on
        self.patient_id = patient_id
        self.patient = meta.session.query(administration.Patient).filter(
                                administration.Patient.id == patient_id).one()

        # Set the gnucash patient_id
        self.gcpatient_id = "pat_" + str(self.patient_id)
        # Set up the Book for accounting
        self.gcsession = GCSession(profissionnalaccounting_url, True)
        self.book = self.gcsession.get_book()

        # set the currency we'll use
        currency = constants.GNUCASH_CURRENCY
        commod_tab = self.book.get_table()
        self.currency = commod_tab.lookup("CURRENCY", currency)

        # Set up the root on accounting book
        self.root = self.book.get_root_account()
        # Assets
        self.assets = self.root.lookup_by_name(assets)
        # What the patient owes to dental office
        self.receivables = self.assets.lookup_by_name(receivables)
        if not self.receivables.lookup_by_name(self.gcpatient_id):
            self.patient_receivables = Account(self.book)
            self.receivables.append_child(self.patient_receivables)
            self.patient_receivables.SetName(self.gcpatient_id)
            self.patient_receivables.SetType(gnc_core_c.ACCT_TYPE_RECEIVABLE)
            self.patient_receivables.SetCommodity(self.currency)
        else:
            self.patient_receivables = self.receivables.lookup_by_name(
                                                            self.gcpatient_id)
        # What the patient paid to dental office, but not usable
        # because it needs to pass by the bank.
        # the detail of dental fund is build in commands/compta.py
        # while getting the paymenttype.
        self.dentalfund = self.assets.lookup_by_name(dentalfund)
        # Incomes
        self.incomes = self.root.lookup_by_name(incomes)
        self.dentalincomes = self.incomes.lookup_by_name(dentalincomes)

    def gnc_numeric_from_decimal(self, decimal_value):
        sign, digits, exponent = decimal_value.as_tuple()

        # convert decimal digits to a fractional numerator
        # equivlent to
        # numerator = int(''.join(digits))
        # but without the wated conversion to string and back,
        # this is probably the same algorithm int() uses
        numerator = 0
        TEN = int(Decimal(0).radix()) # this is always 10
        numerator_place_value = 1
        # add each digit to the final value multiplied by the place value
        # from least significant to most sigificant
        for i in xrange(len(digits)-1,-1,-1):
            numerator += digits[i] * numerator_place_value
            numerator_place_value *= TEN

        if decimal_value.is_signed():
            numerator = -numerator

        # if the exponent is negative, we use it to set the denominator
        if exponent < 0 :
            denominator = TEN ** (-exponent)
        # if the exponent isn't negative, we bump up the numerator
        # and set the denominator to 1
        else:
            numerator *= TEN ** exponent
            denominator = 1

        return GncNumeric(numerator, denominator)
Beispiel #53
0
 def setUp(self):
     self.ses = Session()
     self.book = self.ses.get_book()
Beispiel #54
0
    def __init__(self, patient_id, dentist_id):
        self.parser = ConfigParser.ConfigParser()
        home = os.path.expanduser("~")
        self.parser.read(os.path.join(home, ".odontuxrc"))
        self.dentist = ( meta.session.query(users.OdontuxUser)
            .filter(users.OdontuxUser.id == dentist_id)
            .one()
        )
        profissionnalaccounting_url = self.dentist.gnucash_url.encode("utf_8")
        if profissionnalaccounting_url[-3:] == "xml":
            self.gnucashtype = "xml"
        elif "postgresql" in profissionnalaccounting_url.split("://"):
            self.gnucashtype = "postgresql"
        else:
            self.gnucashtype = "xml"

        assets = constants.ASSETS
        receivables = constants.RECEIVABLES
        dentalfund = constants.DENTAL_FUND

        incomes = constants.INCOMES
        dentalincomes = constants.DENTAL_INCOMES

        # Precise on which patient we'll work on
        self.patient_id = patient_id
        self.patient = meta.session.query(administration.Patient).filter(
                                administration.Patient.id == patient_id).one()

        # Set the gnucash patient_id
        self.gcpatient_id = "pat_" + str(self.patient_id)
        # Set up the Book for accounting
        self.gcsession = GCSession(profissionnalaccounting_url, True)
        self.book = self.gcsession.get_book()

        # set the currency we'll use
        currency = constants.GNUCASH_CURRENCY
        commod_tab = self.book.get_table()
        self.currency = commod_tab.lookup("CURRENCY", currency)

        # Set up the root on accounting book
        self.root = self.book.get_root_account()
        # Assets
        self.assets = self.root.lookup_by_name(assets)
        # What the patient owes to dental office
        self.receivables = self.assets.lookup_by_name(receivables)
        if not self.receivables.lookup_by_name(self.gcpatient_id):
            self.patient_receivables = Account(self.book)
            self.receivables.append_child(self.patient_receivables)
            self.patient_receivables.SetName(self.gcpatient_id)
            self.patient_receivables.SetType(gnc_core_c.ACCT_TYPE_RECEIVABLE)
            self.patient_receivables.SetCommodity(self.currency)
        else:
            self.patient_receivables = self.receivables.lookup_by_name(
                                                            self.gcpatient_id)
        # What the patient paid to dental office, but not usable
        # because it needs to pass by the bank.
        # the detail of dental fund is build in commands/compta.py
        # while getting the paymenttype.
        self.dentalfund = self.assets.lookup_by_name(dentalfund)
        # Incomes
        self.incomes = self.root.lookup_by_name(incomes)
        self.dentalincomes = self.incomes.lookup_by_name(dentalincomes)
# Django setup
# from http://www.b-list.org/weblog/2007/sep/22/standalone-django-scripts/
# This script needs to be callable from the command line, but it also needs
# to know about the Django project's database and other settings.
from django.core.management import setup_environ
import settings  # only works due to path fuckery above
setup_environ(settings)

from gnucash_data import models
from utils.AsciiDammit import asciiDammit

# make sure we can begin a session
models.Lock.check_can_obtain()

# begin GnuCash API session
session = Session(settings.GNUCASH_CONN_STRING)

debug = False


def debug_print(s):
    if debug:
        print s


def get_transaction_string(t):
    memo = txinfo.get('memo', '')
    if memo:
        memo = ' / ' + memo
    return "'%s%s' on %s for %s" \
      % (t['description'], memo,
Beispiel #56
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()
Beispiel #57
0
    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'],
                inst = pricedb.lookup_latest(commodity, currency).get_value()
                print GncNumeric(instance=inst).to_string()


def add_commodity(s, args):
    raise NotImplementedError()


parser = argparse.ArgumentParser()
parser.add_argument('gnucash_file')
parser.add_argument('--dry-run', action='store_true', help='Do not write anything, noop-mode')
subparsers = parser.add_subparsers()
sp = subparsers.add_parser('update-quotes', help='Update stock quotes from online service')
sp.set_defaults(func=update_quotes)
sp = subparsers.add_parser('report', help='Print portfolio report')
sp.set_defaults(func=report)
sp = subparsers.add_parser('add-commodity', help='Helper method to add commodity by ISIN')
sp.add_argument('isin', help='ISIN of stock/bond to add')
sp.set_defaults(func=add_commodity)

args = parser.parse_args()

logging.basicConfig(level=logging.INFO)
logging.getLogger('urllib3').setLevel(logging.WARN)

s = Session(args.gnucash_file)
try:
    args.func(s, args)
finally:
    s.end()