class TestLedger(LedgerTest, TestCase): def setUp(self): self.lgr = Ledger(self.ledger_path, no_pipe=True) self.dynamic_lgr = Ledger(self.dynamic_ledger_path, no_pipe=True) def test_args_only(self): (f, tmprcpath) = tempfile.mkstemp(".ledgerrc") os.close(f) # Who wants to deal with low-level file descriptors? # Create an init file that will narrow the test data to a period that contains no trasnactions with open(tmprcpath, 'w') as f: f.write("--period 2012") # If the command returns no trasnactions, as we would expect if we # parsed the init file, then this will throw an exception. self.lgr.run([""]).next() os.unlink(tmprcpath)
def test_fresh_sync(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) sync = OfxSynchronizer(ledger) ofx = OfxParser.parse(file(os.path.join('fixtures', 'checking.ofx'))) txns1 = ofx.account.statement.transactions txns2 = sync.filter(ofx) self.assertEqual(txns1, txns2)
def test_all_new_txns(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) acct = Mock() acct.download = Mock( return_value=file(os.path.join('fixtures', 'checking.ofx'))) sync = OfxSynchronizer(ledger) self.assertEqual(len(sync.get_new_txns(acct, 7, 7)[1]), 3)
def test_partial_sync(self): ledger = Ledger(os.path.join('fixtures', 'checking-partial.lgr')) sync = OfxSynchronizer(ledger) ofx = OfxSynchronizer.parse_file( os.path.join('fixtures', 'checking.ofx')) txns = sync.filter(ofx.account.statement.transactions, ofx.account.account_id) self.assertEqual(len(txns), 1)
def test_balance_assertion(self): ofx = OfxParser.parse(file(os.path.join('fixtures', 'checking.ofx'))) ledger = Ledger(os.path.join('fixtures', 'checking.lgr')) converter = OfxConverter(ofx=ofx, name="Assets:Foo", ledger=ledger) self.assertEqualLedgerPosting(converter.format_balance(ofx.account.statement), """2013/05/25 * --Autosync Balance Assertion Assets:Foo $0.00 = $100.99 """)
def test_sync_order(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) sync = OfxSynchronizer(ledger) ofx = OfxParser.parse( file(os.path.join('fixtures', 'checking_order.ofx'))) txns = sync.filter(ofx) self.assertTrue(txns[0].date < txns[1].date and txns[1].date < txns[2].date)
def test_comment_txns(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) sync = OfxSynchronizer(ledger) ofx = OfxSynchronizer.parse_file( os.path.join('fixtures', 'comments.ofx')) txns = sync.filter(ofx.account.statement.transactions, ofx.account.account_id) self.assertEqual(len(txns), 1)
def test_sync_order(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) sync = OfxSynchronizer(ledger) ofx = OfxParser.parse( open(os.path.join('fixtures', 'checking_order.ofx'))) txns = sync.filter(ofx.account.statement.transactions, ofx.account.account_id) self.assertTrue(txns[0].date < txns[1].date and txns[1].date < txns[2].date)
def test_initial_balance(self): ofx = OfxParser.parse(file(os.path.join('fixtures', 'checking.ofx'))) ledger = Ledger(os.path.join('fixtures', 'checking.lgr')) converter = OfxConverter(ofx=ofx, name="Assets:Foo", ledger=ledger) self.assertEqualLedgerPosting(converter.format_initial_balance(ofx.account.statement), """2000/01/01 * --Autosync Initial Balance Assets:Foo $160.49 ; ofxid: 1101.1452687~7.autosync_initial Assets:Equity -$160.49 """)
def test_dynamic_account(self): ofx = OfxParser.parse(file(os.path.join('fixtures', 'checking.ofx'))) ledger = Ledger(os.path.join('fixtures', 'checking-dynamic-account.lgr')) converter = OfxConverter(ofx=ofx, name="Assets:Foo", ledger=ledger) self.assertEqualLedgerPosting(converter.convert(ofx.account.statement.transactions[1]).format(), """2011/04/05 AUTOMATIC WITHDRAWAL, ELECTRIC BILL WEB(S ) Assets:Foo -$34.51 ; ofxid: 1101.1452687~7.0000487 Expenses:Bar $34.51 """)
def test_payee_match(self): ofx = OfxParser.parse( open(os.path.join('fixtures', 'checking-payee-match.ofx'))) ledger = Ledger(os.path.join('fixtures', 'checking.lgr')) converter = OfxConverter(account=ofx.account, name="Foo", ledger=ledger) self.assertEqualLedgerPosting( converter.convert( ofx.account.statement.transactions[0]).format(), """2011/03/31 Match Payee Foo -$0.01 ; ofxid: 1101.1452687~7.0000489 Expenses:Bar $0.01 """)
class TestLedger(LedgerTest, TestCase): def setUp(self): self.lgr = Ledger(self.ledger_path, no_pipe=True) self.dynamic_lgr = Ledger(self.dynamic_ledger_path, no_pipe=True) def test_args_only(self): (f, tmprcpath) = tempfile.mkstemp(".ledgerrc") os.close(f) # Who wants to deal with low-level file descriptors? # Create an init file that will narrow the test data to a period that # contains no trasnactions with open(tmprcpath, 'w') as f: f.write("--period 2012") # If the command returns no trasnactions, as we would expect if we # parsed the init file, then this will throw an exception. next(self.lgr.run([""])) os.unlink(tmprcpath)
def run(args=None, config=None): if args is None: args = sys.argv[1:] parser = argparse.ArgumentParser(description='Synchronize ledger.') parser.add_argument('-m', '--max', type=int, default=90, help='maximum number of days to process') parser.add_argument('-r', '--resync', action='store_true', default=False, help='do not stop until max days reached') parser.add_argument('PATH', nargs='?', help='do not sync; import from OFX \ file') parser.add_argument('-a', '--account', type=str, default=None, help='sync only the named account; \ if importing from file, set account name for import') parser.add_argument('-l', '--ledger', type=str, default=None, help='specify ledger file to READ for syncing') parser.add_argument('-L', '--no-ledger', dest='no_ledger', action='store_true', default=False, help='do not de-duplicate against a ledger file') parser.add_argument('-i', '--indent', type=int, default=4, help='number of spaces to use for indentation') parser.add_argument('--initial', action='store_true', default=False, help='create initial balance entries') parser.add_argument('--fid', type=int, default=None, help='pass in fid value for OFX files that do not \ supply it') parser.add_argument('--hardcode-account', type=str, default=None, dest='hardcodeaccount', help='pass in hardcoded account number for OFX files \ to maintain ledger files without real account numbers') parser.add_argument('--shorten-account', default=False, action='store_true', dest='shortenaccount', help='shorten all account numbers to last 4 digits \ to maintain ledger files without full account numbers') parser.add_argument('--unknown-account', type=str, dest='unknownaccount', default=None, help='specify account name to use when one can\'t be \ found by payee') parser.add_argument('--assertions', action='store_true', default=False, help='create balance assertion entries') parser.add_argument('-d', '--debug', action='store_true', default=False, help='enable debug logging') parser.add_argument('--hledger', action='store_true', default=False, help='force use of hledger (on by default if invoked \ as hledger-autosync)') parser.add_argument( '--payee-format', type=str, default=None, dest='payee_format', help="""Format string to use for generating the payee line. Substitutions can be written using {memo}, {payee}, {txntype}, {account} or {tferaction} for OFX. If the input file is a CSV file, substitutions are written using the CSV file column names between {}.""") parser.add_argument('--python', action='store_true', default=False, help='use the ledger python interface') parser.add_argument('--slow', action='store_true', default=False, help='use slow, but possibly more robust, method of \ calling ledger (no subprocess)') parser.add_argument('--which', action='store_true', default=False, help='display which version of ledger (cli), hledger, \ or ledger (python) will be used by ledger-autosync to check for previous \ transactions') parser.add_argument('--reverse', action='store_true', default=False, help='print CSV transactions in reverse order') parser.add_argument('-o', '--ofxconfig', type=str, default=None, help='specify config file for ofxclient') parser.add_argument('-y', '--date-format', type=str, default=None, dest="date_format", help="""Format string to use for printing dates. See strftime for details on format string syntax. Default is "%%Y/%%m/%%d".""" ) parser.add_argument('--no-infer-account', dest="infer_account", action='store_false', default=True, help='disable inference of offset account from payee') args = parser.parse_args(args) if sys.argv[0][-16:] == "hledger-autosync": args.hledger = True ledger_file = None if args.ledger and args.no_ledger: raise LedgerAutosyncException( 'You cannot specify a ledger file and -L') elif args.ledger: ledger_file = args.ledger else: ledger_file = find_ledger_file() if args.debug: logging.basicConfig(level=logging.DEBUG) if ledger_file is None: sys.stderr.write("LEDGER_FILE environment variable not set, and no \ .ledgerrc file found, and -l argument was not supplied: running with deduplication disabled. \ All transactions will be printed!\n") ledger = None elif args.no_ledger: ledger = None elif args.hledger: ledger = HLedger(ledger_file) elif args.python: ledger = LedgerPython(ledger_file=ledger_file) elif args.slow: ledger = Ledger(ledger_file=ledger_file, no_pipe=True) else: ledger = mk_ledger(ledger_file) if args.which: sys.stderr.write("ledger-autosync is using ") if isinstance(ledger, Ledger): sys.stderr.write("ledger (cli)\n") elif isinstance(ledger, HLedger): sys.stderr.write("hledger\n") elif isinstance(ledger, LedgerPython): sys.stderr.write("ledger.so (python)\n") exit() config_dir = os.environ.get( 'XDG_CONFIG_HOME', os.path.join(os.path.expanduser("~"), '.config')) load_plugins(config_dir) if args.PATH is None: if config is None: if args.ofxconfig is None: config_file = os.path.join(config_dir, 'ofxclient.ini') else: config_file = args.ofxconfig if (os.path.exists(config_file)): config = OfxConfig(file_name=config_file) else: config = OfxConfig() accounts = config.accounts() if args.account: accounts = [ acct for acct in accounts if acct.description == args.account ] sync(ledger, accounts, args) else: _, file_extension = os.path.splitext(args.PATH.lower()) if file_extension == '.csv': import_csv(ledger, args) else: import_ofx(ledger, args)
def run(args=None, config=None): if args is None: args = sys.argv[1:] parser = argparse.ArgumentParser(description='Synchronize ledger.') parser.add_argument('-m', '--max', type=int, default=90, help='maximum number of days to process') parser.add_argument('-r', '--resync', action='store_true', default=False, help='do not stop until max days reached') parser.add_argument('PATH', nargs='?', help='do not sync; import from OFX \ file') parser.add_argument('-a', '--account', type=str, default=None, help='sync only the named account; \ if importing from file, set account name for import') parser.add_argument('-l', '--ledger', type=str, default=None, help='specify ledger file to READ for syncing') parser.add_argument('-i', '--indent', type=int, default=4, help='number of spaces to use for indentation') parser.add_argument('--initial', action='store_true', default=False, help='create initial balance entries') parser.add_argument('--fid', type=int, default=None, help='pass in fid value for OFX files that do not \ supply it') parser.add_argument('--unknown-account', type=str, dest='unknownaccount', default=None, help='specify account name to use when one can\'t be \ found by payee') parser.add_argument('--assertions', action='store_true', default=False, help='create balance assertion entries') parser.add_argument('-d', '--debug', action='store_true', default=False, help='enable debug logging') parser.add_argument('--hledger', action='store_true', default=False, help='force use of hledger (on by default if invoked \ as hledger-autosync)') parser.add_argument('--slow', action='store_true', default=False, help='use slow, but possibly more robust, method of \ calling ledger (no subprocess)') parser.add_argument('--which', action='store_true', default=False, help='display which version of ledger (cli), hledger, \ or ledger (python) will be used by ledger-autosync to check for previous \ transactions') args = parser.parse_args(args) if sys.argv[0][-16:] == "hledger-autosync": args.hledger = True ledger_file = None if args.ledger: ledger_file = args.ledger else: ledger_file = find_ledger_file() if args.debug: logging.basicConfig(level=logging.DEBUG) if args.hledger: ledger = HLedger(ledger_file) elif args.slow: ledger = Ledger(ledger_file=ledger_file, no_pipe=True) else: ledger = mk_ledger(ledger_file) if args.which: sys.stderr.write("ledger-autosync is using ") if type(ledger) == Ledger: sys.stderr.write("ledger (cli)\n") elif type(ledger) == HLedger: sys.stderr.write("hledger\n") elif type(ledger) == LedgerPython: sys.stderr.write("ledger.so (python)\n") exit() if args.PATH is None: if config is None: config_dir = os.environ.get( 'XDG_CONFIG_HOME', os.path.join(os.path.expanduser("~"), '.config')) config_file = os.path.join(config_dir, 'ofxclient.ini') if (os.path.exists(config_file)): config = OfxConfig(file_name=config_file) else: config = OfxConfig() accounts = config.accounts() if args.account: accounts = [ acct for acct in accounts if acct.description == args.account ] sync(ledger, accounts, args) else: _, file_extension = os.path.splitext(args.PATH) if file_extension == '.csv': import_csv(ledger, args) else: import_ofx(ledger, args)
def setUp(self): self.lgr = Ledger(os.path.join('fixtures', 'empty.lgr'), no_pipe=True)
def test_partial_sync(self): ledger = Ledger(os.path.join('fixtures', 'paypal.lgr')) sync = CsvSynchronizer(ledger) self.assertEqual( 1, len(sync.parse_file(os.path.join('fixtures', 'paypal.csv'))))
def setUp(self): self.empty_lgr = Ledger(os.path.join('fixtures', 'empty.lgr'), no_pipe=True) self.lgr = Ledger(self.ledger_path, no_pipe=True) self.dynamic_lgr = Ledger(self.dynamic_ledger_path, no_pipe=True)
def test_partial_sync(self): ledger = Ledger(os.path.join('fixtures', 'checking-partial.lgr')) sync = OfxSynchronizer(ledger) (ofx, txns) = sync.parse_file(os.path.join('fixtures', 'checking.ofx')) self.assertEqual(len(txns), 1)
def test_fully_synced(self): ledger = Ledger(os.path.join('fixtures', 'checking.lgr')) sync = OfxSynchronizer(ledger) (ofx, txns) = sync.parse_file(os.path.join('fixtures', 'checking.ofx')) self.assertEqual(txns, [])
def test_comment_txns(self): ledger = Ledger(os.path.join('fixtures', 'empty.lgr')) sync = OfxSynchronizer(ledger) (ofx, txns) = sync.parse_file(os.path.join('fixtures', 'comments.ofx')) self.assertEqual(len(txns), 1)
def setUp(self): self.lgr = Ledger(self.ledger_path, no_pipe=True) self.dynamic_lgr = Ledger(self.dynamic_ledger_path, no_pipe=True)
def setUp(self): self.empty_lgr = Ledger(os.path.join('fixtures', 'empty.lgr'), no_pipe=True) self.checking_lgr = Ledger(os.path.join('fixtures', 'checking.lgr'), no_pipe=True)