* Martin Blais <[email protected]> [2019-10-09 22:24 -0400]:
> On Tue, Oct 8, 2019 at 11:29 AM Phil! Gold <[email protected]> wrote:
> > The specific problem is that I have a few different funds I need to
> > keep separate from each other. We periodically have projects in
> > collaboration with other organizations where the funding for those
> > projects has to remain separate from our general funds. I manage this
> > in Ledger by having separate income and expense accounts for these
> > projects.
>
> There's no such rule system (I don't recall coming across it in Ledger
> either, how does it work?),
Well, for Ledger I wrote my own scripts that process the Income and
Expense accounts and sort them into appropriate Net Asset accounts. For
year-to-date reports, the sums just get printed in the reports, but at the
end of the year I write the sums into that year's journal file as new
Ledger transactions.
The net result is that I can use Ledger's built-in querying tools to get
either an income statement or a complete balance sheet for a fiscal year
by querying either the last day of the FY or the first day of the next FY,
respectively. For year-to-date stuff (which is almost always current
year-to-date), if I use the built-in querying tools I have to mentally
combine the income and expense accounts myself.
Since beancount has a richer query language, I'd hoped to be able to do
all of the income/expense -> net asset stuff dynamically without fixing
the account closing stuff at the end of the fiscal year. I guess that's
not possible.
> but what I'd recommend you do is write a little script that creates the
> EOY transactions and insert those into your file.
That's what I ended up doing. In case it's useful to anyone else, I'm
attaching it here. (But its rules--encoded in the get_account_target()
function--depend heavily on the particular account structure I've set up.)
--
...computer contrarian of the first order... / http://aperiodic.net/phil/
PGP: 026A27F2 print: D200 5BDB FC4B B24A 9248 9F7A 4322 2D22 026A 27F2
--- --
do {
:
} until (HELL_FREEZES_OVER);
---- --- --
--
You received this message because you are subscribed to the Google Groups
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/beancount/20191010170525.GM19546%40elros.aperiodic.net.
#!/usr/bin/env python3
__plugins__ = ['add_clear_txns']
import datetime
from decimal import Decimal
from beancount.core import amount, data, flags
FY_START_MONTH = 8
def get_account_target(account):
pieces = account.split(':')
if pieces[1] == 'Projects':
return 'Net-Assets:{}:{}:{}'.format(pieces[1], pieces[2], pieces[3])
elif pieces[1] == 'Restricted-Funds':
return 'Net-Assets:{}:{}'.format(pieces[1], pieces[2])
else:
return 'Net-Assets:{}'.format(pieces[1])
def generate_close_transactions(entries, opened, account_totals, effective_date):
new_entries = []
for account, units in account_totals.items():
p1 = data.Posting(
account=account,
units=amount.mul(units, Decimal(-1)),
cost=None,
price=None,
flag=None,
meta=None)
p2 = data.Posting(
account=get_account_target(account),
units=units,
cost=None,
price=None,
flag=None,
meta=None)
txn = data.Transaction(
date=effective_date,
meta=data.new_metadata('', 0),
flag=flags.FLAG_SUMMARIZE,
payee=None,
narration='Close {}'.format(account),
tags=set(),
links=set(),
postings=[p1, p2])
new_entries.append(txn)
if not p2.account in opened:
opn = data.Open(
date=txn.date,
meta=data.new_metadata('', 0),
account=p2.account,
currencies=None,
booking=None)
new_entries.append(opn)
opened.add(p2.account)
return entries + new_entries, opened
def add_clear_txns(entries, options_map, config_str=None):
config = eval(config_str)
errors = []
new_entries = []
account_totals = {}
opened = set(['Net-Assets:General'])
current_fy_end = None
for entry in entries:
if isinstance(entry, data.Transaction):
if current_fy_end is not None and current_fy_end < entry.date:
new_entries, opened = generate_close_transactions(new_entries, opened, account_totals, current_fy_end)
account_totals = {}
current_fy_end = None
if current_fy_end is None:
current_fy_end = datetime.date(
year=entry.date.year,
month=FY_START_MONTH,
day=1) + datetime.timedelta(days=-1)
if current_fy_end < entry.date:
current_fy_end = current_fy_end.replace(year=entry.date.year + 1)
for posting in entry.postings:
if posting.account.startswith('Income:') or posting.account.startswith('Expenses:'):
if posting.account not in account_totals:
account_totals[posting.account] = posting.units
else:
account_totals[posting.account] = amount.add(account_totals[posting.account], posting.units)
new_entries, opened = generate_close_transactions(new_entries, opened, account_totals, current_fy_end)
return entries + new_entries, errors