Added watchdog to watch for changes and automatically convert

This commit is contained in:
2022-01-11 16:07:31 +10:00
parent 435a237049
commit 0b68363c6e
5 changed files with 99 additions and 221 deletions

8
Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
FROM python:3
ADD converter.py /
RUN pip install OfxParser
RUN pip install watchdog
CMD [ "python", "./converter.py" ]

View File

@@ -1,87 +0,0 @@
OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1>
<SONRS>
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<DTSERVER>20220110041351
<LANGUAGE>ENG
<FI>
<ORG>HSBC Bank Australia
<FID>10624
</FI>
<INTU.BID>10624
<INTU.USERID>XXXXXXXXXXXXXXXXXXXXXXXXXX
</SONRS>
</SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>0
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<STMTRS>
<CURDEF>AUD
<BANKACCTFROM>
<BANKID>001610020
<ACCTID>342101 576544258
<ACCTTYPE>CREDITLINE
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>
<DTEND>
<STMTTRN>
<TRNTYPE>CREDIT
<DTPOSTED>20220106
<DTUSER>20220106
<TRNAMT>1173.71
<FITID>202200600001
<NAME> TRANSFER
<MEMO>FROM 099-271041-090 AUD IB1305543 INTERNET BANKING
</STMTTRN>
<STMTTRN>
<TRNTYPE>CREDIT
<DTPOSTED>20220106
<DTUSER>20220106
<TRNAMT>628.81
<FITID>202200600002
<NAME> TRANSFER
<MEMO>FROM 099-271041-090 AUD IB1004824 INTERNET BANKING
</STMTTRN>
<STMTTRN>
<TRNTYPE>DEBIT
<DTPOSTED>20220104
<DTUSER>20220104
<TRNAMT>-399440.42
<FITID>202200400001
<NAME> TRANSFER
<MEMO>PEXA217198219-B2895881 LOAN DD 1592204/099-271041 DBCU00064 BANKING TERMINAL (UBT
</STMTTRN>
</BANKTRANLIST>
<LEDGERBAL>
<BALAMT>-397637.90
<DTASOF>20220110041351
</LEDGERBAL>
<AVAILBAL>
<BALAMT>1802.52
<DTASOF>20220110041351
</AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>

View File

@@ -1,4 +0,0 @@
Date,Original Description,Category,Amount,Account Name
06/01/2022,FROM 099-271041-090 AUD IB1305543 INTERNET BANKING,Uncategorised,1173.71,HSBC Everyday Global
06/01/2022,FROM 099-271041-090 AUD IB1004824 INTERNET BANKING,Uncategorised,628.81,HSBC Everyday Global
04/01/2022,PEXA217198219-B2895881 LOAN DD 1592204/099-271041 DBCU00064 BANKING TERMINAL (UBT,Uncategorised,-399440.42,HSBC Everyday Global
1 Date Original Description Category Amount Account Name
2 06/01/2022 FROM 099-271041-090 AUD IB1305543 INTERNET BANKING Uncategorised 1173.71 HSBC Everyday Global
3 06/01/2022 FROM 099-271041-090 AUD IB1004824 INTERNET BANKING Uncategorised 628.81 HSBC Everyday Global
4 04/01/2022 PEXA217198219-B2895881 LOAN DD 1592204/099-271041 DBCU00064 BANKING TERMINAL (UBT Uncategorised -399440.42 HSBC Everyday Global

View File

@@ -1,92 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from ofxparse import OfxParser\n",
"import codecs"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"with codecs.open('qfx.qfx') as fileobj:\n",
" ofx = OfxParser.parse(fileobj)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'10624'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"account = ofx.account\n",
"\n",
"account.institution.fid"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('9570.86')"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"statement = account.statement\n",
"statement.available_balance"
]
}
],
"metadata": {
"interpreter": {
"hash": "8f1f8a1d9576cf73e2f91f0cdc8e61e6f80707111d98c220b357b8bb1eb61bce"
},
"kernelspec": {
"display_name": "Python 3.8.12 64-bit ('hsbc': conda)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -4,10 +4,27 @@
from csv import DictWriter from csv import DictWriter
from glob import glob from glob import glob
from ofxparse import OfxParser from ofxparse import OfxParser
from pathlib import Path
import os
import time
import watchdog.events
import watchdog.observers
DATE_FORMAT = "%d/%m/%Y" DATE_FORMAT = "%d/%m/%Y"
WATCH_DIR = os.path.dirname(os.path.realpath(__file__))
PATTERN = '*.qfx'
BACKUP_DIR = 'Imported'
def write_csv(statement, out_file):
class Handler(watchdog.events.PatternMatchingEventHandler):
def __init__(self):
# Set the patterns for PatternMatchingEventHandler
watchdog.events.PatternMatchingEventHandler.__init__(self, patterns=['*.qfx'],
ignore_directories=True, case_sensitive=False)
@staticmethod
def write_csv(statement, out_file):
print("Writing: " + out_file) print("Writing: " + out_file)
fields = ['date', 'memo', 'category', 'amount', 'name'] fields = ['date', 'memo', 'category', 'amount', 'name']
with open(out_file, 'w') as f: with open(out_file, 'w') as f:
@@ -17,8 +34,8 @@ def write_csv(statement, out_file):
for line in statement: for line in statement:
writer.writerow(line) writer.writerow(line)
@staticmethod
def get_statement_from_qfx(qfx): def get_statement_from_qfx(qfx):
balance = qfx.account.statement.balance balance = qfx.account.statement.balance
statement = [] statement = []
@@ -41,10 +58,46 @@ def get_statement_from_qfx(qfx):
statement.append(line) statement.append(line)
return statement return statement
@staticmethod
def unique_path(directory, name_pattern):
counter = 0
while True:
counter += 1
path = directory / name_pattern.format(counter)
if not path.exists():
return path
files = glob("*.qfx") def on_created(self, event):
for qfx_file in files: qfx = OfxParser.parse(open(event.src_path, encoding="latin-1"), fail_fast=False)
qfx = OfxParser.parse(open(qfx_file, encoding="latin-1"), fail_fast=False) statement = Handler.get_statement_from_qfx(qfx)
statement = get_statement_from_qfx(qfx)
out_file = "converted_" + qfx_file.replace(".qfx",".csv") path = Path(event.src_path)
write_csv(statement, out_file) path.resolve()
out_file = str(path.parent / ('converted' + path.stem + '.csv'))
Handler.write_csv(statement, out_file)
#Now move the input file to backup
archive_file_dir = path.parent / BACKUP_DIR
archive_file = (path.stem + '{:04d}' + path.suffix)
destination = Handler.unique_path(archive_file_dir, archive_file)
if not archive_file_dir.exists():
archive_file_dir.mkdir()
if not destination.exists():
path.replace(destination)
if __name__ == "__main__":
event_handler = Handler()
observer = watchdog.observers.Observer()
observer.schedule(event_handler, path=WATCH_DIR, recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()