Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
beancount-interpolate
Advanced tools
Four plugins for double-entry accounting system Beancount to interpolate transactions by generating additional entries over time.
They are:
recur
: dublicates all entry postings over timesplit
: dublicates all entry postings over time at fraction of valuedepr
: generates new entries to depreciate target asset/liability posting over given periodspread
: generate new entries to allocate P&L of target income/expense posting over given periodThese plugins are triggered by adding metadata or tags to source entries. It's safe to disable at any time. All plugins share the same parser that can set maximal period, custom starting date and minimal step by either number or keyword.
You can use these to define recurring transactions, account for depreciation, smooth transactions over time and make graphs less zig-zag.
This
depr
is not yet compatible with any accounting standards. For tax-compatible yearly depreciation take a look at this plugin by Alok Parlikar under MIT license. All contributions to improvedepr
are welcome.
pip3 install beancount_interpolate --user
Or copy to path used for python. For example, $HOME/.local/lib/python3.7/site-packages/beancount_interpolate/*
would do on Debian. If in doubt, look where beancount
folder is and copy next to it.
Let's say John has only two activities
If we plot John's wealth, it would look like zig-zag and be negative between -150 EUR (right after salary) and -450 EUR (right before), that is big and unstable error for your current wealth. And there could be more incomes/expenses with various 'periods'. In most complicated case John would have multiple income/expense sources with various lenght periods that are unsynchronised, but John wants dashboard with graph of correct daily report on his wealth.
Possible solutions:
Enable the plugin (see available options below).
plugin "beancount_interpolate.spread"
Add meta or tags to your transactions. All folllowing transactions does the same.
; Explicit.
2016-06-15 * "The Company" "Simplest salary entry"
Income:TheCompany:NetSalary -310.00 EUR
spreadAfter: "Month @ 2016-05-01"
Assets:MyBank:Checking 310.00 EUR
; Transaction meta applies to all Income/Expense postings if they don't have their own.
2016-06-15 * "The Company" "Simplest salary entry"
spreadAfter: "Month @ 2016-05-01"
Income:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
; Use spreadBefore if that reads better in your case.
2016-06-15 * "The Company" "Simplest salary entry"
spreadBefore: "Month @ 2016-05-31"
Income:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
; Use default period.
2016-06-15 * "The Company" "Simplest salary entry"
spreadAfter: "2016-05-01"
Income:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
; Use date of transaction.
2016-06-15 * "The Company" "Simplest salary entry"
spreadAfter: "Month"
Income:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
; Use date of transaction and default period. Beware the different transaction date.
2016-05-01 * "The Company" "Simplest salary entry" #spreadAfter
Income:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
First, plugin edits the original transaction like this:
2016-05-01 * "The Company" "Simplest salary entry (Generated by interpolate-spread)" #spread
Liabilities:Current:TheCompany:NetSalary -310.00 EUR
Assets:MyBank:Checking 310.00 EUR
Second, plugin inserts 30 or 31 transactions from 2016-05-01 to 2016-05-31 like this:
2016-05-xx * "The Company" "Simplest salary entry (Generated by interpolate-spread)" #spread
Income:TheCompany:NetSalary -10.00 EUR
Liabilities:Current:TheCompany:NetSalary 10.00 EUR
The content of meta tag consists of 5 parts, every of them optional:
x
, a whole number. Defaults to 1.period
, a case-insensitive keyword "day[s]", "week[s]", "month[s]" or "year[s]". Defaults to "day".@
sign. Defaults to transaction date.m
, a whole number. Defaults to 1.step
size, can be either keyword from as period. Defaults to "day".Summary: [x] [period] [@ YYYY-MM[-DD]] [/ [m] [step]]
You want to make recurring entry every X days until forever (or some Y days have passed). Recur will duplicate tagged entry for you!
Enable the plugin (see available options below).
plugin "beancount_interpolate.recur"
In fact, the argumentation is the same as in spread
, but the only difference is that different usecases needs a bit different treatment. For example, our John want to set aside money for savings daily. To account for it nicely, spread
won't do - we don't need any Liabilities:Current:...
accounts generated for us. A simple duplication will do here.
Enable the plugin (see available options below).
plugin "beancount_interpolate.split"
Add meta or tags to your transactions. All folllowing transactions does the same.
; Explicit.
2016-01-01 * "Me" "Set aside money for savings"
split: "Year"
Assets:MyBank:Checking -365.00 EUR
Assets:MyBank:Savings 365.00 EUR
; In fact, original date doesn't matter here, as original entry will be deleted.
2016-06-15 * "Me" "Set aside money for savings"
splitAfter: "Year @ 2016-01-01"
Assets:MyBank:Checking -365.00 EUR
Assets:MyBank:Savings 365.00 EUR
; Use can also use tags.
2016-01-01 * "Me" "Set aside money for savings" #split
Assets:MyBank:Checking -365.00 EUR
Assets:MyBank:Savings 365.00 EUR
First, plugin deletes the original transaction.
Second, plugin inserts transactions every day until today, included.
2016-01-01 * "Me" "Set aside money for savings (Generated by interpolate-split)" #split
Assets:MyBank:Checking -1.00 EUR
Assets:MyBank:Savings 1.00 EUR
2016-01-02 * "Me" "Set aside money for savings (Generated by interpolate-split)" #split
Assets:MyBank:Checking -1.00 EUR
Assets:MyBank:Savings 1.00 EUR
...
Depreciate technically is the same as spread but from other way around. But practically, you would like to have different settings for your short-term spreads and long-term depreciations.
Enable the plugin (see available options below).
plugin "beancount_interpolate.depr"
Add meta or tags to your transactions. All folllowing transactions does the same.
; Explicit.
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting"
Assets:Fixed:PC 199.00 EUR
depr: "Year @ 2016-06-15"
Assets:MyBank:Checking -199.00 EUR
; Transaction meta applies to all Assets:Fixed postings if depr is entry-wide.
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting"
depr: "Year @ 2016-06-15"
Assets:Fixed:PC 199.00 EUR
Assets:MyBank:Checking -199.00 EUR
; Use default period (Year).
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting"
depr: "Year"
Assets:Fixed:PC 199.00 EUR
Assets:MyBank:Checking -199.00 EUR
; Use date of transaction.
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting"
depr: "Month"
Assets:Fixed:PC 199.00 EUR
Assets:MyBank:Checking -199.00 EUR
; Use default period (Year) and default date (entry date).
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting"
depr: "empty string or some nonsense"
Assets:Fixed:PC 199.00 EUR
Assets:MyBank:Checking -199.00 EUR
; Use default period (Year) and default date (entry date) using a tag.
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting" #depr
Assets:Fixed:PC 199.00 EUR
Assets:MyBank:Checking -199.00 EUR
Plugin inserts lots of transactions starting from given date until end (or today) like this:
2016-06-15 * "CornerStore" "Bought new Laptop to do beancounting (depr 1/365)" #depred
Assets:Fixed:PC -00.55 EUR
Expenses:Depreciation:PC 00.55 EUR
2016-06-16 * "CornerStore" "Bought new Laptop to do beancounting (depr 2/365)" #depred
Assets:Fixed:PC -00.54 EUR
Expenses:Depreciation:PC 00.54 EUR
In Beancount, options are passed to plugins as second argument and may be multi-line.
To beancount_interpolate
options have to be formatted as valid JSON.
Options that applies to all four plugins:
aliases_after
- list of strings to look for in meta and tags.default_duration
- integer or string of keyword that plugin will default duration to, if none was provided in mark.default_step
- integer that plugin will default step to, if none was provided in mark.min_value
- decimal that will be the minimal value of leg within created transactions.max_new_tx
- integer that will be the maximal amount of newly created transactions.suffix
- string appended to created transaction annotations. Two variables are n-th transaction and total amount of transactions.tag
- string that as tag will be applied to all created transactions.Options that applies only to spread
and depr
. For spread
new transactions are created under account name where account_expense
and account_income
prefixes are swapped to account_assets
or account_liab
prefixes respectively. For depr
that other way around: account_assets
and account_liab
prefixes are swapped to account_expense
and account_income
prefixes instead.
account_income
account_expenses
account_assets
account_liab
Here are all available options and their default values. Options are passed as serialized object to the plugin.
plugin "beancount_interpolate.recur" "{
'aliases_after': ['recurAfter', 'recur'],
'default_duration': 'Infinite',
'default_step': 'Day',
'default_method': 'SL',
'min_value': 0.05,
'max_new_tx': 9999,
'suffix': ' (recur %d/%d)',
'tag': 'recurred'
}"
plugin "beancount_interpolate.split" "{
'aliases_after': ['splitAfter', 'split'],
'default_duration': 'Month',
'default_step': 'Day',
'default_method': 'SL',
'min_value': 0.05,
'max_new_tx': 9999,
'suffix': ' (split %d/%d)',
'tag': 'splitted'
}"
plugin "beancount_interpolate.spread" "{
'account_income': 'Income',
'account_expenses': 'Expenses',
'account_assets': 'Assets:Current',
'account_liab': 'Liabilities:Current',
'aliases_after': ['spreadAfter', 'spread'],
'default_duration': 'Month',
'default_step': 'Day',
'default_method': 'SL', # Straight Line
'min_value': 0.05, # cannot be smaller than 0.01
'max_new_tx': 9999,
'suffix': ' (spread %d/%d)',
'tag': 'spreaded'
}"
plugin "beancount_interpolate.depr" "{
'account_income': 'Income:Appreciation',
'account_expenses': 'Expenses:Depreciation',
'account_assets': 'Assets:Fixed',
'account_liab': 'Liabilities:Fixed',
'aliases_after': ['deprAfter', 'depr'],
'default_duration': 'Year',
'default_step': 'Day',
'min_value': 0.05, # cannot be smaller than 0.01
'max_new_tx': 9999,
'suffix': ' (depr %d/%d)',
'tag': 'depred'
}"
aliases_after
If any of aliases are found in transaction tag, transaction meta or posting meta, then the plugin will be applied.
default_duration
Default duration to apply when one is not specified explicitly. Note that month and year keywords do not adapt to current period, but are simple constants (PR welcome!)
default_step
Default step to apply when one is not specified explicitly. In fact, currently it is not possible to specify it explicitly on per-case basis (PR welcome!)
min_value
Minimal value of leg when for new created transactions. It will try to do so Here's example how it works:
For example, you want to spread your groceries 10.00 USD over 7 days, but it apparently doesn't divide nicely. So,
The min_value
is required to be at least 0.01 by beancount, but I'd recommend to raise it even further to avoid "1-cent spam" that lowers readability of reports and impacts performance.
There's an interesting behavior for transactions that are very small. If on any day the allocation is smaller by min_value
for any of legs, the transaction on that day is not generated and put aside in full. Thus, such small transactions tend to happen once in a while with min_value
amount. Even more funny, if there are more than one posting with small amount, those postings keep their "put aside" values seperaly - it may happen that at some day there will be a transaction with both of postings, effectively giving double of min_value
. It may be hard to those little postings in reports, and I doubt that anyone would care about them at all, the best place to look at is the source.
max_new_tx
Caps the max new transactions generated for one entry. By default set to 9999, looks like working but is not tested.
suffix
Suffix is string appended to created transaction annotations. It has two variables within in the given order:
tag
String that as tag will be applied to all created transactions.
The source contains five files - one per plugin and commons. Plugins have very similar structure in pairs: spread is similar to depreciate, and recur is similar to split.
Please see Makefile and inline comments.
Note: there's a branch single-plugin-refactor
that's a up-for-grabs WIP based on v2 by @benedictvh. See #8 #9, #12 for details.
Source | Author | git | tests | Updated | PyPI | Docs | Comment |
---|---|---|---|---|---|---|---|
beancount_interpolate.depr | Akuukis | ✅ | ✅ | 2021-01 | Readme | ||
parallel_average_cost | Falsifian | ❌ | ✅ | 2021-03 | ❌ | Discussion | This plugin is intended to help when you need to calculate your capital gains in two different ways, and one of them is average-cost booking. |
auto_depreciation | hktkzyx | ✅ | ✅ | 2020-03 | ❌ | Docs | |
amortize_over | Cary Kempston | ❌ | ❌ | 2017-09 | ❌ | Discussion | |
flexible_deprecation | Alok Parlikar | ✅ | ❌ | 2016-06 | Docstring | Improved by Dave Stephens (Discussion) and fixed by Akuukis (PR) | |
split_transactions | Johann Klähn | ❌ | ❌ | 2015-06 | ❌ | Discussion |
Furthermore may look into the sources for inspiration of the related DepreciateForLedger.
And of course love (in form of backlink) to the plaintextaccounting.org.
FAQs
Plugins for Beancount to interpolate transactions
We found that beancount-interpolate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.