mirror of
https://github.com/aclindsa/moneygo.git
synced 2024-10-30 07:40:05 -04:00
Add markdown documentation
This commit is contained in:
parent
aeed78f0b7
commit
5047dc6948
@ -9,6 +9,10 @@ OFX (via [ofxgo](https://github.com/aclindsa/ofxgo)).
|
||||
This project is in active development and is not yet ready to be relied upon as
|
||||
your primary accounting software.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Documentation in markdown](./docs/index.md)
|
||||
|
||||
## Installation
|
||||
|
||||
First, install npm, python, curl, and go >= 1.7 in your distribution. Here is
|
||||
|
@ -107,6 +107,8 @@ func luaAccount__index(L *lua.LState) int {
|
||||
} else {
|
||||
panic("SecurityId not in lua security_map")
|
||||
}
|
||||
case "SecurityId", "securityid":
|
||||
L.Push(lua.LNumber(float64(a.SecurityId)))
|
||||
case "Parent", "parent", "ParentAccount", "parentaccount":
|
||||
if a.ParentAccountId == -1 {
|
||||
L.Push(lua.LNil)
|
||||
|
4
docs/index.md
Normal file
4
docs/index.md
Normal file
@ -0,0 +1,4 @@
|
||||
# MoneyGo Documentation
|
||||
|
||||
* [Lua Reports](lua_reports.md)
|
||||
* [Importing Transactions using OFX](ofx_imports.md)
|
155
docs/lua_reports.md
Normal file
155
docs/lua_reports.md
Normal file
@ -0,0 +1,155 @@
|
||||
# Lua Reports
|
||||
|
||||
MoneyGo reports are written in [Lua](https://lua.org), as implemented by
|
||||
[github.com/yuin/gopher-lua](https://github.com/yuin/gopher-lua), with hooks
|
||||
added to query the necessary MoneyGo state to generate the report.
|
||||
|
||||
## An Example: Monthly Cash Flow Report
|
||||
|
||||
Before diving into the details, here's an example report that calculates the
|
||||
difference between income and expenses for each month in the current year:
|
||||
|
||||
```
|
||||
function generate()
|
||||
year = date.now().year
|
||||
|
||||
accounts = get_accounts()
|
||||
t = tabulation.new(12)
|
||||
t:title(year .. " Monthly Cash Flow")
|
||||
series = t:series("Income minus expenses")
|
||||
|
||||
for month=1,12 do
|
||||
begin_date = date.new(year, month, 1)
|
||||
end_date = date.new(year, month+1, 1)
|
||||
|
||||
t:label(month, tostring(begin_date))
|
||||
cash_flow = 0
|
||||
|
||||
for id, acct in pairs(accounts) do
|
||||
if acct.type == account.Expense or acct.type == account.Income then
|
||||
balance = acct:balance(begin_date, end_date)
|
||||
--[[
|
||||
Note: We should convert balance.amount to the user's default currency
|
||||
before proceeding here
|
||||
--]]
|
||||
cash_flow = cash_flow - balance.amount
|
||||
end
|
||||
end
|
||||
series:value(month, cash_flow)
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
```
|
||||
|
||||
## Basic Operation
|
||||
|
||||
The lua code behind a report *must* contain a `generate()` function which takes
|
||||
no arguments. This function is called when generating a report, and must return
|
||||
a `tabulation` object, created by calling `t = tabulation:new(n)`, where `n` is
|
||||
the integer number of data values in each of the series of this tabulation (all
|
||||
series in the same tabulation must have the same number of values).
|
||||
|
||||
### Titles and Labels
|
||||
|
||||
Assuming your tabulation object is `t`, you should then call `t.label(m,
|
||||
"some_string")` for each value of `m` in `[1, n]` to set the label for the 'm'th
|
||||
data element in each series. You do not need to do this before creating series,
|
||||
and can do it lazily as you generate data, if needed. Titles, subtitles, and the
|
||||
y-axis label (the units) can be set as follows on a tabulation object named `t`:
|
||||
|
||||
* `t.title("The title of my report")`
|
||||
* `t.subtitle("The subtitle of my report")`
|
||||
* `t.units("USD ($)")`
|
||||
|
||||
### Data Series
|
||||
|
||||
To create a new top-level series, call `s = t:series("series name")` where `t`
|
||||
is a tabulation object. Just as for labels for tabulation objects, you set
|
||||
`s:value(m, number)` for each value of `m` in `[1, n]` (where `n` is the same
|
||||
integer used to create the tabulation object to which this series belongs).
|
||||
|
||||
Nested series can be created by calling `s2 = s:series("nested series name")`,
|
||||
where `s` is any already-created series object. Nested series allow for drilling
|
||||
down to explore the information in more detail. In the web interface, they are
|
||||
clickable and cause the charts to display the selected series as the new top
|
||||
level.
|
||||
|
||||
It is assumed that nested series' reported values are not already included in
|
||||
their parents' values. When being displayed, all the children series values are
|
||||
added into the parent's. This means that a series may have no values of its own,
|
||||
but still show up in a chart because it is reporting the sum of its children's
|
||||
values.
|
||||
|
||||
## Gathering Data
|
||||
|
||||
Collecting/tabulating the data is up to you (chasing this flexibility was the
|
||||
impetus behind Lua reports in the first place).
|
||||
|
||||
### Accounts and Balances
|
||||
|
||||
You can get a table of account objects for each of your accounts (indexed by
|
||||
account ID) by calling the global function, `get_accounts()`. Each of these
|
||||
accounts has several fields describing it:
|
||||
|
||||
* `a.Name` returns the account's name
|
||||
* `a.Description` returns the account's description
|
||||
* `a.Type` returns the account's type, as an integer constant. The account type
|
||||
constants are available on the top-level 'account' object
|
||||
* `account.Bank`
|
||||
* `account.Cash`
|
||||
* `account.Asset`
|
||||
* `account.Liability`
|
||||
* `account.Investment`
|
||||
* `account.Income`
|
||||
* `account.Expense`
|
||||
* `account.Trading`
|
||||
* `account.Equity`
|
||||
* `account.Receivable`
|
||||
* `account.Payable`
|
||||
* `a.TypeName` returns a string representation of the account's type
|
||||
* `a.Security` returns a security object representing the currency, stock, etc.
|
||||
of this account.
|
||||
* `a.Parent` returns this account's parent account, or nil if the account has no
|
||||
parent.
|
||||
* `a:Balance` is a function which returns the account balance in the account's
|
||||
security, optionally over a date range. If no arguments are provided, the
|
||||
total account balance as of the end of time is returned. If one date is
|
||||
provided, the balance as of that date is returned. If two dates are provided,
|
||||
the difference in balances between the first and second dates is returned.
|
||||
|
||||
### Securities
|
||||
|
||||
You can get a table containing all the securities/currencies registered to an
|
||||
account using the global function `get_securities()`. Each of these securities
|
||||
has several fields describing it:
|
||||
|
||||
* `s.SecurityId`
|
||||
* `s.Name`
|
||||
* `s.Description`
|
||||
* `s.Symbol` returns the symbol traditionally associated with that security
|
||||
(i.e. '$' for USD, or BRK.B for class B shares of Berkshire Hathaway)
|
||||
* `s.Precision` returns the number of digits of precision past the decimal point
|
||||
that this currency allows for (i.e. 2 for USD)
|
||||
* `s.Type` returns an int constant which represents what type of security it is
|
||||
(i.e. stock or currency)
|
||||
|
||||
You can also query for an account's default currency using the global
|
||||
`get_default_currency()` function.
|
||||
|
||||
### Dates
|
||||
|
||||
In order to make it easier to do operations like finding account balances for a
|
||||
month at a time, MoneyGo implements it's own date type (eschewing the
|
||||
traditional Lua implementation). You *must* use the MoneyGo date types when
|
||||
passing them to any MoneyGo lua functions. To create a date object, you can use
|
||||
one of two methods:
|
||||
|
||||
1. `date.now()` returns the current date
|
||||
2. `date.new(2017, 7, 5)` returns a date object representing July 5th, 2017.
|
||||
Note that this method also accepts a single argument of a table with the
|
||||
'year', 'month', and 'day' fields set to int's.
|
||||
|
||||
In addition to supporting conversion to a string, addition, subtraction, and
|
||||
comparison operators, dates support returning their constituent parts using
|
||||
`d.Year`, `d.Month`, and `d.Day`.
|
@ -37,6 +37,36 @@ func luaContextGetSecurities(L *lua.LState) (map[int64]*Security, error) {
|
||||
return security_map, nil
|
||||
}
|
||||
|
||||
func luaContextGetDefaultCurrency(L *lua.LState) (*Security, error) {
|
||||
security_map, err := luaContextGetSecurities(L)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := L.Context()
|
||||
|
||||
user, ok := ctx.Value(userContextKey).(*User)
|
||||
if !ok {
|
||||
return nil, errors.New("Couldn't find User in lua's Context")
|
||||
}
|
||||
|
||||
if security, ok := security_map[user.DefaultCurrency]; ok {
|
||||
return security, nil
|
||||
} else {
|
||||
return nil, errors.New("DefaultCurrency not in lua security_map")
|
||||
}
|
||||
}
|
||||
|
||||
func luaGetDefaultCurrency(L *lua.LState) int {
|
||||
defcurrency, err := luaContextGetDefaultCurrency(L)
|
||||
if err != nil {
|
||||
panic("luaGetDefaultCurrency couldn't fetch default currency")
|
||||
}
|
||||
|
||||
L.Push(SecurityToLua(L, defcurrency))
|
||||
return 1
|
||||
}
|
||||
|
||||
func luaGetSecurities(L *lua.LState) int {
|
||||
security_map, err := luaContextGetSecurities(L)
|
||||
if err != nil {
|
||||
@ -62,9 +92,13 @@ func luaRegisterSecurities(L *lua.LState) {
|
||||
L.SetField(mt, "__metatable", lua.LString("protected"))
|
||||
getSecuritiesFn := L.NewFunction(luaGetSecurities)
|
||||
L.SetField(mt, "get_all", getSecuritiesFn)
|
||||
getDefaultCurrencyFn := L.NewFunction(luaGetDefaultCurrency)
|
||||
L.SetField(mt, "get_default", getDefaultCurrencyFn)
|
||||
|
||||
// also register the get_securities function as a global in its own right
|
||||
// also register the get_securities and get_default functions as globals in
|
||||
// their own right
|
||||
L.SetGlobal("get_securities", getSecuritiesFn)
|
||||
L.SetGlobal("get_default_currency", getDefaultCurrencyFn)
|
||||
}
|
||||
|
||||
func SecurityToLua(L *lua.LState, security *Security) *lua.LUserData {
|
||||
|
Loading…
Reference in New Issue
Block a user