mirror of
https://github.com/simonmichael/hledger.git
synced 2024-12-26 20:02:27 +03:00
1095 lines
38 KiB
Plaintext
1095 lines
38 KiB
Plaintext
hledger project notes
|
|
=====================
|
|
|
|
* inspiration
|
|
"...simplicity of design was the most essential, guiding principle.
|
|
Clarity of concepts, economy of features, efficiency and reliability of
|
|
implementations were its consequences." --Niklaus Wirth
|
|
|
|
"The competent programmer is fully aware of the limited size of his own
|
|
skull. He therefore approaches his task with full humility, and avoids
|
|
clever tricks like the plague." --Edsger Dijkstra
|
|
|
|
"I was hesitating to cross the street in Edinburgh one day, and these two
|
|
little old Scottish ladies cried out to me 'LIVE DANGEROUSLY, SON! LIVE
|
|
DANGEROUSLY'" --kowey
|
|
|
|
ALL THAT'S NEEDED IS THE DESIRE TO BE HEARD. THE WILL TO LEARN. AND THE
|
|
ABILITY TO SEE. --Scott McCloud, Understanding Comics
|
|
|
|
* principles
|
|
** we aim to make reliable, maintainable, usable, useful software, sustainably.
|
|
** docs before packaging before tests before fixes before refactoring before features
|
|
** "bugs" are errors, as in the programmers messed up
|
|
** automate
|
|
** measure
|
|
** test continuously, test everything
|
|
** less is more
|
|
** code review/pair programming
|
|
|
|
|
|
* todo/backlog
|
|
** documentation, marketing
|
|
*** developer notes & log
|
|
*** website
|
|
**** add tables of contents
|
|
**** integrate binaries, demo, pastebin
|
|
*** manual
|
|
**** make accessible from command line
|
|
*** add missing
|
|
**** faq
|
|
**** examples/how-tos
|
|
**** hledger/ledger comparison/feature matrix
|
|
**** blog posts
|
|
*** reduce
|
|
*** aesthetics
|
|
**** better screenshots/images
|
|
***** use highslide
|
|
*** automation
|
|
**** keep blurbs in sync
|
|
***** README file
|
|
***** hledger.hs module description
|
|
***** hledger.cabal description field (exclude home page link)
|
|
***** home page description (http://joyful.com/Hledger/editform)
|
|
***** mail list description (http://groups.google.com/groups/hledger -> edit welcome msg)
|
|
***** gmane description
|
|
***** darcsweb description
|
|
**** keep Options.hs and README option list in sync
|
|
**** discovering commands for --help
|
|
**** announcements
|
|
*** liveness
|
|
**** show feeds on site ?
|
|
***** commits (darcsweb)
|
|
**** weekly repo activity summary on list
|
|
**** available feeds
|
|
*** screencasts
|
|
**** intro
|
|
***** intro to hledger
|
|
****** place in the world
|
|
****** basic installation
|
|
****** quick demo
|
|
****** where to go from here
|
|
***** installing hledger on windows
|
|
***** installing hledger on mac
|
|
***** installing hledger on unix
|
|
***** accessing hledger's support forums
|
|
****** website
|
|
****** mail list
|
|
****** irc channel
|
|
***** reporting a hledger bug
|
|
**** using
|
|
***** income/expense tracking
|
|
***** time tracking
|
|
***** downloading bank data
|
|
***** reconciling with bank statement
|
|
***** see time reports by day/week/month/project
|
|
***** get accurate numbers for client billing and tax returns
|
|
***** find unpaid invoices
|
|
**** developing
|
|
***** intro to hledger development
|
|
***** testing hleder
|
|
***** documenting hledger
|
|
***** a hledger coding example
|
|
***** a tour of hledger's code
|
|
**** ledger cooperation
|
|
*** developer docs
|
|
**** developer notes & log
|
|
**** roadmap
|
|
***** 1.0
|
|
culmination of 0.x releases - stable/usable/documented
|
|
followup releases are 1.01, 1.02..
|
|
GHC 6.12/HP 2010 primary platform
|
|
GHC 6.10/HP 2009 also supported if possible
|
|
GHC 6.8 might work for core features, but not officially supported
|
|
separate ledger package ? license ?
|
|
separate vty, web packages ?
|
|
support plugins ?
|
|
web: loli+hsp+hack+simpleserver/happstack, or yesod+hstringtemplate+wai+simpleserver/happstack ?
|
|
add: completion ?
|
|
chart: register charts ?
|
|
histogram: cleaned up/removed
|
|
complete user manual
|
|
binaries for all platforms ?
|
|
|
|
***** 2.0
|
|
development releases are.. 1.60, 1.61.. or 1.98.01, 1.98.02..
|
|
separate ledger lib
|
|
plugins
|
|
Decimal
|
|
binaries for all platforms
|
|
|
|
**** internal api docs
|
|
**** external api docs
|
|
**** DEVGUIDE
|
|
***** How to do anything that needs doing in the hledger project.
|
|
****** website & documentation
|
|
******* overview of hledger docs
|
|
******* how the site is built
|
|
******* convenience urls
|
|
list.hledger.org - mail list
|
|
bugs.hledger.org - issue tracker
|
|
bugs.hledger.org/1 - go to specific issue
|
|
bugs.hledger.org/new - create a new issue
|
|
hledger.org/{list,bugs}/* also works
|
|
|
|
****** issue tracking
|
|
****** testing
|
|
****** coding
|
|
****** funding process
|
|
***** reference
|
|
****** unsafe things which may fail at runtime include..
|
|
******* incomplete pattern matching
|
|
******* error
|
|
******* printf
|
|
******* read
|
|
**** functional programming
|
|
hledger is written in the Haskell programming language;
|
|
it demonstrates a pure functional implementation of ledger.
|
|
*** presenting/live demos
|
|
*** develop funding process
|
|
**** license change ?
|
|
**** donate button, see chimoo guy
|
|
**** funding document 2009/01
|
|
***** text
|
|
=======
|
|
funding
|
|
=======
|
|
|
|
vision
|
|
======
|
|
|
|
How to grow the hledger project ?
|
|
|
|
I'm looking for ways to fund active and sustainable hledger
|
|
development by me and others.
|
|
|
|
A secondary goal is to develop new sustainable models and processes
|
|
for funding free software developers and other community projects.
|
|
|
|
This is sometimes the point in a free sw project's development where
|
|
the project leader seemingly loses the plot, alienates contributors
|
|
and destroys the community's good-will dynamic. I've seen it many
|
|
times, but a few have succeeded and I want to be one of them - so
|
|
that I can eat, have a modicum of stability and do my best work in
|
|
service to the community. At worst, I'll look bad but the project
|
|
will still be out there. At best I'll live more easily and joyfully
|
|
while serving the cause of Financial Solvency!
|
|
|
|
So I'm beginning by posting these notes and inviting your thoughts -
|
|
as much or as little as folks want to give. How could we do this
|
|
so that all benefit ?
|
|
|
|
funding models
|
|
==============
|
|
Brainstorming some possible funding models & processes.
|
|
|
|
* grants
|
|
|
|
How to find possible grant sources ?
|
|
|
|
* con
|
|
|
|
* getting grant funding is a whole new field to study
|
|
* slow and time intensive, I imagine
|
|
|
|
* donations
|
|
|
|
Solicit donations.
|
|
|
|
* pro
|
|
|
|
* simple
|
|
|
|
* con
|
|
|
|
* often difficult
|
|
* donators do not feel a direct benefit
|
|
|
|
* shareware
|
|
|
|
Release the project under a non-free license, requiring commercial
|
|
users to pay the fee on an honour basis (eg).
|
|
|
|
* pro
|
|
|
|
* flexible, low administration, encourages trust
|
|
|
|
* con
|
|
|
|
* effectively closed-source ? would inhibit collaboration
|
|
* benefit is still indirect, only a proportion will pay
|
|
* enforcement/guilt may come into play
|
|
|
|
* limited-time premium branch
|
|
|
|
The funded version of hledger gets some desirable premium features
|
|
before the free version and is closed-source. Funders/customers pay
|
|
a fixed price for immediate access to the funded version. Yearly, a
|
|
new funded version is released and the old funded version is merged
|
|
into the free version. (To gain experience it could be done on a
|
|
smaller scale, eg monthly/quarterly.)
|
|
|
|
* pro
|
|
|
|
* all features reach community, predictably
|
|
* customers are also community funders
|
|
* customers receive direct benefit from paying
|
|
|
|
* con
|
|
|
|
* free sw developers compete/outshine the premium branch
|
|
|
|
* bounties
|
|
|
|
Some (or all) feature, bugfix, project management or other tasks are
|
|
published with a bounty attached. When the bounty is paid by one or
|
|
more funders, the task is performed and delivered. Or, bounty is paid
|
|
on completion of task (honour system).
|
|
|
|
* pro
|
|
|
|
* funders receive direct benefit
|
|
|
|
* bounties using fundable.org (eg)
|
|
|
|
A more organised form of the above, perhaps facilitating trust,
|
|
co-funding and larger bounties.
|
|
|
|
* pro
|
|
|
|
* proven process developed by others
|
|
|
|
* con
|
|
|
|
* fundable takes a cut
|
|
|
|
* hosted service
|
|
|
|
Offer hosted and managed ledgers, perhaps with premium features, for
|
|
a monthly fee
|
|
|
|
* pro
|
|
|
|
* proven model
|
|
* clear benefit to customers, especially non-technies
|
|
|
|
* con
|
|
|
|
* success of free/self-installed version competes with hosting service
|
|
* some will avoid web-hosting their financial data
|
|
|
|
* customisation
|
|
|
|
Offer per-user customisations, possibly to be merged in the trunk,
|
|
for a fee
|
|
|
|
* support
|
|
|
|
Offer user/developer support for a fee
|
|
|
|
* training
|
|
|
|
Offer application and/or financial training for a fee
|
|
|
|
* profit sharing/tithing
|
|
|
|
Each period (quarter, half-year, year), donate 10% (eg) to project
|
|
contributors and/or supporting projects
|
|
|
|
* transparent funding
|
|
|
|
Funding and usage of funds is published on the web as a ledger
|
|
|
|
* opaque funding
|
|
|
|
All funding and spending need not be made public
|
|
|
|
strengths
|
|
=========
|
|
hledger has some aptitudes in this area:
|
|
|
|
* hledger deals with money => hledger users will tend to have some money
|
|
* hledger's purpose is to increase financial success => users will feel its value to their bottom line
|
|
* hledger is a tool that can support project funding, eg by publishing community funding data
|
|
|
|
weaknesses
|
|
==========
|
|
* hledger doesn't have a nice ui yet
|
|
* hledger has a limited featureset
|
|
* hledger requires work, eg data entry and chart of accounts maintenance
|
|
* hledger is geeky
|
|
* there is competition
|
|
* hledger has no compelling market niche (aside from payment-averse free software users)
|
|
|
|
competitors/fellow niche inhabitants
|
|
====================================
|
|
|
|
* web apps
|
|
|
|
* netsuite
|
|
* sql-ledger, ledgersmb
|
|
* wesabe
|
|
* ...
|
|
|
|
* desktop apps
|
|
|
|
* quickbooks
|
|
* quicken
|
|
* ms money
|
|
* grisbi
|
|
* gnucash
|
|
* excel
|
|
* ledger!
|
|
* ...
|
|
|
|
***** responses
|
|
****** albino
|
|
have you considered talking to business who hate their financial sw and going from there
|
|
****** gwern
|
|
most haskellers have never heard of hledger, sounds arrogant or hubristic to talk of charging for it
|
|
|
|
**** home edition
|
|
**** real-time project ledger
|
|
** packaging, installability
|
|
*** linux
|
|
***** debian/ubuntu packaging
|
|
*** mac
|
|
***** easy installer
|
|
***** easy startup
|
|
*** windows
|
|
***** easy installer
|
|
***** easy startup
|
|
** testing
|
|
*** documentation
|
|
**** site up, current ?
|
|
**** demo up, current ?
|
|
**** haddock building, current ?
|
|
**** doctests ?
|
|
*** unit
|
|
**** hunit
|
|
**** quickcheck
|
|
**** easier unit test development
|
|
*** functional
|
|
**** ledger file parsing tests
|
|
***** test all ledger file format features
|
|
***** clarify hledgerisms in file format - that hledger can read but ledger can't
|
|
**** ledger 3 baseline tests
|
|
*** performance
|
|
**** speed, benchmark tests
|
|
**** memory usage
|
|
*** build & packaging
|
|
**** use -Wall and anything else useful
|
|
**** build with multiple ghc versions
|
|
**** cabal test
|
|
**** hackage upload
|
|
**** cabal install with:
|
|
***** ghc 6.8
|
|
***** ghc 6.10.x
|
|
***** windows
|
|
***** linux
|
|
***** macos
|
|
***** no flags
|
|
***** happs flag
|
|
***** vty flag
|
|
*** field
|
|
**** talkback, auto bug reports
|
|
**** usability
|
|
**** download & usage stats
|
|
** errors
|
|
*** parsing: recursive file includes cause a hang
|
|
*** parsing: extra noise with eg bad date parse errors
|
|
$ cat t.journal
|
|
200/1/99 x
|
|
a 1
|
|
b
|
|
$ ./hledger.hs -f t.journal print
|
|
hledger.hs: could not parse journal data in t.journal
|
|
"t.journal" (line 1, column 9):
|
|
unexpected " " <- undesired
|
|
expecting digit <- noise
|
|
bad year number: 200
|
|
|
|
*** parsing: period expressions should allow interval at the end
|
|
*** parsing: canonicalise account names to be case-insensitive
|
|
*** parsing: only journals can include, and only another journal
|
|
*** parsing: misleading error when journal lacks a final newline
|
|
hledger -f- balance
|
|
<<<
|
|
2010/1/2
|
|
a 1
|
|
b
|
|
*** parsing: better leap year checking
|
|
ledger:
|
|
While parsing file "/Users/simon/personal/2010.ledger", line 442:
|
|
While parsing transaction:
|
|
> 2/27=2/29 (20100201ucla) ucla payment
|
|
Error: Day of month is not valid for year
|
|
|
|
*** balance: --depth with --flat should show aggregate balances
|
|
*** register: intervals with unspecified from should start from first txn not first matched txn ?
|
|
*** convert: rules file can't have blank lines after last data
|
|
*** web: doesn't support multiple filter patterns
|
|
*** web: accounts final balance can be -0, colored red
|
|
*** web: post handlers should preserve a p
|
|
*** web: --base-url trailing slash gives redirect loop
|
|
hledger web --port 5001 --base-url http://localhost:5001/ -f ~/personal/household.journal
|
|
*** web: assets.bank.checking indentation in demo journal
|
|
*** web: loses -B after an edit, and/or a filesystem edit
|
|
*** docs: need to be less wall-of-text
|
|
*** docs:installing:describe three install options in one place
|
|
*** windows: can't print non-ascii
|
|
http://code.google.com/p/hledger/issues/detail?id=25
|
|
http://blog.andrewbeacock.com/2008/12/rxvt-better-console-for-cygwin-unix-on.html
|
|
http://www.burningcutlery.com/derek/winsetup/
|
|
http://msdn.microsoft.com/en-us/library/ms714415(v=VS.85).aspx
|
|
*** LEDGER vs LEDGER_FILE
|
|
*** clarify data modifying story
|
|
**** auto-create of empty files annoying ?
|
|
**** data-modifying commands: add, web->add/edit
|
|
** refactoring, cleanup
|
|
*** more modularity
|
|
**** packages/namespace
|
|
***** more package splits ?
|
|
****** hledger-web
|
|
****** hledger-vty
|
|
**** plugin strategy
|
|
**** export lists
|
|
**** graph and reduce dependencies
|
|
*** clarify levels of abstraction
|
|
**** web ui balance sheet view - data model, view layout
|
|
**** hledger web framework - define routes, handlers/views/actions/controllers/presenters, skins/styles..
|
|
**** happstack - ? happstack api..
|
|
**** hledger app platform - hledger.hs, Options, Utils, withLedgerDo..
|
|
**** hledger lib - Ledger, TimeLog, Account, Transaction, Commodity..
|
|
**** hledger dev platform - make build, ci, test, bench, prof, check, release..
|
|
**** general libs - directory, parsec, regex-*, HUnit, time..
|
|
**** cabal - hledger.cabal, hackage..
|
|
**** ghc - ghc 6.8, 6.10..
|
|
**** haskell 98
|
|
**** unix/windows/mac platform
|
|
*** inspiration
|
|
http://community.haskell.org/~ndm/downloads/paper-hoogle_overview-19_nov_2008.pdf -> Design Guidelines
|
|
** features
|
|
*** show add form after adding
|
|
*** : completes one account name component
|
|
*** auto-complete from substrings, not just prefixes
|
|
*** auto-complete accounts & amount as well as description
|
|
*** use current year as default when no year specified
|
|
*** use journal from stdin when provided ?
|
|
*** allow price record for null commodity, eg with quotes
|
|
P 2009/1/1 "" 0.5h
|
|
and why doesn't this work ? time.journal:
|
|
P 2010/9/27 h 1
|
|
$ hledger -f time.journal bal -p aug -B
|
|
1
|
|
17.75h work:jobs
|
|
1
|
|
17.50h clearview
|
|
1 60 clear glass thermal data
|
|
0.25h admin:cheque issue
|
|
12.75h backups/hosting
|
|
2.00h cleanup
|
|
1.00h move plan
|
|
2.25h move prep
|
|
4.00h testing
|
|
3.50h speed
|
|
1.50h barbara spellcheck issue
|
|
0.50h installation report dates
|
|
0.25h plan change issue
|
|
1.00h planning/discussion
|
|
0.50h speed issue
|
|
0.25h tina quote low-e layout
|
|
0.50h tina title 24 issue
|
|
0.25h kcrw:admin:contract update:unbilled
|
|
--------------------
|
|
1
|
|
17.75h
|
|
|
|
*** register --wide and/or --format ...
|
|
*** --related
|
|
*** Double -> Decimal
|
|
*** parsing: safety check that effective date > actual (to catch eg 2009/12/30=1/4)
|
|
*** parsing: support @@
|
|
*** parsing: support D
|
|
*** parsing: accept all real-world ledger files
|
|
As far as I know it currently accepts all ledger 2.6-era files.
|
|
Add support for ledger 3 file format as/when that stabilises.
|
|
It would be nice to optionally report/upload parse errors when they happen.
|
|
*** talkback feature
|
|
gather data on real-world installation & usage issues
|
|
simplify bug reporting/handling
|
|
improve reliability
|
|
*** upload feature
|
|
*** payee & account anonymisation
|
|
*** easier timelog formats
|
|
*** add: completion etc.
|
|
*** convert: generalise/reuse add's history awareness
|
|
*** web: charts (Chart or google)
|
|
*** wide/customisable/consistent layout
|
|
*** effective/actual dates for postings
|
|
*** better web ui/gui
|
|
*** nice reports with charts
|
|
*** more automated bank data conversion
|
|
*** parse more file formats - gnucash, qif, ofx, csv..
|
|
*** download via ofx protocol
|
|
*** watching a changing ledger
|
|
*** more date syntax ? last nov, next friday, optional this, week of
|
|
*** more period syntax ? every N days, biweekly
|
|
*** accept multiple -f files
|
|
*** more reliable tidy layout from print
|
|
*** i18n
|
|
*** speed, memory usage
|
|
*** clear, documented interfaces/surfaces
|
|
*** plugin architecture/modular packaging
|
|
**** goals
|
|
***** allow separately-packaged functionality to be discovered at run-time and integrated within the hledger ui.
|
|
Example: user installs hledger-ofx package from hackage, or adds Ofx.hs to their ~/.hledger/plugins/;
|
|
then "ofx" is among the commands listed by hledger --help, and/or is a new command available in
|
|
the web and vty interfaces, and/or is a new file format understood by the convert command.
|
|
**** issues to consider
|
|
***** what is the api for plugins ?
|
|
they'll want to import Ledger lib, to work with ledger data structures
|
|
|
|
***** there are different kinds of "plugin". What could plugins provide ?
|
|
****** commands - for all uis, or for one or more of them (cli, web, vty..). A command may itself be a new ui.
|
|
****** import/export formats
|
|
****** skins/styles/templates for uis, eg the web ui ?
|
|
**** techniques to consider
|
|
***** running executables provided by plugins
|
|
a cli command plugin: cli execs the executable with same arguments
|
|
a web command plugin: web ui runs the executable as a subprocess and captures the output
|
|
***** linking plugins into main app with direct-plugins
|
|
simplification of plugins lib
|
|
main app needs to know the types used in plugin's interface
|
|
weakens type safety, avoiding runtime errors requires extra care
|
|
requires whole-program linking at plugin load time
|
|
plugins can be discovered by querying ghc for installed packages or modules in a known part of the hierarchy
|
|
maintained and keen to help
|
|
***** linking plugins into main app with plugins (original)
|
|
more complex than above
|
|
more type-safe/featureful ?
|
|
***** doing whatever xmonad does with dyre
|
|
***** interpreting plugins under control of main app with hint
|
|
ghci in an IO-like monad
|
|
types need converting, etc.
|
|
plugins may run more slowly
|
|
plugins can be discovered/loaded by module path or by loading files directly
|
|
|
|
|
|
* misc
|
|
** things I want to know
|
|
*** time
|
|
where have I been spending my time in recent weeks ?
|
|
where have I spent my time today ?
|
|
what is my status wrt spending plan for this week/month/year ?
|
|
what is my current status wrt time spending goals ?
|
|
*** money
|
|
where have I been spending my money ?
|
|
what is my status wrt spending plan for this week/month/year ?
|
|
what is my current status wrt spending/savings goals ?
|
|
what are all my current balances ?
|
|
what does my balance history look like ?
|
|
what does my balance future look like ?
|
|
are there any cashflow, tax, budgetary problems looming ?
|
|
*** charts
|
|
[1:27pm] <sm> I have decided I am not getting enough visible day-to-day value out of my ledger, I need more of that to stay motivated
|
|
[1:27pm] <Nafai> What do you think will help in that?
|
|
[1:27pm] <sm> I think some simple self-updating charts, or even good reports in a visible place
|
|
[1:28pm] <sm> something I don't have to spend an hour fiddling with to get answers
|
|
[1:38pm] <sm> Nafai: identifying/designing some useful reports/charts seems to be blocking me
|
|
[1:39pm] <sm> there are probably some standard ones I should use
|
|
[1:40pm] <sm> a graph of daily net worth is probably one of the simplest
|
|
[1:58pm] <sm> what else.. a chart of weekly expenses in key categories
|
|
[1:58pm] <sm> ditto, monthly
|
|
[1:58pm] <sm> a chart of monthly income
|
|
[1:59pm] <sm> those three should help me be more clear about cashflow status
|
|
[2:00pm] <sm> also I'd like something that shows me how much I am on top of financial tracking - how current my numbers are, when last reconciled etc - at a glance
|
|
[2:01pm] <sm> another simple one: current balances in all accounts
|
|
[2:01pm] <sm> those would be a great start
|
|
[2:04pm] <sm> daily net worth, weekly expense, monthly expense, monthly income, confidence/currentness report, and balance report
|
|
[2:05pm] <sm> let's see, which of those 6 would give most payoff right now
|
|
[2:05pm] <sm> probably 5
|
|
[2:06pm] <sm> how could I measure that ?
|
|
[2:06pm] <sm> number of days since last ledger entry..
|
|
[2:06pm] <sm> number of ledger entries in last 30 days (compared to average)
|
|
[2:07pm] <sm> number of days since last cleared checking entry (indicating an online reconcile)
|
|
[2:08pm] <sm> those would be a good start. How do I make those visual
|
|
[2:09pm] <sm> well I guess the first step is a script to print them
|
|
|
|
** data representation
|
|
*** http://www.python.org/dev/peps/pep-0327/
|
|
*** http://www.n-heptane.com/nhlab/repos/Decimal/
|
|
*** http://www.n-heptane.com/nhlab/repos/Decimal/Money.hs
|
|
*** http://www2.hursley.ibm.com/decimal/
|
|
** docs
|
|
*** http://en.wikibooks.org/wiki/Accounting
|
|
*** http://books.google.com/books?id=4V8pZmpwmBYC&lpg=PP1&dq=analysis%20patterns&pg=PA95#v=onepage&q&f=false
|
|
*** lwn grumpy editor articles
|
|
**** http://lwn.net/Articles/149383/
|
|
**** http://lwn.net/Articles/153043/
|
|
**** http://lwn.net/Articles/233627/
|
|
**** http://lwn.net/Articles/314577/
|
|
**** http://lwn.net/Articles/387967/ (free after 5/27)
|
|
*** hledger ghci examples
|
|
This is the main object you'll deal with as a user of the Ledger
|
|
library.
|
|
|
|
The most useful functions also have shorter, lower-case aliases for easier
|
|
interaction. Here's an example:
|
|
|
|
> > import Hledger.Data
|
|
> > j <- readJournal "sample.ledger"
|
|
> > let l = journalToLedger nullfilterspec j
|
|
> > accountnames l
|
|
> ["assets","assets:bank","assets:bank:checking","assets:bank:saving",...
|
|
> > accounts l
|
|
> [Account assets with 0 txns and $-1 balance,Account assets:bank with...
|
|
> > topaccounts l
|
|
> [Account assets with 0 txns and $-1 balance,Account expenses with...
|
|
> > account l "assets"
|
|
> Account assets with 0 txns and $-1 balance
|
|
> > accountsmatching ["ch"] l
|
|
> accountsmatching ["ch"] l
|
|
> [Account assets:bank:checking with 4 txns and $0 balance]
|
|
> > subaccounts l (account l "assets")
|
|
> subaccounts l (account l "assets")
|
|
> [Account assets:bank with 0 txns and $1 balance,Account assets:cash...
|
|
> > head $ transactions l
|
|
> 2008/01/01 income assets:bank:checking $1 RegularPosting
|
|
> > accounttree 2 l
|
|
> Node {rootLabel = Account top with 0 txns and 0 balance, subForest = [...
|
|
> > accounttreeat l (account l "assets")
|
|
> Just (Node {rootLabel = Account assets with 0 txns and $-1 balance, ...
|
|
> > datespan l -- disabled
|
|
> DateSpan (Just 2008-01-01) (Just 2009-01-01)
|
|
> > rawdatespan l
|
|
> DateSpan (Just 2008-01-01) (Just 2009-01-01)
|
|
> > ledgeramounts l
|
|
> [$1,$-1,$1,$-1,$1,$-1,$1,$1,$-2,$1,$-1]
|
|
> > commodities l
|
|
> [Commodity {symbol = "$", side = L, spaced = False, comma = False, ...
|
|
|
|
*** ledger budgeting/forecasting
|
|
seanh:
|
|
|
|
With `--budget` you can compare your budgeted transactions to your
|
|
actual transactions and see whether you are under or over your budget.
|
|
|
|
The way it works is this: say you have a budget entry that moves £50
|
|
from Assets into Expenses:Cash every week:
|
|
|
|
~ Weekly
|
|
Expenses:Cash £50
|
|
Assets
|
|
|
|
When you run register or balance with `--budget` ledger will insert
|
|
reverse transactions that move £50 _from_ Expenses:Cash _into_ Assets
|
|
every week. These are called budget entries. The idea is that your real
|
|
transactions that move money from Assets into Expenses will offset the
|
|
inserted budget entries that move money the other way. The budget
|
|
entries and the real transactions should sum to zero, if they don't then
|
|
it shows how much you have overspent or underspent.
|
|
|
|
For example:
|
|
|
|
ledger --budget balance '^expenses'
|
|
|
|
balances your budgeted expenses against your actual expenses on those
|
|
budgeted accounts (sub-accounts of expenses that do not appear in the
|
|
budget are ignored in this calculation). The sum of the budget entries
|
|
(which move money out of expenses accounts) and your real transactions
|
|
(which move money into expenses accounts) should be 0. If the sum is
|
|
positive then it shows how much you've overspent, if it's negative then
|
|
it shows how much you've underspent.
|
|
|
|
You can do the same with register and get a print out of each
|
|
transaction (budget entries and real transactions) with a running total:
|
|
|
|
ledger --budget register '^expenses'
|
|
|
|
And you can produce weekly, monthly or yearly budget reports:
|
|
|
|
ledger --budget --weekly register '^expenses'
|
|
ledger --budget --monthly register '^expenses'
|
|
ledger --budget --yearly register '^expenses'
|
|
|
|
These will only output reports for each week, month or year that has
|
|
passed (your ledger file contains transactions dated later than that
|
|
week, month, or year). You can see how well you did last week (or month,
|
|
or year) but you can't see how well you're doing so far this week
|
|
(month, year).
|
|
|
|
The `--unbudgeted` argument will show (and sum) all your expenses for
|
|
accounts that are _not_ budgeted, and the `--add-budget` argument will
|
|
consider all your expenses budgeted or not with the budget entries
|
|
added in.
|
|
|
|
With `--forecast` you can project your budget into the future to see,
|
|
for example, when some account will reach 0. For example, to predict
|
|
your net worth:
|
|
|
|
ledger --forecast 'd<[2012]' register '^assets' '^liabilities'
|
|
|
|
Or to see how your expenses will add up:
|
|
|
|
ledger --forecast 'd<[2012]' register '^expenses'
|
|
|
|
*** essential/getting started info
|
|
|
|
I've never used financial management software before, I'm just confused at what I'm doing.
|
|
http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system
|
|
money isn't created or destroyed, it moves between accounts
|
|
all possible accounts are organised under five categories: assets, liabilities, equity, income, expenses
|
|
|
|
the gist of it for *ledger users is that each transaction in your journal (file) is balanced, ie its postings add up to zero
|
|
typically you have a posting to some account (expenses:food $10) and an equal posting from another (assets:cash $-10)
|
|
|
|
so should things like income be a forever-decreasing value?
|
|
yes
|
|
|
|
I think traditional bookkeeping uses "debit" and "credit" for (among other things) hiding the negative sign
|
|
I wonder, if folks had been comfortable with negative numbers in the middle ages, if debit/credit would have been invented
|
|
|
|
so, when I start a ledger file and I start my initial account balances for, say, checking, I withdraw them from equity or income? Or does it matter in this case?
|
|
traditionally, you transfer opening balances from equity
|
|
and this is just a convention, or is there some better reason behind it?
|
|
I believe it's actually based on the real-world meaning, and makes sense if you study enough bookkeeping
|
|
I thought equity was more a share of something owned.
|
|
that's right, and if you squint enough the two uses are equivalent
|
|
So I'd do something like "assets:checking $foo \ assets:savings $bar \ liabilities:creditcard $-baz \ equity:opening balance"?
|
|
yes
|
|
|
|
what about loans? Those are liabilities, right?
|
|
yes
|
|
|
|
okay. So after I set up my initial account balances, it's just a matter of keeping track how and what I spend.
|
|
yup, tracking your checking account's or your wallet's inflows and outflows is a good way to start
|
|
Gradually you'll add more tricky things like invoices and short-term loans (accounts receivable/payable)
|
|
|
|
|
|
I also read in the manual that you can set up routine actions, like debiting from one account and crediting to another on a monthly basis.
|
|
this can help me set up budgets, right?
|
|
yes, ledger lets you specify those with special modifier/periodic transactions. They appear in reports but not in your journal file. Or you can use cron or something to actually add them to the journal
|
|
and there's also a budget report feature
|
|
|
|
a catalog of standard bookkeeping entries for typical real-world transactions is really helpful and worth searching for
|
|
|
|
** software
|
|
*** http://gnucash.org
|
|
*** http://www.xtuple.com/postbooks
|
|
*** http://weberp.org
|
|
**** http://www.weberp.org/weberp/doc/Manual/ManualContents.php
|
|
** selinger article on currency & capital gains accounting
|
|
http://www.mscs.dal.ca/~selinger/accounting/tutorial.html#1.2
|
|
** hledger feedback
|
|
*** fabrice niessen
|
|
+For me, what would be very useful for a 1.0 version would be:
|
|
+
|
|
+- @check directive (see beancount), but implemented as a comment for ledger,
|
|
+ so that ledger does not get confused by this, and that you can implement
|
|
+ more features without breaking backward compatibility;
|
|
+
|
|
+- account declaration (see beancount), in ledger comments. Giving an account
|
|
+ number would (or could) help for the reporting stuff, for knowing which
|
|
+ value to get to read, for inserting in a given report;
|
|
+
|
|
+- some built-in ratios for being able to see the health of the finances (see
|
|
+ my Excel file, if you're interested);
|
|
+
|
|
+- easier standard outputs, such as the one above (with expenses and income in
|
|
+ 2 columns).
|
|
+
|
|
+- real report generation (I thought at LaTeX as in SQL Ledger, but I am now
|
|
+ heading and producing reports through Org, which is 1000x better). Results
|
|
+ soon.
|
|
+
|
|
|
|
** hamlet feedback
|
|
*** thread data through nested templates with Reader monad
|
|
*** HDString constructor for HamletData ?
|
|
*** data type for non-RT Hamlet as well, or better, the same type for both
|
|
*** allow (RT or non-RT) templates in $ $ as well, drop ^ ^
|
|
*** allow literal arguments in references
|
|
*** easier verbatim content quoting, eg lines starting with \\. Having to escape $$ is not so convenient for jquery
|
|
*** docs and compiler errors should say something clearer than "Hamlet url" (Hamlet routetype, urltype, routet, urlt ?)
|
|
|
|
|
|
*** 2010/8
|
|
**** $ $ could handle templates as well; drop ^ ^
|
|
**** @ @ could recognise tuples automatically; drop ?
|
|
**** why !: : for conditional attributes ? How about !? ?
|
|
|
|
** code snippets
|
|
|
|
fromOfxTransaction :: StatementTransaction -> LedgerTransaction
|
|
fromOfxTransaction StatementTransaction {
|
|
stType = _ --sttype -- :: TransactionType
|
|
,stDatePosted = stdateposted -- :: Maybe UTCTime
|
|
,stAmount = stamount -- :: Decimal
|
|
,stCheckNumber = stchecknumber -- :: Maybe Int
|
|
,stFITID = _ --stfitid -- :: String
|
|
,stSIC = _ --stsic -- :: Maybe String
|
|
,stName = stname -- :: String
|
|
} =
|
|
LedgerTransaction {
|
|
ltdate = date -- :: Day,
|
|
,ltstatus = stat -- :: Bool,
|
|
,ltcode = code -- :: String,
|
|
,ltdescription = desc -- :: String,
|
|
,ltcomment = com -- :: String,
|
|
,ltpostings = ps -- :: [Posting],
|
|
,ltpreceding_comment_lines = prec -- :: String
|
|
}
|
|
where
|
|
date = maybe (error "found an undated bank transaction, giving up") utctDay stdateposted
|
|
stat = False
|
|
code = maybe "" show stchecknumber
|
|
desc = stname
|
|
com = ""
|
|
ps = [
|
|
Posting False "UNKNOWN" a "" RegularPosting,
|
|
Posting False "CHECKING" (-a) "" RegularPosting
|
|
]
|
|
prec = ""
|
|
a = Mixed [dollars $ fromDecimal stamount]
|
|
fromDecimal d = fromIntegral (decimalMantissa d) / (10 ^ decimalPlaces d)
|
|
|
|
|
|
Name: test
|
|
Version: 0.1
|
|
Synopsis: test package for linking against internal libraries
|
|
Author: Stefan Wehr
|
|
Build-type: Simple
|
|
Cabal-version: >=1.8 -- IMPORTANT
|
|
|
|
Library
|
|
Hs-source-dirs: lib -- IMPORTANT
|
|
Exposed-modules: A
|
|
Build-Depends: base >= 4
|
|
|
|
Executable test-exe
|
|
Build-depends: base >= 4, test, -- link against the internal library
|
|
Main-is: Main.hs -- imports A
|
|
Hs-source-dirs: prog -- IMPORTANT
|
|
|
|
|
|
-- trace a MixedAmount
|
|
matrace :: MixedAmount -> MixedAmount
|
|
matrace a@(Mixed as) = trace (show as) a
|
|
|
|
-- normalise and trace a MixedAmount
|
|
nmatrace :: MixedAmount -> MixedAmount
|
|
nmatrace a = trace (show as) a where (Mixed as) = normaliseMixedAmount a
|
|
|
|
-- cabal test
|
|
import System.FilePath
|
|
main = defaultMainWithHooks $ simpleUserHooks { runTests = runTests' }
|
|
runTests' :: Args -> Bool -> PackageDescription -> LocalBuildInfo -> IO ()
|
|
runTests' _ _ _ lbi = system testprog >> return ()
|
|
where testprog = (buildDir lbi) </> "hledger" </> "hledger test"
|
|
|
|
-- queryStringFromAP a p = if null ap then "" else "?" ++ ap
|
|
-- where
|
|
-- ap = intercalate "&" [a',p']
|
|
-- a' = if null a then "" else printf "&a=%s" a
|
|
-- p' = if null p then "" else printf "&p=%s" p
|
|
|
|
-- toggleScriptFor name = [$hamlet|
|
|
-- <script type="text/javascript">
|
|
-- function $name$Toggle() {
|
|
-- e = document.getElementById('$name$');
|
|
-- link = document.getElementById('$name$link');
|
|
-- if (e.style.display == 'none') {
|
|
-- link.style['font-weight'] = 'bold';
|
|
-- e.style.display = 'block';
|
|
-- } else {
|
|
-- link.style['font-weight'] = 'normal';
|
|
-- e.style.display = 'none';
|
|
-- }
|
|
-- return false;
|
|
-- }
|
|
-- </script>
|
|
-- |]
|
|
|
|
-- group register report items by transaction
|
|
groupeditems [] = []
|
|
groupeditems items = is:(groupeditems js)
|
|
where (is,js) = span (\(ds,_,_) -> isNothing ds) items
|
|
|
|
|
|
/* html, body {height: 100%} */
|
|
/* #content {min-height: 100%} */
|
|
/* #editform textarea { height:100%; } */
|
|
|
|
/* input:focus { background-color: #efe; } */
|
|
|
|
/* a.tooltip {position: relative} */
|
|
/* a.tooltip span {display:none; padding:5px; width:200px;} */
|
|
/* a:hover {background:#fff;} /\*background-color is a must for IE6*\/ */
|
|
/* a.tooltip:hover span{display:inline; position:absolute;} */
|
|
|
|
/* div#page {width: 960px; margin: 0 auto} */
|
|
|
|
/* div#container {height: 35px; line-height: 35px} */
|
|
|
|
/* div#content {position: absolute; top: 50%; height: 500px; margin-top: -250px} */
|
|
|
|
/* div#content {position: absolute; top: 50%; left:50%; width:800px; height: 500px; margin-left: -400px; margin-top: -250px} */
|
|
|
|
/* div#button {background: #888; border: 1px solid; border-color: #999 #777 #777 #999 } */
|
|
|
|
/* .element {border-radius: 5px} */
|
|
|
|
; prototype "equalising" transactions
|
|
;
|
|
; generate a transfer between alice & bob equalising their contribution to rent's 5/1 balance
|
|
; A 2010/5/1 expenses:rent
|
|
; alice 50%
|
|
; bob 50%
|
|
|
|
; generate a transfer between alice & bob such that alice's contribution to car payment's 5/1 balance is $100
|
|
; A 2010/5/1 expenses:car:payment
|
|
; alice $100
|
|
; bob
|
|
|
|
; A 2010/5/1 expenses:car not:expenses:car:payment
|
|
; alice 50%
|
|
; bob
|
|
|
|
; A 2010/5/1 expenses:food
|
|
; alice
|
|
; bob
|
|
|
|
; A 2010/5/1 expenses:home
|
|
; alice
|
|
; bob
|
|
|
|
; A 2010/5/1 expenses:utilities
|
|
; alice
|
|
; bob
|
|
|
|
|
|
maybeFileInput :: String -> FormInput sub master (Maybe FileInfo)
|
|
maybeFileInput name = GForm $ \_ env -> do
|
|
let res = FormSuccess $ lookup name env
|
|
return (res, [addBody [$hamlet|
|
|
%input!type=file!name=$name$
|
|
|]], Multipart)
|
|
|
|
-- handler for add form auto-complete requests
|
|
-- <?php
|
|
-- header("Content-type:text/xml");
|
|
-- ini_set('max_execution_time', 600);
|
|
-- require_once('../../common/config.php');
|
|
-- print("<?xml version=\"1.0\"?>");
|
|
|
|
-- $link = mysql_pconnect($mysql_host, $mysql_user, $mysql_pasw);
|
|
-- $db = mysql_select_db ($mysql_db);
|
|
|
|
-- if (!isset($_GET["pos"])) $_GET["pos"]=0;
|
|
|
|
-- //Create database and table if doesn't exists
|
|
-- //mysql_create_db($mysql_db,$link);
|
|
-- $sql = "Select * from Countries";
|
|
-- $res = mysql_query ($sql);
|
|
-- if(!$res){
|
|
-- $sql = "CREATE TABLE Countries (item_id INT UNSIGNED not null AUTO_INCREMENT,item_nm VARCHAR (200),item_cd VARCHAR (15),PRIMARY KEY ( item_id ))";
|
|
-- $res = mysql_query ($sql);
|
|
-- populateDBRendom();
|
|
-- }else{
|
|
--
|
|
-- }
|
|
-- //populate db with 10000 records
|
|
-- function populateDBRendom(){
|
|
-- $filename = getcwd()."../../common/countries.txt";
|
|
-- $handle = fopen ($filename, "r");
|
|
-- $contents = fread ($handle, filesize ($filename));
|
|
-- $arWords = split("\r\n",$contents);
|
|
-- //print(count($arWords));
|
|
-- for($i=0;$i<count($arWords);$i++){
|
|
-- $nm = $arWords[$i];
|
|
-- $cd = rand(123456,987654);
|
|
-- $sql = "INsert into Countries(item_nm,item_cd) Values('".$nm."','".$cd."')";
|
|
-- mysql_query ($sql);
|
|
-- if($i==9999)
|
|
-- break;
|
|
-- }
|
|
-- fclose ($handle);
|
|
-- }
|
|
|
|
-- getDataFromDB($_GET["mask"]);
|
|
-- mysql_close($link);
|
|
|
|
|
|
|
|
-- //print one level of the tree, based on parent_id
|
|
-- function getDataFromDB($mask){
|
|
-- $sql = "SELECT DISTINCT item_nm FROM Countries Where item_nm like '".mysql_real_escape_string($mask)."%'";
|
|
-- $sql.= " Order By item_nm LIMIT ". $_GET["pos"].",20";
|
|
|
|
-- if ( $_GET["pos"]==0)
|
|
-- print("<complete>");
|
|
-- else
|
|
-- print("<complete add='true'>");
|
|
-- $res = mysql_query ($sql);
|
|
-- if($res){
|
|
-- while($row=mysql_fetch_array($res)){
|
|
-- print("<option value=\"".$row["item_nm"]."\">");
|
|
-- print($row["item_nm"]);
|
|
-- print("</option>");
|
|
-- }
|
|
-- }else{
|
|
-- echo mysql_errno().": ".mysql_error()." at ".__LINE__." line in ".__FILE__." file<br>";
|
|
-- }
|
|
-- print("</complete>");
|
|
-- }
|
|
-- ?>
|
|
|
|
|
|
* journal
|
|
** 2010
|
|
*** 5/4
|
|
**** balance sheet pomodoro 1
|
|
started balance sheet script
|
|
began refactoring for importable Hledger.Cli.*
|
|
set up missing tools on netbook: haskell-mode
|
|
adapt to distro & ghc 6.12 upgrade
|
|
install missing cabal packages
|
|
tighten dependency to avoid testpack 2.0 api change
|
|
ghc-pkg dump error
|
|
**** balance sheet pomodoro 2
|
|
set up work log
|
|
adapt to distro & ghc 6.12 upgrade: ghc-pkg dump error (cabal clean)
|
|
tools setup: hasktags
|
|
move Options to Hledger.Cli
|
|
got trivial balancesheet script working
|
|
deal with darcs mv screwup
|
|
*** 5/6
|
|
**** review/cleanup pomodoro
|
|
review/record pending changes
|
|
develop work log/backlog
|
|
website hakyll conversion
|
|
*** 5/19
|
|
researched current web libs
|
|
finished move to Hledger module space
|
|
cleaned up notes
|
|
*** 5/20
|
|
converted manual to markdown
|
|
more detailed installation docs
|
|
*** 5/21
|
|
upgraded hakyll
|
|
fixed hakyll/pandoc quotes issue
|
|
*** 5/22
|
|
refactored journal/ledger construction
|
|
updated benchmarks
|
|
resolved register memory leak
|
|
*** 5/23
|
|
clarified Journal & Ledger roles
|
|
various 6.12, utf8 and other fixes
|
|
released 0.10
|
|
|
|
*** 5/24
|
|
implemented --flat, --drop
|
|
*** 5/25
|
|
support, investigated rounding issue
|