redstreet / beancount_reds_importers

Simple ingesting tools for Beancount (plain text, double entry accounting software). More importantly, a framework to allow you to easily write your own importers.
GNU General Public License v3.0
114 stars 38 forks source link

Is there a way to support CSV files that contain data for multiple accounts? #51

Closed davraamides closed 1 year ago

davraamides commented 1 year ago

This may be an edge case, but I'm trying to import my data from a Tiller CSV extract which contains transaction activity for all of my configured accounts (banks, brokerage firms, credit cards, etc.) I've seen you can identify the main_account and cash_account dynamically using the {ticker} and {currency} variables but in looking through the code, I only see those two variables being replaced in the account names. Is there a way to access all columns from the original CSV file so I can reference those in the config passed to the Importer initializer? Something like

    'main_account'   : 'Assets:{Institution}:{Account}:{ticker}',

BTW, I'm using beancount-reds-importers==0.6.0 installed with pip.

redstreet commented 1 year ago

Hi there, there isn't, but that can be added if needed.

However, the examples in your message are easily addressed by configuration, since they aren't actually dynamic from a config perspective. I'll post an example in a minute.

redstreet commented 1 year ago

Each importer instantiation is always for a single account only. For input files (csvs/ofxs) with multiple account, multiple instantiations are made. Here is an example:

    s = acct.split(':')
    root = s[1]
    taxability = s[2]
    leaf = ':'.join(s[3:])
    accts = {
        'account_number' : account_number,
        'main_account'   : acct + ':{ticker}',
        'cash_account'   : f'{acct}:{{currency}}',
        'transfer'       : 'Assets:Zero-Sum-Accounts:Transfers:Bank-Account',
        'dividends'      : f'Income:{root}:{taxability}:Dividends:{leaf}:{{ticker}}',
        'interest'       : f'Income:{root}:{taxability}:Interest:{leaf}:{{ticker}}',
        'cg'             : f'Income:{root}:{taxability}:Capital-Gains:{leaf}:{{ticker}}',
        'capgainsd_lt'   : f'Income:{root}:{taxability}:Capital-Gains-Distributions:Long:{leaf}:{{ticker}}',
        'capgainsd_st'   : f'Income:{root}:{taxability}:Capital-Gains-Distributions:Short:{leaf}:{{ticker}}',
        'fees'           : f'Expenses:Fees-and-Charges:Brokerage-Fees:{taxability}:{leaf}',
        'rounding_error' : 'Equity:Rounding-Errors:Imports',
        'fund_info'      : fund_info,
    }
    return importer.Importer({**accts, **config})

called like so:

CONFIG = [
   invst(fidelity, '12345678', 'Assets:Investments:Taxable:Fidelity-Main-5678'),
   invst(fidelity, '11111111', 'Assets:Investments:Taxable:Fidelity-Fun-1111'),
   invst(fidelity, '22222222', 'Assets:Investments:Taxable:Fidelity-Other-2222'),
  ...
]

This will allow you to use extract multiple accounts from a single csv. The importer will use def skip_transaction() to filter out all transactions that are not a part of the current account being imported like so:

def skip_transaction(self, row):
  return row.Account != self.config['account_number']

Note some are f''-strings, and some are not. The former ones are resolved at config time, and hence need at {{}} for the special variables.

In the above, {acct} (same as {Account} in your example) is resolved at config time, before being passed in to the importer. Does that help?

davraamides commented 1 year ago

Ah, that makes sense. Thanks for the quick response and the detailed example. I'll try it out!