Skip to content

Instantly share code, notes, and snippets.

@gbirke
Created March 23, 2023 20:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gbirke/2277173732d13987e618db670125fc2c to your computer and use it in GitHub Desktop.
Save gbirke/2277173732d13987e618db670125fc2c to your computer and use it in GitHub Desktop.
Convert CSV credit card statements of GLS Bank to look more like bank statements
#!/usr/bin/env python3
import argparse
import csv
import os.path
import sys
import logging
import re
"""
This script converts CSV credit card statements of GLS Bank to look more like
bank statements.
The difference is that in credit card statements the recipient column is
always "GLS Bank" and the real recipient is in the 2nd line of the multiline
description column.
This script parses the description column and updates the recipient and
description column if the description starts with "Basislastschrift"
(which indicates a payment).
Author: Gabriel Birke <gb@birke-software.de>
License: MIT
Version Changes
---------------
2022-03-15
Adapted to new CSV format:
* New Primanota column
* longer contains line breaks in description. instead, the desciption is a fixed-width table
2022-05-14
Adapted to new CSV format
* Skip first line (headers)
* different columns
"""
DESCRIPTION_COLUMN = 10
RECIPIENT_COLUMN = 6
def convert_row(row):
# Skip non-transaction rows
if len(row) < 10:
return row
description = row[DESCRIPTION_COLUMN]
if re.match(r'Abrechnung vom.*Hauptkarte', description):
return []
if re.match(r'Jahresbeitrag.*Hauptkarte', description):
return row
row[RECIPIENT_COLUMN] = description[0:27].strip()
row[DESCRIPTION_COLUMN] = description[27:]
return row
def convert_files(source_file, destination_file):
with open(source_file, encoding='utf-8', newline='') as input_file, open(destination_file, 'w', newline='', encoding='utf-8') as output_file:
input_reader = csv.reader(
input_file,
delimiter=";",
quoting=csv.QUOTE_NONE
)
output_writer = csv.writer(
output_file,
delimiter=";",
quoting=csv.QUOTE_NONE
)
row_index = 0
for row in input_reader:
if row_index > 0:
converted_row = convert_row(row)
else:
converted_row = row
if converted_row == []:
continue
output_writer.writerow(converted_row)
row_index += 1
def get_filenames(source_file, override):
if not os.path.isfile(source_file):
print("Can't read '%s' - is it a file?".format(source_file))
if source_file[-4:] != '.csv':
logging.warn("Input file name should end in .csv for optimal output file naming")
destination_file = source_file[0:-4] + ".converted.csv"
if os.path.isfile(destination_file):
if override:
logging.warning("Overwriting %s", destination_file)
else:
logging.error("Output file '%s' already exists", destination_file)
sys.exit(2)
return source_file, destination_file
def setup_cli():
parser = argparse.ArgumentParser(description="Convert GLS Bank credit card statements to bank statements")
parser.add_argument('statement_file', nargs='+', help="CSV file with credit card statements")
parser.add_argument('-f', '--force', dest='override', action="store_true", default=False, help="Overwrite output file if it exists")
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", default=False, help="Suppress output")
return parser
if __name__ == "__main__":
parser = setup_cli()
args = parser.parse_args()
if args.quiet:
logging.basicConfig(level=logging.CRITICAL)
else:
logging.basicConfig(level=logging.INFO)
for statement_file in args.statement_file:
source_file, destination_file = get_filenames(statement_file, args.override)
convert_files(source_file, destination_file)
logging.info("Converted to %s", destination_file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment