Skip to content
This repository has been archived by the owner on Mar 1, 2021. It is now read-only.

Commit

Permalink
Merge pull request #17 from gratipay/reorganize-declarations
Browse files Browse the repository at this point in the history
scope declarations to fiscal year
  • Loading branch information
kaguillera committed Feb 3, 2016
2 parents d979ed3 + 54ee9b2 commit b9ea24a
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 61 deletions.
4 changes: 0 additions & 4 deletions FY2013/2012-06.dat
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
2012-06-01 Opening Balance
Assets:Operations:New Alliance $ 102.45
Equity:Owners:Chad Whitacre -$ 102.45

; Gittip Payday 0
2012-06-01 Users
Assets:Escrow:Samurai $ 2.96
Expand Down
3 changes: 3 additions & 0 deletions FY2013/FY2013.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
2012-06-01 Opening Balance
Assets:Operations:New Alliance $ 102.45
Equity:Owners:Chad Whitacre -$ 102.45
21 changes: 13 additions & 8 deletions declarations.dat → FY2013/declarations.dat
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
commodity $

account Assets:Escrow:Cash
account Assets:Escrow:New Alliance
account Assets:Escrow:Samurai
Expand All @@ -10,14 +11,13 @@ account Assets:Fee Buffer:Stripe
account Assets:Operations:New Alliance
account Assets:Operations:Samurai
account Assets:Operations:Stripe

account Liabilities:Escrow
account Liabilities:Fee Buffer

account Equity:Owners:Chad Whitacre
account Equity:Current Activity
account Expenses:Escrow:Cash
account Expenses:Fee Buffer:Cash
account Expenses:Fee Buffer:Samurai
account Expenses:Fee Buffer:Stripe
account Expenses:Operations:Errors:Samurai
account Expenses:Operations:Processing:Stripe

account Income:Escrow:Samurai
account Income:Escrow:Stripe
account Income:Fee Buffer:Cash
Expand All @@ -26,5 +26,10 @@ account Income:Fee Buffer:Stripe
account Income:Operations:Errors:Samurai
account Income:Operations:IHasAMoney.com
account Income:Operations:Verification & Testing
account Liabilities:Escrow
account Liabilities:Fee Buffer

account Expenses:Escrow:Cash
account Expenses:Fee Buffer:Cash
account Expenses:Fee Buffer:Samurai
account Expenses:Fee Buffer:Stripe
account Expenses:Operations:Errors:Samurai
account Expenses:Operations:Processing:Stripe
97 changes: 58 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
# Gratipay Finances

