def __init__(self, account, currency='CAD', basename=None, first_day=None, filename_regexp=None, account_types=None): """Create a new importer for the given account. Args: account: An account string, the account to associate to the files. account_types: An AccountTypes object or None to use the default ones. basename: An optional string, the name of the new files. currency: A string, the currency for all extracted transactions. filename_regexp: A regular expression string used to match the basename (no path) of the target file. first_day: An int in [1,28]; the first day of the statement/billing period or None. If None, the file date will be the date of the last extracted entry; otherwise, it will be the date of the end of the monthly period containing the last extracted entry. Also, if a balance directive can be generated, if None, the balance directive will be set to the day following the date of the last extracted entry; otherwise, it will be set to the day following the end of the statement period. """ self.filename_re = re.compile(filename_regexp or self.filename_regexp) self.account = account self.currency = currency.upper() self.basename = basename self.first_day = first_day self.account_sign = atypes.get_account_sign(account, account_types)
def test_get_account_sign(self): for account_name, expected in [ ("Assets:US:RBS:Savings", +1), ("Liabilities:US:RBS:MortgageLoan", -1), ("Equity:Opening-Balances", -1), ("Income:US:ETrade:Dividends", -1), ("Expenses:Toys:Computer", +1), ]: self.assertEqual(expected, account_types.get_account_sign(account_name))
def get_account_sign(self, account_name): """Get account sign. Arguments: account_name: An account name. Returns: The sign of the given account, +1 for an assets or expenses account, -1 otherwise. """ return get_account_sign(account_name, self.account_types)
def add_ira_contribs(entries, options_map, config): """Add legs for 401k employer match contributions. See module docstring for an example configuration. Args: entries: a list of entry instances options_map: a dict of options parsed from the file config: A configuration string, which is intended to be a Python dict mapping match-accounts to a pair of (negative-account, position-account) account names. Returns: A tuple of entries and errors. """ # Parse and extract configuration values. config_obj = eval(config, {}, {}) if not isinstance(config_obj, dict): raise RuntimeError( "Invalid plugin configuration: should be a single dict.") currency = config_obj.pop('currency', 'UNKNOWN') flag = config_obj.pop('flag', None) account_transforms = config_obj.pop('accounts', {}) new_entries = [] for entry in entries: if isinstance(entry, data.Transaction): orig_entry = entry for posting in entry.postings: if (posting.account in account_transforms and posting.position and (account_types.get_account_sign(posting.account) * posting.position.number) > 0): # Get the new account legs to insert. neg_account, pos_account = account_transforms[ posting.account] assert posting.position.lot.cost is None # Insert income/expense entries for 401k. entry = add_postings( entry, amount.Amount(abs(posting.position.number), currency), neg_account.format(year=entry.date.year), pos_account.format(year=entry.date.year), flag) if DEBUG and orig_entry is not entry: printer.print_entry(orig_entry) printer.print_entry(entry) new_entries.append(entry) return new_entries, []
def get_account_sign(self, account_name): """Get account sign.""" return get_account_sign(account_name, self.account_types)
def get_account_sign(self, account_name): return get_account_sign(account_name, self.account_types)
def treemap_data(self, account_name): return { 'label': account_name, 'balances': self.balances(account_name), 'modifier': get_account_sign(account_name, self.account_types), }
def possign(context, x, account): """Correct sign of an Amount based on the usual balance of associated account.""" sign = account_types.get_account_sign(account, context.account_types) return x if sign >= 0 else -x
def treemap_data(self, account_name, begin_date=None, end_date=None): return { 'label': account_name, 'balances': self.balances(account_name, begin_date, end_date), 'modifier': get_account_sign(account_name, self.account_types), }
def add_ira_contribs(entries, options_map, config_str): """Add legs for 401k employer match contributions. See module docstring for an example configuration. Args: entries: a list of entry instances options_map: a dict of options parsed from the file config_str: A configuration string, which is intended to be a Python dict mapping match-accounts to a pair of (negative-account, position-account) account names. Returns: A tuple of entries and errors. """ # Parse and extract configuration values. # FIXME: Use ast.literal_eval() here; you need to convert this code and the getters. # FIXME: Also, don't raise a RuntimeError, return an error object; review # this for all the plugins. # FIXME: This too is temporary. # pylint: disable=eval-used config_obj = eval(config_str, {}, {}) if not isinstance(config_obj, dict): raise RuntimeError( "Invalid plugin configuration: should be a single dict.") # Currency of the inserted postings. currency = config_obj.pop('currency', 'UNKNOWN') # Flag to attach to the inserted postings. insert_flag = config_obj.pop('flag', None) # A dict of account names that trigger the insertion of postings to pairs of # inserted accounts when triggered. accounts = config_obj.pop('accounts', {}) # Convert the key in the accounts configuration for matching. account_transforms = {} for key, config in accounts.items(): if isinstance(key, str): flag = None account = key else: assert isinstance(key, tuple) flag, account = key account_transforms[account] = (flag, config) new_entries = [] for entry in entries: if isinstance(entry, data.Transaction): orig_entry = entry for posting in entry.postings: if (posting.units is not MISSING and (posting.account in account_transforms) and (account_types.get_account_sign(posting.account) * posting.units.number > 0)): # Get the new account legs to insert. required_flag, ( neg_account, pos_account) = account_transforms[posting.account] assert posting.cost is None # Check required flag if present. if (required_flag is None or (required_flag and required_flag == posting.flag)): # Insert income/expense entries for 401k. entry = add_postings( entry, amount.Amount(abs(posting.units.number), currency), neg_account.format(year=entry.date.year), pos_account.format(year=entry.date.year), insert_flag) if DEBUG and orig_entry is not entry: printer.print_entry(orig_entry) printer.print_entry(entry) new_entries.append(entry) return new_entries, []