|
- #!/bin/python3
-
- import sys
- import csv
- import re
- from pathlib import Path
-
- whitelist_cards = ["7756"]
-
- def usage():
- print('Usage: ynab.py <filename>')
-
-
- def is_reserved(row):
- return '(Reservert)' in row[1]
-
- def convert_memo(original):
- original = re.match(r'="[ ]?(.+)"', original).groups()[0]
- original = original.replace(" Kurs: 1.0000", "")
- words = original.split(" ")
-
- for i in range(20):
- if words[0] == "":
- # It's empty
- del words[0]
- elif m := re.match(r'\*(\d{4})', words[0]):
- # It's the last four digits of a card
- if m.groups()[0] in whitelist_cards:
- # It's an expected card, ignore it
- del words[0]
- else:
- # It's an unexpected card, move it to the end
- words.append(words.pop(0))
- elif m := re.match(r'\d{2}\.\d{2}', words[0]):
- # It's the date. Move it to the end
- words.append(words.pop(0))
- elif (m1 := re.match(r'^[A-Z]{3}$', words[0])) and (m2 := re.match(r'[\d]+\.[\d]+', words[1])):
- # It's the original currency
- if words[0] == "NOK":
- # It's Norwegian kroner, ignoring
- del words[0]
- del words[0]
- else:
- # It's some other currency, move it to the end
- words.append(words.pop(0))
- words.append(words.pop(0))
- else:
- break
- else:
- raise Exception(f"Infinite loop while parsing \"{original}\"")
-
-
- return " ".join(words)
-
-
- def convert(reader, writer):
- header = ['Date', 'Payee', 'Memo', 'Outflow', 'Inflow']
-
- writer.writerow(header)
-
- # Ignore header
- reader.__next__()
-
- for row in reader:
- if is_reserved(row):
- continue
-
- money_out = 0
- money_in = 0
-
- if (isinstance(row[3], str)):
- moneystr = row[3].replace(',', '.')
-
- try:
- money = float(moneystr) if moneystr else 0
- except ValueError as e:
- print(f'Error in row {row}')
- raise e
- else:
- money = float(row[3])
-
- if money >= 0:
- money_in = money
- else:
- money_out = -money
-
- memo = convert_memo(row[2])
-
- new_row = [*row[:2], memo, money_out, money_in]
- writer.writerow(new_row)
-
-
- def main():
- if len(sys.argv) != 2:
- usage()
- exit(1)
-
- filepath = Path(sys.argv[1])
-
- new_basename = f'ynab-{filepath.name}'
- new_filepath = filepath.parent / new_basename
-
- with filepath.open(mode='r') as old_file:
- reader = csv.reader(old_file, delimiter=';')
-
- with new_filepath.open(mode='w') as new_file:
- writer = csv.writer(new_file)
- convert(reader, writer)
-
-
- if __name__ == '__main__':
- main()
|