This is [Gratipay](https://gratipay.com/)'s financial accounting system, which
is based on [Ledger](http://ledger-cli.org/). We have a directory for each
year, and an `NN.dat` file for each month. Our wrapper scripts are in the
`bin/` directory; add it to your `PATH` for best results. Each month gets [a
PR](https://github.com/gratipay/finances/pulls).
is comprised of some wrapper scripts for [Ledger](http://ledger-cli.org/) and a
[workflow](#workflow) here on GitHub. While we [catch
up](https://github.com/gratipay/finances/issues/3) on our books, our budget and
old data are available in our
[old spreadsheet](https://docs.google.com/spreadsheet/pub?key=0AiDJ5uiG6Hp3dDJnVDNLMVk4NldhSy1JbFJ0aWRUYkE&output=html&widget=true).

[![status](https://api.travis-ci.org/gratipay/finances.svg)](https://travis-ci.org/gratipay/finances)

While we [catch up](https://github.com/gratipay/finances/issues/3) on our
books, our budget and old data are only available in our old
[spreadsheet](https://docs.google.com/spreadsheet/pub?key=0AiDJ5uiG6Hp3dDJnVDNLMVk4NldhSy1JbFJ0aWRUYkE&output=html&widget=true).


## How Our Books are Organized

Expand All @@ -30,22 +27,41 @@ any other Gratipay Team). To deal with this dual reality, we use a **fee
buffer**. Ideally the balance in the fee buffer is zero, though of course it
fluctuates in practice.

You'll see, then, that the assets on our balance sheet, as well as our income
and expenses on our income statement, are broken down according to these three
second-level categories: escrow, fee buffer, and operations. The fee buffer and
operations on the income statement hit retained earnings on the balance sheet.
Escrow on the income statement hits escrow liability on the balance sheet.
You'll see, then, that the assets on our balance sheet are broken down
according to these three second-level categories: escrow, fee buffer, and
operations. Each also gets a separate income statement:

- Net income on the income statement hits Current Activity on the balance sheet
- Escrow activity hits the Escrow liability account
- Fee Buffer activity hits the Fee Buffer liability account

Whereas the second-level categories are *logical*, our actual *physical* bank
and processor accounts end up as third-level categories. So, for example, our
actual balance at New Alliance Federal Credit Union is equal to the sum of
Whereas the second-level asset categories are *logical*, our actual *physical*
bank and processor accounts end up as third-level categories. So, for example,
our actual balance at New Alliance Federal Credit Union is equal to the sum of
these three balance sheet accounts:

- Assets:Escrow:New Alliance
- Assets:Fee Buffer:New Alliance
- Assets:Operations:New Alliance


### Fiscal Year

Our fiscal year runs from June 1 through May 31.


## How This Repo is Organized

There is a directory for each fiscal year, named `FYNNNN`. Inside are three
kinds of files:

- `FYNNNN.dat`—the opening and closing transactions for the fiscal year
- `NNNN-MM.dat`—a month's worth of transactions
- `declarations.dat`—the list of accounts in use during the fiscal year

Our scripts and helpers are in the `bin/` directory.


## Working on the Finances

First, you'll need [Ledger](http://ledger-cli.org/) (v3),
Expand All @@ -57,22 +73,39 @@ and then, from the root of your clone of this repo, run (with
[`bin`](https://github.com/gratipay/finances/blob/master/bin/) on your `PATH`):

```bash
clear && test.py && balance-sheet.py && income-statement.py
test.py && clear && balance-sheet.py && income-statement.py
```

That'll check for errors (we also have CI set up [at
Travis](https://travis-ci.org/gratipay/finances)) and then show you a balance
sheet and income statement. If you need to add accounts or currencies you can
do so in
[`declarations.dat`](https://github.com/gratipay/finances/blob/master/declarations.dat).
If you want to run arbitrary Ledger commands, we provide a wrapper that points
`ledger` to our `dat` files for your convenience:
do so in the `declarations.dat` file for the year you're working on. If you
want to run arbitrary Ledger
[commands](http://ledger-cli.org/3.0/doc/ledger3.html), we provide a wrapper
that points `ledger` to our `dat` files for your convenience:

```bash
wledger.py register
```


### Workflow

Each month gets [a PR](https://github.com/gratipay/finances/pulls) entitled
`reconcile YYYY-MM`, with a branch named `YYYY-MM`. We close the month by
merging the PR for the month. Inside of an open month, we should overwrite
ledger transactions as needed (changes are tracked in Git commits and GitHub
comments). Outside of an open month, we must make any correcting transactions
in the current month, rather than overwriting transactions in an old dat file.

Each fiscal year also gets a PR entitled `close FYNNNN` and/or `audit FYNNNN`.
We close the year by merging the PR(s). Inside of an open year, we may change
account names (this affects all month files for the year). Once a year is
closed, we mustn't edit it at all, apart from comments.

It's always okay to add or clarify comments.


### Style

Here are some style notes for the `dat` files:
Expand All @@ -92,23 +125,6 @@ Here are some style notes for the `dat` files:
1. Use comments! Especially for weird stuff.


### Change Restrictions

We start a PR for each month, named `YYYY-MM`, and we close the month by
merging the PR.

Inside of an open month, we should overwrite ledger transactions as needed.
Changes are tracked in git commits and GitHub comments. Outside of an open
month, we must make correcting transactions in the current month, rather than
overwriting transactions in the old dat file.

Inside of an open year, we may change account names (this affects all month
files for the year). Outside of an open year, we must archive accounts rather
than renaming them.

It's always okay to add comments to a file.


### Access

Many accounting tasks require access to Gratipay's bank and payment processor
Expand All @@ -126,4 +142,7 @@ Radar](http://inside.gratipay.com/howto/sweep-the-radar).
# Legal

The scripts and data in this repo are released into the public domain to the
extent possible under [CC0](http://creativecommons.org/publicdomain/zero/1.0/).
extent possible under [CC0](http://creativecommons.org/publicdomain/zero/1.0/),
and if you don't accept that then you may also use them under the
[CC](https://creativecommons.org/licenses/) or [OSI
license](https://opensource.org/licenses) of your choosing.
25 changes: 15 additions & 10 deletions bin/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def list_datfiles(start=None, end=None, root='.'):
for dirname in sorted(listdir(root)):
if not dirname.startswith('FY'): continue
for filename in sorted(listdir(path.join(root, dirname))):
if not filename.endswith('.dat'): continue
if re.match(r'\d\d\d\d-\d\d\.dat', filename) is None: continue
year, month = filename[:-len('.dat')].split('-')
years.append(year)
months_by_year[year].append(month)
Expand All @@ -66,35 +66,40 @@ def list_datfiles(start=None, end=None, root='.'):
if year not in years:
sys.exit("Sorry, we don't have any data for {}.".format(year))

filtered = []
fiscal_years = set()
months_to_load = []
for year in years:
if year < start[0]: continue
elif year > end[0]: break

months = months_by_year[year]
months_for_year = months_by_year[year]

def check(month):
if month[1] not in months:
if month[1] not in months_for_year:
sys.exit("Sorry, we don't have any data for {}-{}.".format(*month))

if start[0] == year:
if start[1] is None: start[1] = months[0]
if start[1] is None: start[1] = months_for_year[0]
check(start)
if end[0] == year:
if end[1] is None: end[1] = months[-1]
if end[1] is None: end[1] = months_for_year[-1]
check(end)

for month in months:
for month in months_for_year:
if start[1] == year and month < start[1]: continue
elif end[1] == year and month > end[1]: break

fiscal_year = year if month < FISCAL_YEAR_STARTING_MONTH else unicode(int(year) + 1)
filtered.append('FY{}/{}-{}.dat'.format(fiscal_year, year, month))
fiscal_years.add(fiscal_year)
months_to_load.append((fiscal_year, year, month))

if end < start:
sys.exit('Error: {}-{} comes before {}-{}.'.format(*(end + start)))

return ['-f ' + f for f in filtered]
year_ends = ['-f ' + 'FY{}/FY{}.dat'.format(fy, fy) for fy in sorted(fiscal_years)]
declarations = ['-f ' + 'FY{}/declarations.dat'.format(fy) for fy in sorted(fiscal_years)]
transactions = ['-f ' + 'FY{}/{}-{}.dat'.format(fy, y, m) for fy, y, m in months_to_load]
return declarations + year_ends + transactions


def income_statement():
Expand Down Expand Up @@ -154,7 +159,7 @@ def wrapped(*a, **kw):

@in_root
def report(cmd):
cmd = [cmd[0]] + ['-f', 'declarations.dat', '--pedantic'] + cmd[1:]
cmd.append('--pedantic')
retcode = subprocess.call(' '.join(cmd), shell=True)
if retcode != 0:
raise SystemExit(retcode)

0 comments on commit b9ea24a

Please sign in to comment.