Refactor and add revolut processing
This commit is contained in:
parent
160703d3cb
commit
4963c3e7a7
8 changed files with 124 additions and 7 deletions
|
@ -1 +0,0 @@
|
||||||
__version__ = "0.1.4"
|
|
1
ofx_processor/bpvf_processor/__init__.py
Normal file
1
ofx_processor/bpvf_processor/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
__version__ = "0.1.4"
|
1
ofx_processor/revolut_processor/__init__.py
Normal file
1
ofx_processor/revolut_processor/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
__version__ = "0.1.4"
|
54
ofx_processor/revolut_processor/main.py
Normal file
54
ofx_processor/revolut_processor/main.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
|
||||||
|
import click
|
||||||
|
import dateparser
|
||||||
|
|
||||||
|
|
||||||
|
def process_amount(amount):
|
||||||
|
if amount:
|
||||||
|
return float(amount.replace(",", "."))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def process_memo(line):
|
||||||
|
return " - ".join(
|
||||||
|
filter(None, map(str.strip, [line["Category"], line["Exchange Rate"]]))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.argument("csv_filename")
|
||||||
|
def cli(csv_filename):
|
||||||
|
formatted_data = []
|
||||||
|
|
||||||
|
with open(csv_filename) as f:
|
||||||
|
reader = csv.DictReader(f, delimiter=";")
|
||||||
|
for line in reader:
|
||||||
|
date = dateparser.parse(line["Completed Date"])
|
||||||
|
formatted_data.append(
|
||||||
|
{
|
||||||
|
"Date": date.strftime("%Y-%m-%d"),
|
||||||
|
"Payee": line["Reference"],
|
||||||
|
"Memo": process_memo(line),
|
||||||
|
"Outflow": process_amount(line["Paid Out (EUR)"]),
|
||||||
|
"Inflow": process_amount(line["Paid In (EUR)"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not formatted_data:
|
||||||
|
click.secho("Nothing to write.")
|
||||||
|
|
||||||
|
processed_file = os.path.join(os.path.dirname(csv_filename), "processed.csv")
|
||||||
|
with open(processed_file, "w") as f:
|
||||||
|
writer = csv.DictWriter(
|
||||||
|
f, delimiter=",", quotechar='"', fieldnames=formatted_data[0].keys()
|
||||||
|
)
|
||||||
|
writer.writeheader()
|
||||||
|
writer.writerows(formatted_data)
|
||||||
|
|
||||||
|
click.secho("{} written".format(processed_file), fg="green")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cli()
|
66
poetry.lock
generated
66
poetry.lock
generated
|
@ -66,6 +66,20 @@ optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Date parsing library designed to parse dates from HTML pages"
|
||||||
|
name = "dateparser"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "0.7.2"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
python-dateutil = "*"
|
||||||
|
pytz = "*"
|
||||||
|
regex = "*"
|
||||||
|
tzlocal = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Read metadata from Python packages"
|
description = "Read metadata from Python packages"
|
||||||
|
@ -176,7 +190,26 @@ version = ">=0.12"
|
||||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "main"
|
||||||
|
description = "Extensions to the standard Python datetime module"
|
||||||
|
name = "python-dateutil"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||||
|
version = "2.8.1"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = ">=1.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "World timezone definitions, modern and historical"
|
||||||
|
name = "pytz"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2019.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
description = "Alternative regular expression module, to replace re."
|
description = "Alternative regular expression module, to replace re."
|
||||||
name = "regex"
|
name = "regex"
|
||||||
optional = false
|
optional = false
|
||||||
|
@ -184,7 +217,7 @@ python-versions = "*"
|
||||||
version = "2020.1.8"
|
version = "2020.1.8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "main"
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
name = "six"
|
name = "six"
|
||||||
optional = false
|
optional = false
|
||||||
|
@ -207,6 +240,17 @@ optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "tzinfo object for the local timezone"
|
||||||
|
name = "tzlocal"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.0.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytz = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Measures number of Terminal column cells of wide-character codes"
|
description = "Measures number of Terminal column cells of wide-character codes"
|
||||||
|
@ -232,7 +276,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||||
testing = ["pathlib2", "contextlib2", "unittest2"]
|
testing = ["pathlib2", "contextlib2", "unittest2"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "fdef0368fd2681fefb714829b8c3d65a68ebe48db2c885abb46f6f4e48fe452f"
|
content-hash = "be08d3690daf99f4cf8210564a85c7346366473c6bfc2f098dcdf3108883c20b"
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
|
@ -260,6 +304,10 @@ colorama = [
|
||||||
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
||||||
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
||||||
]
|
]
|
||||||
|
dateparser = [
|
||||||
|
{file = "dateparser-0.7.2-py2.py3-none-any.whl", hash = "sha256:983d84b5e3861cb0aa240cad07f12899bb10b62328aae188b9007e04ce37d665"},
|
||||||
|
{file = "dateparser-0.7.2.tar.gz", hash = "sha256:e1eac8ef28de69a554d5fcdb60b172d526d61924b1a40afbbb08df459a36006b"},
|
||||||
|
]
|
||||||
importlib-metadata = [
|
importlib-metadata = [
|
||||||
{file = "importlib_metadata-1.4.0-py2.py3-none-any.whl", hash = "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359"},
|
{file = "importlib_metadata-1.4.0-py2.py3-none-any.whl", hash = "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359"},
|
||||||
{file = "importlib_metadata-1.4.0.tar.gz", hash = "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"},
|
{file = "importlib_metadata-1.4.0.tar.gz", hash = "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"},
|
||||||
|
@ -295,6 +343,14 @@ pytest = [
|
||||||
{file = "pytest-5.3.2-py3-none-any.whl", hash = "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4"},
|
{file = "pytest-5.3.2-py3-none-any.whl", hash = "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4"},
|
||||||
{file = "pytest-5.3.2.tar.gz", hash = "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa"},
|
{file = "pytest-5.3.2.tar.gz", hash = "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa"},
|
||||||
]
|
]
|
||||||
|
python-dateutil = [
|
||||||
|
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
|
||||||
|
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
|
||||||
|
]
|
||||||
|
pytz = [
|
||||||
|
{file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"},
|
||||||
|
{file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"},
|
||||||
|
]
|
||||||
regex = [
|
regex = [
|
||||||
{file = "regex-2020.1.8-cp27-cp27m-win32.whl", hash = "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161"},
|
{file = "regex-2020.1.8-cp27-cp27m-win32.whl", hash = "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161"},
|
||||||
{file = "regex-2020.1.8-cp27-cp27m-win_amd64.whl", hash = "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242"},
|
{file = "regex-2020.1.8-cp27-cp27m-win_amd64.whl", hash = "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242"},
|
||||||
|
@ -350,6 +406,10 @@ typed-ast = [
|
||||||
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
|
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
|
||||||
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
||||||
]
|
]
|
||||||
|
tzlocal = [
|
||||||
|
{file = "tzlocal-2.0.0-py2.py3-none-any.whl", hash = "sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048"},
|
||||||
|
{file = "tzlocal-2.0.0.tar.gz", hash = "sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"},
|
||||||
|
]
|
||||||
wcwidth = [
|
wcwidth = [
|
||||||
{file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"},
|
{file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"},
|
||||||
{file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"},
|
{file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "ofx-processor"
|
name = "ofx-processor"
|
||||||
version = "0.1.4"
|
version = "0.2.0"
|
||||||
description = "Personal ofx processor"
|
description = "Personal ofx processor"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
@ -14,13 +14,15 @@ classifiers = [
|
||||||
python = ">=3.7"
|
python = ">=3.7"
|
||||||
ofxtools = "^0.8.20"
|
ofxtools = "^0.8.20"
|
||||||
click = "^7.0"
|
click = "^7.0"
|
||||||
|
dateparser = "^0.7.2"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^5.2"
|
pytest = "^5.2"
|
||||||
black = "^19.10b0"
|
black = "^19.10b0"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
ofxprocessor = 'ofx_processor.main:cli'
|
process-bpvf = 'ofx_processor.bpvf_processor.main:cli'
|
||||||
|
process-revolut = 'ofx_processor.revolut_processor.main:cli'
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry>=0.12"]
|
requires = ["poetry>=0.12"]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from ofx_processor import __version__
|
from ofx_processor.bpvf_processor import __version__
|
||||||
|
|
||||||
|
|
||||||
def test_version():
|
def test_version():
|
||||||
|
|
Loading…
Reference in a new issue