Started to use click as a cli
This commit is contained in:
parent
afbe8a96b1
commit
60cbf9da2e
12 changed files with 181 additions and 212 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
|||
*.pyc
|
||||
app.db
|
||||
app.db
|
||||
*.sta
|
||||
*.csv
|
||||
*.TXT
|
||||
|
|
3
Pipfile
3
Pipfile
|
@ -4,11 +4,14 @@ url = "https://pypi.org/simple"
|
|||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
flake8 = "*"
|
||||
|
||||
[packages]
|
||||
sqlalchemy = "*"
|
||||
prompt-toolkit = "*"
|
||||
bottle = "*"
|
||||
mt-940 = "*"
|
||||
click = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
||||
|
|
69
Pipfile.lock
generated
69
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "e8dc56266a4018b0bdb774d18144085e717b5a9792bedfc7cb1325c78a641c19"
|
||||
"sha256": "25b9941c75b9e81082b3302534b779bedf7a24979213c97e7da0524201b2f333"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -24,20 +24,36 @@
|
|||
"index": "pypi",
|
||||
"version": "==0.12.18"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:a402e9bf468b63314e37460b68ba68243d55b2f8c4d0192f85a019af3945050e",
|
||||
"sha256:c93e53af97f630f12f5f62a3274e79527936ed466f038953dfa379d4941f651a"
|
||||
"sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc",
|
||||
"sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.3"
|
||||
"version": "==7.1.1"
|
||||
},
|
||||
"mt-940": {
|
||||
"hashes": [
|
||||
"sha256:95e55584908c7d51b8a08cfb55d72297f06385e40c9baf9258cdaaf26811aafa",
|
||||
"sha256:fad1a00df51ede762d7d5e4d019de9ad86357d7556862b259ce7fba400ac2d6e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.20.0"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:859e1b205b6cf6a51fa57fa34202e45365cf58f8338f0ee9f4e84a4165b37d5b",
|
||||
"sha256:ebe6b1b08c888b84c50d7f93dee21a09af39860144ff6130aadbd61ae8d29783"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:64a7b71846db6423807e96820993fa12a03b89127d278290ca25c0b11ed7b4fb"
|
||||
"sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.13"
|
||||
"version": "==1.3.15"
|
||||
},
|
||||
"wcwidth": {
|
||||
"hashes": [
|
||||
|
@ -47,5 +63,42 @@
|
|||
"version": "==0.1.8"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
"develop": {
|
||||
"entrypoints": {
|
||||
"hashes": [
|
||||
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb",
|
||||
"sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7.9"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||
],
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,4 @@ session = Session()
|
|||
|
||||
from models import *
|
||||
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
for name in ["Haus", "Maus", "Spielzeug"]:
|
||||
c = Category(name=name)
|
||||
session.add(c)
|
||||
session.commit()
|
||||
Base.metadata.create_all(engine)
|
45
import.py
45
import.py
|
@ -1,45 +0,0 @@
|
|||
#! /usr/bin/env python3
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from sqlalchemy import create_engine, desc
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import Transaction
|
||||
import sys
|
||||
|
||||
|
||||
def convert_amount(s):
|
||||
s = s.replace(",", "")
|
||||
return int(float(s) * 100)
|
||||
|
||||
|
||||
engine = create_engine("sqlite:///app.db")
|
||||
Base = declarative_base()
|
||||
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
|
||||
latest = session.query(Transaction).order_by(desc(Transaction.date)).first()
|
||||
|
||||
with open("transactions.csv") as fh:
|
||||
fh.readline() # Get rid of first line
|
||||
csv_reader = csv.reader(fh, delimiter=";")
|
||||
count = 0
|
||||
for line in csv_reader:
|
||||
date = datetime.strptime(line[0], "%Y-%m-%d")
|
||||
amount = line[2]
|
||||
iban = line[4]
|
||||
name = line[5]
|
||||
description = line[6]
|
||||
|
||||
if latest and date < latest.date:
|
||||
print("Found transaction older than then oldest transction in the DB. Aborting")
|
||||
sys.exit(1)
|
||||
|
||||
t = Transaction(date=date, name=name, iban=iban, amount=convert_amount(amount), description=description)
|
||||
session.add(t)
|
||||
session.commit()
|
||||
count += 1
|
||||
print(".", end="", flush=True)
|
||||
print()
|
||||
print(f"Imported {count} transactions")
|
47
importer.py
Normal file
47
importer.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
#! /usr/bin/env python3
|
||||
import mt940
|
||||
import click
|
||||
from sqlalchemy import create_engine, desc
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import Transaction
|
||||
import sys
|
||||
|
||||
|
||||
def convert_amount(t):
|
||||
return int(t.amount * 100)
|
||||
|
||||
@click.command(name='import')
|
||||
@click.argument('filename', type=click.Path(exists=True))
|
||||
def command(filename):
|
||||
click.echo(click.format_filename(filename))
|
||||
engine = create_engine("sqlite:///app.db")
|
||||
Base = declarative_base()
|
||||
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
|
||||
latest = session.query(Transaction).order_by(desc(Transaction.date)).first()
|
||||
|
||||
transactions = mt940.parse("2020-01.TXT")
|
||||
count = 0
|
||||
for t in transactions:
|
||||
data = t.data
|
||||
|
||||
date = data['date']
|
||||
amount = convert_amount(data['amount'])
|
||||
iban = data['applicant_iban']
|
||||
name = data['applicant_name']
|
||||
description = data['purpose']
|
||||
|
||||
if latest and data['date'] < latest.date:
|
||||
print("Found transaction older than then oldest transction in the DB. Aborting")
|
||||
sys.exit(1)
|
||||
|
||||
t = Transaction(date=date, name=name, iban=iban, amount=amount, description=description)
|
||||
session.add(t)
|
||||
session.commit()
|
||||
count += 1
|
||||
print(".", end="", flush=True)
|
||||
print()
|
||||
print(f"Imported {count} transactions")
|
13
main.py
Executable file
13
main.py
Executable file
|
@ -0,0 +1,13 @@
|
|||
#! /usr/bin/env python3
|
||||
import click
|
||||
import sort, importer, serve
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli.add_command(sort.command)
|
||||
cli.add_command(importer.command)
|
||||
cli.add_command(serve.command)
|
||||
cli()
|
|
@ -2,5 +2,4 @@
|
|||
rm -rf app.db
|
||||
python create.py
|
||||
python categories.py
|
||||
python import.py
|
||||
python sort.py
|
||||
python importer.py
|
||||
|
|
17
serve.py
17
serve.py
|
@ -1,9 +1,10 @@
|
|||
#! /usr/bin/env python3
|
||||
from bottle import route, run, template
|
||||
from bottle import route, run, template, redirect
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from models import *
|
||||
import click
|
||||
|
||||
engine = create_engine("sqlite:///app.db")
|
||||
Base = declarative_base()
|
||||
|
@ -32,9 +33,21 @@ def category(name):
|
|||
|
||||
return template('category', category=c,transactions=transactions)
|
||||
|
||||
@route('/category/<name>/delete')
|
||||
def category(name):
|
||||
c = session.query(Category).filter(Category.name==name).first()
|
||||
if c:
|
||||
session.delete(c)
|
||||
session.commit()
|
||||
|
||||
return redirect("/categories")
|
||||
|
||||
@route('/transactions')
|
||||
def transactions():
|
||||
transactions = session.query(Transaction).all()
|
||||
return template('transactions', transactions=transactions)
|
||||
|
||||
run(host='localhost', port=8080, reloader=True)
|
||||
|
||||
@click.command(name='serve')
|
||||
def command():
|
||||
run(host='localhost', port=8080, reloader=True,debug=True)
|
||||
|
|
61
sort.py
61
sort.py
|
@ -5,40 +5,45 @@ from sqlalchemy.ext.declarative import declarative_base
|
|||
from models import *
|
||||
from categories import add_category
|
||||
import sys
|
||||
import click
|
||||
|
||||
from prompt_toolkit.completion import FuzzyWordCompleter
|
||||
from prompt_toolkit.shortcuts import prompt
|
||||
|
||||
engine = create_engine("sqlite:///app.db")
|
||||
Base = declarative_base()
|
||||
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
@click.command(name='sort')
|
||||
def command():
|
||||
engine = create_engine("sqlite:///app.db")
|
||||
Base = declarative_base()
|
||||
|
||||
categories = session.query(Category).all()
|
||||
category_lookup = {c.full_name(): c.id for c in categories}
|
||||
category_names = FuzzyWordCompleter([c.full_name() for c in categories])
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
|
||||
unsorted = session.query(Transaction).filter(Transaction.category_id == None).all()
|
||||
print("Found {} unsorted transcations".format(len(unsorted)))
|
||||
categories = session.query(Category).all()
|
||||
category_lookup = {c.full_name(): c.id for c in categories}
|
||||
category_names = FuzzyWordCompleter([c.full_name() for c in categories])
|
||||
|
||||
unsorted = session.query(Transaction).filter(Transaction.category_id == None).all()
|
||||
print("Found {} unsorted transcations".format(len(unsorted)))
|
||||
|
||||
for t in unsorted:
|
||||
print(" Name: {}".format(t.name))
|
||||
print(" VWZ: {}".format(t.description))
|
||||
print("Betrag: {}€".format(t.amount / 100))
|
||||
try:
|
||||
select = prompt("Category: ", completer=category_names, complete_while_typing=True)
|
||||
except KeyboardInterrupt:
|
||||
print("Goodbye")
|
||||
sys.exit(0)
|
||||
cat_id = category_lookup.get(select, None)
|
||||
if cat_id:
|
||||
t.category_id = cat_id
|
||||
session.add(t)
|
||||
session.commit()
|
||||
else:
|
||||
print(f"Creating new category '{select}'")
|
||||
add_category(select)
|
||||
|
||||
print("-" * 20)
|
||||
|
||||
|
||||
for t in unsorted:
|
||||
print(" Name: {}".format(t.name))
|
||||
print(" VWZ: {}".format(t.description))
|
||||
print("Betrag: {}€".format(t.amount / 100))
|
||||
try:
|
||||
select = prompt("Category: ", completer=category_names, complete_while_typing=True)
|
||||
except KeyboardInterrupt:
|
||||
print("Goodbye")
|
||||
sys.exit(0)
|
||||
cat_id = category_lookup.get(select, None)
|
||||
if cat_id:
|
||||
t.category_id = cat_id
|
||||
session.add(t)
|
||||
session.commit()
|
||||
else:
|
||||
print(f"Creating new category '{select}'")
|
||||
add_category(select)
|
||||
|
||||
print("-" * 20)
|
||||
|
|
120
transactions.csv
120
transactions.csv
|
@ -1,120 +0,0 @@
|
|||
"Date";"Interest Date";"Amount";"Account";"Counterparty";"Name";"Description"
|
||||
"2019-08-01";"2019-08-01";"10.27";"NL33BUNQ2035704715";"DE27100110012624718836";"Thomas Schulze";"Auslagen codemonauts"
|
||||
"2019-08-01";"2019-08-01";"0.04";"NL33BUNQ2035704715";"NL93BUNQ2036147313";"bunq";"Interest payment"
|
||||
"2019-08-01";"2019-08-02";"-30.00";"NL33BUNQ2035704715";"DE97830654080004031172";"Verein zur Förderung Freier Netze in Mittelhessen e.V";"ZSH LKW, fleaz"
|
||||
"2019-08-01";"2019-08-01";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-01";"2019-08-02";"-288.46";"NL33BUNQ2035704715";"DE88508635130004470516";"MANFRED KLIEFKEN-SCHMIDT";"Breidenstein Felix, Mieter, Im Biengarten 10, 64297 Eberstadt"
|
||||
"2019-08-01";"2019-08-01";"-1.54";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-02";"2019-08-02";"-11.64";"NL33BUNQ2035704715";"";"REWE Darmstadt Hei";"REWE Darmstadt Hei Darmstadt, DE"
|
||||
"2019-08-02";"2019-08-02";"-0.36";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-03";"2019-08-03";"-50.00";"NL33BUNQ2035704715";"";"POSTBANK BERGER STR. 4";"POSTBANK BERGER STR. 4 FRANKFURT, DE"
|
||||
"2019-08-03";"2019-08-03";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-04";"2019-08-04";"-11.26";"NL33BUNQ2035704715";"";"McDonalds 1736";"McDonalds 1736 Pfungstadt, DE"
|
||||
"2019-08-04";"2019-08-04";"-0.74";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-04";"2019-08-04";"-2.89";"NL33BUNQ2035704715";"";"McDonalds 1736";"McDonalds 1736 Pfungstadt, DE"
|
||||
"2019-08-04";"2019-08-04";"-1.11";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-05";"2019-08-05";"7.90";"NL33BUNQ2035704715";"DE27100110012624718836";"Thomas Schulze";"Currywurst"
|
||||
"2019-08-05";"2019-09-01";"-5.41";"NL33BUNQ2035704715";"";"REWE Frankfurt/Bor";"REWE Frankfurt/Bor Frankfurt am, DE"
|
||||
"2019-08-05";"2019-08-05";"-0.59";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-06";"2019-08-06";"-100.00";"NL33BUNQ2035704715";"";"HANAU 28";"HANAU 28 Hanau >, DE"
|
||||
"2019-08-06";"2019-08-06";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-07";"2019-08-07";"10.00";"NL33BUNQ2035704715";"NL67BUNQ2036142834";"bunq";"bunq Reward"
|
||||
"2019-08-11";"2019-08-11";"-12.35";"NL33BUNQ2035704715";"";"Hanau Hbf";"Hanau Hbf Hanau, DE"
|
||||
"2019-08-11";"2019-08-11";"-1.65";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-08-12";"-11.01";"NL33BUNQ2035704715";"";"REWE Frankfurt/Nor";"REWE Frankfurt/Nor Frankfurt, DE"
|
||||
"2019-08-12";"2019-08-12";"-0.99";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-08-13";"-300.00";"NL33BUNQ2035704715";"DE22120300001019770922";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-08-12";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-09-01";"-8.70";"NL33BUNQ2035704715";"";"PAYPAL";"PAYPAL 35314369001, DE"
|
||||
"2019-08-12";"2019-08-12";"-1.30";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-09-01";"-429.00";"NL33BUNQ2035704715";"";"PAYPAL *SECONDITSTO";"PAYPAL *SECONDITSTO 35314369001, DE"
|
||||
"2019-08-12";"2019-08-12";"-1.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-12";"2019-09-01";"-62.08";"NL33BUNQ2035704715";"";"KAUFLAND PFUNGSTADT 22";"KAUFLAND PFUNGSTADT 22 PFUNGSTADT, DE"
|
||||
"2019-08-12";"2019-08-12";"-1.92";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-13";"2019-08-13";"-3.96";"NL33BUNQ2035704715";"";"REWE Frankfurt/Bor";"REWE Frankfurt/Bor Frankfurt am, DE"
|
||||
"2019-08-13";"2019-08-13";"-0.04";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-13";"2019-09-01";"-1.50";"NL33BUNQ2035704715";"";"PP*9778CODE";"PP*9778CODE 35314369001, DE"
|
||||
"2019-08-13";"2019-08-13";"-0.50";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-13";"2019-09-01";"-29.74";"NL33BUNQ2035704715";"";"ONLINE";"ONLINE PARIS, FR"
|
||||
"2019-08-13";"2019-09-01";"-0.89";"NL33BUNQ2035704715";"";"AWS EMEA";"AWS EMEA aws.amazon.co, LU 1.00 USD, 1 USD = 0.89000 EUR"
|
||||
"2019-08-13";"2019-08-14";"-12.89";"NL33BUNQ2035704715";"DE87300308801908262006";"Amazon Payments Europe S.C.A.";"49991379690543"
|
||||
"2019-08-13";"2019-08-13";"-1.11";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-13";"2019-08-14";"-9.16";"NL33BUNQ2035704715";"DE87300308801908262006";"Amazon Payments Europe S.C.A.";"22140883725963"
|
||||
"2019-08-13";"2019-08-13";"-0.84";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-13";"2019-08-14";"-28.99";"NL33BUNQ2035704715";"DE87300308801908262006";"Amazon Payments Europe S.C.A.";"87385356146263"
|
||||
"2019-08-13";"2019-08-13";"-1.01";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-14";"2019-08-14";"-5.07";"NL33BUNQ2035704715";"";"REWE Frankfurt/Bor";"REWE Frankfurt/Bor Frankfurt am, DE"
|
||||
"2019-08-14";"2019-08-14";"-0.93";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-14";"2019-08-14";"-31.45";"NL33BUNQ2035704715";"";"BAUHAUS 574";"BAUHAUS 574 DARMSTADT, DE"
|
||||
"2019-08-14";"2019-08-14";"-0.55";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-14";"2019-08-14";"-26.86";"NL33BUNQ2035704715";"";"TOTAL Service Station";"TOTAL Service Station DARMSTADT, DE"
|
||||
"2019-08-14";"2019-08-14";"-1.14";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-14";"2019-08-14";"-50.00";"NL33BUNQ2035704715";"";"SPARKASSE DARMSTADT";"SPARKASSE DARMSTADT 010-GAA-FY, DE"
|
||||
"2019-08-14";"2019-08-14";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-14";"2019-09-01";"1.50";"NL33BUNQ2035704715";"";"PP*9778CODE";"Refund: PP*9778CODE (35314369001, 000)"
|
||||
"2019-08-15";"2019-08-15";"-64.16";"NL33BUNQ2035704715";"";"KAUFLAND PFUNGSTADT 22";"KAUFLAND PFUNGSTADT 22 PFUNGSTADT, DE"
|
||||
"2019-08-15";"2019-08-15";"-1.84";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-16";"2019-08-16";"-19.46";"NL33BUNQ2035704715";"";"REWE Darmstadt Rue";"REWE Darmstadt Rue Darmstadt, DE"
|
||||
"2019-08-16";"2019-08-16";"-0.54";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-17";"2019-08-15";"-25.49";"NL33BUNQ2035704715";"DE87300500000008996811";"Drillisch Online GmbH";"C3079895 U293132603 B360994149 WINSIM B2C.DE"
|
||||
"2019-08-17";"2019-08-17";"-0.51";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-17";"2019-08-17";"-11.17";"NL33BUNQ2035704715";"";"REWE Darmstadt Hei";"REWE Darmstadt Hei Darmstadt, DE"
|
||||
"2019-08-17";"2019-08-17";"-0.83";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-18";"2019-08-16";"-2.96";"NL33BUNQ2035704715";"DE44701600000000142108";"Hetzner Online GmbH";"Rechnungsnr.: R0009973290 - Kundennr.: K0717063016"
|
||||
"2019-08-18";"2019-08-18";"-1.04";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-18";"2019-09-01";"-21.90";"NL33BUNQ2035704715";"";"Lieferando.de";"Lieferando.de Amsterdam, NL"
|
||||
"2019-08-18";"2019-08-18";"-0.10";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-19";"2019-08-19";"-2.90";"NL33BUNQ2035704715";"";"Filialagentur der Dits";"Filialagentur der Dits Darmstadt, DE"
|
||||
"2019-08-19";"2019-08-19";"-1.10";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-19";"2019-08-19";"-10.22";"NL33BUNQ2035704715";"";"REWE 597 Darmstadt Bah";"REWE 597 Darmstadt Bah Darmstadt, DE"
|
||||
"2019-08-19";"2019-08-19";"-1.78";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-19";"2019-09-01";"-5.73";"NL33BUNQ2035704715";"";"KAUFLAND PFUNGSTADT 22";"KAUFLAND PFUNGSTADT 22 PFUNGSTADT, DE"
|
||||
"2019-08-19";"2019-08-19";"-0.27";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-20";"2019-09-01";"-11.14";"NL33BUNQ2035704715";"";"REWE Darmstadt Hei";"REWE Darmstadt Hei Darmstadt, DE"
|
||||
"2019-08-20";"2019-08-20";"-0.86";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-20";"2019-09-01";"-13.37";"NL33BUNQ2035704715";"";"KAUFLAND PFUNGSTADT 22";"KAUFLAND PFUNGSTADT 22 PFUNGSTADT, DE"
|
||||
"2019-08-20";"2019-08-20";"-0.63";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-21";"2019-08-21";"-100.00";"NL33BUNQ2035704715";"";"Berliner Volksbank eG";"Berliner Volksbank eG Zehdenick, DE"
|
||||
"2019-08-21";"2019-08-21";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-22";"2019-09-01";"-9.99";"NL33BUNQ2035704715";"";"PAYPAL *MKUEHL";"PAYPAL *MKUEHL 35314369001, DE"
|
||||
"2019-08-22";"2019-08-22";"-0.01";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-22";"2019-09-01";"-6.43";"NL33BUNQ2035704715";"";"REWE (KT) Pfungstadt";"REWE (KT) Pfungstadt Pfungstadt, DE"
|
||||
"2019-08-22";"2019-08-22";"-1.57";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-23";"2019-09-01";"-6.18";"NL33BUNQ2035704715";"";"PAYPAL *MM TRADING";"PAYPAL *MM TRADING 35314369001, DE"
|
||||
"2019-08-23";"2019-08-23";"-1.82";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-23";"2019-09-01";"-4.40";"NL33BUNQ2035704715";"";"PAYPAL *CHENYITIAN2";"PAYPAL *CHENYITIAN2 35314369001, DE"
|
||||
"2019-08-23";"2019-08-23";"-1.60";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-23";"2019-09-01";"-18.76";"NL33BUNQ2035704715";"";"KAUFLAND PFUNGSTADT 22";"KAUFLAND PFUNGSTADT 22 PFUNGSTADT, DE"
|
||||
"2019-08-23";"2019-08-23";"-1.24";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-25";"2019-09-01";"-11.99";"NL33BUNQ2035704715";"";"PAYPAL *NETFLIX.COM";"PAYPAL *NETFLIX.COM 35314369001, LU"
|
||||
"2019-08-25";"2019-08-25";"-0.01";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-25";"2019-08-23";"-32.52";"NL33BUNQ2035704715";"DE27510900000044145103";"book-n-drive mobilitaetssysteme GmbH";"10269521908141 Ihre Rechnung vom 14.08.19"
|
||||
"2019-08-25";"2019-08-25";"-1.48";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-28";"2019-09-01";"-7.34";"NL33BUNQ2035704715";"";"REWE Frankfurt/Bor";"REWE Frankfurt/Bor Frankfurt am, DE"
|
||||
"2019-08-28";"2019-08-28";"-0.66";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-28";"2019-09-01";"-7.49";"NL33BUNQ2035704715";"";"BAUHAUS 574";"BAUHAUS 574 DARMSTADT, DE"
|
||||
"2019-08-28";"2019-08-28";"-0.51";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-29";"2019-09-01";"-6.00";"NL33BUNQ2035704715";"";"PAYPAL *FREDERIKSTE";"PAYPAL *FREDERIKSTE 35314369001, DE"
|
||||
"2019-08-29";"2019-08-29";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"25.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"-20.00";"NL33BUNQ2035704715";"";"REISEB FFM-HBF GLEIS 1";"REISEB FFM-HBF GLEIS 1 FRANKFURT, DE"
|
||||
"2019-08-30";"2019-08-30";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-09-01";"-5.90";"NL33BUNQ2035704715";"";"PAYPAL *ZHUTINGMAOY";"PAYPAL *ZHUTINGMAOY 35314369001, DE"
|
||||
"2019-08-30";"2019-08-30";"-0.10";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-09-01";"-6.29";"NL33BUNQ2035704715";"";"PAYPAL *MM TRADING";"PAYPAL *MM TRADING 35314369001, DE"
|
||||
"2019-08-30";"2019-08-30";"-1.71";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"1,956.14";"NL33BUNQ2035704715";"NL84BUNQ2035424534";"codemonauts UG (haftungsbeschränkt)";"Gehalt 08/2019"
|
||||
"2019-08-30";"2019-08-30";"-300.00";"NL33BUNQ2035704715";"DE22120300001019770922";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"-25.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix";""
|
||||
"2019-08-30";"2019-09-01";"-49.17";"NL33BUNQ2035704715";"";"AMAZON DE MARKETPLACE";"AMAZON DE MARKETPLACE WWW.AMAZON.DE, LU"
|
||||
"2019-08-30";"2019-08-30";"-0.83";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-09-01";"-11.29";"NL33BUNQ2035704715";"";"PP*HUMBLEBUNDL HUMBLEB";"PP*HUMBLEBUNDL HUMBLEB 4029357733, US"
|
||||
"2019-08-30";"2019-08-30";"-0.71";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-08-30";"9.40";"NL33BUNQ2035704715";"DE27100110012624718836";"Thomas Schulze";"Auslagen codemonauts"
|
||||
"2019-08-30";"2019-08-30";"-90.00";"NL33BUNQ2035704715";"";"SPARKASSE DARMSTADT";"SPARKASSE DARMSTADT 015-GAA-F2, DE"
|
||||
"2019-08-30";"2019-08-30";"-2.00";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-30";"2019-09-01";"-18.51";"NL33BUNQ2035704715";"";"REWE Darmstadt Hei";"REWE Darmstadt Hei Darmstadt, DE"
|
||||
"2019-08-30";"2019-08-30";"-1.49";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
||||
"2019-08-31";"2019-09-01";"-9.99";"NL33BUNQ2035704715";"";"PAYPAL *SPOTIFY";"PAYPAL *SPOTIFY 35314369001, GB"
|
||||
"2019-08-31";"2019-08-31";"-0.01";"NL33BUNQ2035704715";"NL82BUNQ2035817226";"Felix Breidenstein";""
|
|
|
@ -3,6 +3,9 @@
|
|||
List of categories:
|
||||
<ul>
|
||||
% for c in categories:
|
||||
<li><a href="/category/{{ c.name }}">{{ c.full_name() }}</a></li>
|
||||
<li>
|
||||
<a href="/category/{{ c.name }}">{{ c.full_name() }}</a>
|
||||
<a class="text-red-600 ml-2" href="/category/{{ c.name }}/delete">❌</a>
|
||||
</li>
|
||||
% end
|
||||
</ul>
|
||||
|
|
Loading…
Add table
Reference in a new issue