-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
5 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
"""bankstatements.py | ||
Contains metadata for parsing input files | ||
""" | ||
|
||
ing_nl = {"fields": {"Datum": "date", | ||
"Naam / Omschrijving": "name", | ||
"Rekening": "source", | ||
"Tegenrekening": "destination", | ||
"Code": "meta", | ||
"Af Bij": "direction", | ||
"Bedrag (EUR)": "amount", | ||
"MutatieSoort": "meta", | ||
"Mededelingen": "meta"}, | ||
"interpretation": {"directionout": "Af", | ||
"currency": {"symbol": "", #TODO fix unicode issue | ||
"code": "EUR"}, | ||
"separators": {"thousandseparator": ".", | ||
"decimalseparator": ","}, | ||
"dateformat": "%Y%m%d"}, | ||
"properties": {"quotechar": "\"", | ||
"delimiter": ","}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
"""ToLedger: Bank statements to ledger format | ||
Usage: | ||
toledger.py <format> [options] | ||
toledger.py <format> [options] <input> | ||
toledger.py <format> [options] <input> <output> | ||
toledger.py (-h | --help) | ||
Options: | ||
-a --append Append to the output file if it exists. | ||
-b --balance Ensure that all output is balanced. | ||
Choose this option if the output must be a | ||
standalone ledger file. These files should always | ||
have a balance of 0 to be valid. | ||
--from=<from> Account to get balances from. | ||
Default Equity:[Unspecified | IBAN] | ||
--to=<to> Account to send transactions to. | ||
Default Expenses:[Unspecified | IBAN] | ||
--name=<name> Account name. Default Assets:[IBAN] | ||
-c --code Use the currency code, e.g. EUR | ||
-s --symbol Use the currency symbol, e.g. € | ||
-h --help Show the usage guidelines. | ||
""" | ||
from docopt import docopt | ||
from sys import stdin, stdout | ||
import csv | ||
import bankstatements | ||
from time import strftime, strptime | ||
|
||
def main(a): | ||
with open(a["<input>"], "r") as inputfile: | ||
input = csv.reader(inputfile, **properties(a["<format>"])) | ||
filemode = "a" if a["--append"] else "w" | ||
if not a["<output>"]: outputlocation = stdout | ||
else: outputlocation = open(a["<output>"], filemode) | ||
with outputlocation as output: | ||
i = 0 | ||
for inputentry in input: | ||
if i == 0: | ||
header = inputentry | ||
else: | ||
parsedentry = parse(header, inputentry, a["<format>"]) | ||
# TODO: Interactive mode | ||
write(output, **parsedentry) | ||
i += 1 | ||
return 0 | ||
|
||
def parse(header, entry, format): | ||
# TODO: Smart transaction labeling | ||
parsed = {"meta": {}} | ||
for name, field in specification(format)["fields"].items(): | ||
if field == "meta": parsed["meta"][name] = entry[header.index(name)] | ||
else: parsed[field] = entry[header.index(name)] | ||
for name, field in specification(format)["interpretation"].items(): | ||
if name == "directionout": | ||
parsed["direction"] = "-" if parsed["direction"] == field else "" | ||
elif name == "currency": | ||
if "--code" in a: | ||
parsed["amount"] = " ".join([parsed["amount"], field["code"]]) | ||
elif "--symbol" in a: | ||
parsed["amount"] = " ".join([field["symbol"], parsed["amount"]]) | ||
elif name == "separators": | ||
parsed["amount"] = parsed["amount"].replace( | ||
field["thousandseparator"], "") | ||
parsed["amount"] = parsed["amount"].replace( | ||
field["decimalseparator"], ".") | ||
elif name == "dateformat": | ||
parsed["date"] = strftime("%Y-%m-%d", strptime(parsed["date"], field)) | ||
return parsed | ||
|
||
def specification(format): | ||
try: | ||
specification = getattr(bankstatements, format) | ||
return specification | ||
except: | ||
raise NotImplementedError("The specified format does not exist") | ||
|
||
def properties(format): return specification(format)["properties"] | ||
|
||
def write(output, **data): | ||
output.write("\n") | ||
output.write(data["date"]+" "+data["name"]) | ||
output.write("\n\t") | ||
if data["direction"] == "-": | ||
output.write("Expenses:"+max([data["destination"], "Unspecified"], key=len)+ | ||
" "+"\n\t") | ||
else: | ||
output.write("Equity:"+max([data["destination"], "Unspecified"], key=len)+ | ||
" "+"\n\t") | ||
output.write("Assets:"+data["source"]+"\t"+data["direction"]+ | ||
data["amount"]+"\n") | ||
# TODO Save metadata to outputfile | ||
output.write("\n") | ||
return | ||
|
||
if __name__ == '__main__': | ||
a = docopt(__doc__, version='ToLedger 1.0') | ||
main(a) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
"""ToLedger: Bank statements to ledger format | ||
Usage: | ||
toledger.py <format> [options] | ||
toledger.py <format> [options] <input> | ||
toledger.py <format> [options] <input> <output> | ||
toledger.py (-h | --help) | ||
Options: | ||
-a --append Append to the output file if it exists. | ||
-b --balance Ensure that all output is balanced. | ||
Choose this option if the output must be a | ||
standalone ledger file. These files should always | ||
have a balance of 0 to be valid. | ||
--from=<from> Account to get balances from. | ||
Default Equity:[Unspecified | IBAN] | ||
--to=<to> Account to send transactions to. | ||
Default Expenses:[Unspecified | IBAN] | ||
--name=<name> Account name. Default Assets:[IBAN] | ||
-c --code Use the currency code, e.g. EUR | ||
-s --symbol Use the currency symbol, e.g. € | ||
-h --help Show the usage guidelines. | ||
""" | ||
from docopt import docopt | ||
from sys import stdin, stdout | ||
import csv | ||
import bankstatements | ||
from time import strftime, strptime | ||
|
||
def main(a): | ||
with open(a["<input>"], "r") as inputfile: | ||
input = csv.reader(inputfile, **properties(a["<format>"])) | ||
filemode = "a" if a["--append"] else "w" | ||
if not a["<output>"]: outputlocation = stdout | ||
else: outputlocation = open(a["<output>"], filemode) | ||
with outputlocation as output: | ||
i = 0 | ||
for inputentry in input: | ||
if i == 0: | ||
header = inputentry | ||
else: | ||
parsedentry = parse(header, inputentry, a["<format>"]) | ||
# TODO: Interactive mode | ||
write(output, **parsedentry) | ||
i += 1 | ||
return 0 | ||
|
||
def parse(header, entry, format): | ||
# TODO: Smart transaction labeling | ||
parsed = {"meta": {}} | ||
for name, field in specification(format)["fields"].items(): | ||
if field == "meta": parsed["meta"][name] = entry[header.index(name)] | ||
else: parsed[field] = entry[header.index(name)] | ||
for name, field in specification(format)["interpretation"].items(): | ||
if name == "directionout": | ||
parsed["direction"] = "-" if parsed["direction"] == field else "" | ||
elif name == "currency": | ||
if "--code" in a: | ||
parsed["amount"] = " ".join([parsed["amount"], field["code"]]) | ||
elif "--symbol" in a: | ||
parsed["amount"] = " ".join([field["symbol"], parsed["amount"]]) | ||
elif name == "separators": | ||
parsed["amount"] = parsed["amount"].replace( | ||
field["thousandseparator"], "") | ||
parsed["amount"] = parsed["amount"].replace( | ||
field["decimalseparator"], ".") | ||
elif name == "dateformat": | ||
parsed["date"] = strftime("%Y-%m-%d", strptime(parsed["date"], field)) | ||
return parsed | ||
|
||
def specification(format): | ||
try: | ||
specification = getattr(bankstatements, format) | ||
return specification | ||
except: | ||
raise NotImplementedError("The specified format does not exist") | ||
|
||
def properties(format): return specification(format)["properties"] | ||
|
||
def write(output, **data): | ||
output.write("\n") | ||
output.write(data["date"]+" "+data["name"]) | ||
output.write("\n\t") | ||
if data["direction"] == "-": | ||
output.write("Expenses:"+max([data["destination"], "Unspecified"], key=len)+ | ||
" "+"\n\t") | ||
else: | ||
output.write("Equity:"+max([data["destination"], "Unspecified"], key=len)+ | ||
" "+"\n\t") | ||
output.write("Assets:"+data["source"]+"\t"+data["direction"]+ | ||
data["amount"]+"\n") | ||
# TODO Save metadata to outputfile | ||
output.write("\n") | ||
return | ||
|
||
if __name__ == '__main__': | ||
a = docopt(__doc__, version='ToLedger 1.0') | ||
main(a) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[metadata] | ||
description-file = README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters