Exemple #1
0
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)
Exemple #4
0
 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)
Exemple #7
0
 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)
Exemple #8
0
 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
""")
Exemple #11
0
    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
""")
Exemple #12
0
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)
Exemple #13
0
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)
Exemple #14
0
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)
Exemple #15
0
 def setUp(self):
     self.lgr = Ledger(os.path.join('fixtures', 'empty.lgr'), no_pipe=True)
Exemple #16
0
 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)
Exemple #18
0
 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)
Exemple #19
0
 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, [])
Exemple #20
0
 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)
Exemple #22
0
 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)
Exemple #23
0
 def setUp(self):
     self.lgr = Ledger(self.ledger_path, no_pipe=True)
     self.dynamic_lgr = Ledger(self.dynamic_ledger_path, no_pipe=True)